From: Taylor Blau <me@ttaylorr.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: Jeff King <peff@peff.net>,
git@vger.kernel.org, Taylor Blau <me@ttaylorr.com>
Subject: Re: [PATCH 1/3] config: work around gcc-10 -Wstringop-overflow warning
Date: Wed, 5 Aug 2020 11:15:07 -0400 [thread overview]
Message-ID: <20200805151507.GC9546@syl.lan> (raw)
In-Reply-To: <xmqqv9hys7ag.fsf@gitster.c.googlers.com>
On Tue, Aug 04, 2020 at 09:30:15AM -0700, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
>
> > Compiling with gcc-10, -O2, and -fsanitize=undefined results in a
> > compiler warning:
> >
> > config.c: In function ‘git_config_copy_or_rename_section_in_file’:
> > config.c:3170:17: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=]
> > 3170 | output[0] = '\t';
> > | ~~~~~~~~~~^~~~~~
> > config.c:3076:7: note: at offset -1 to object ‘buf’ with size 1024 declared here
> > 3076 | char buf[1024];
> > | ^~~
> >
> > This is a false positive. The interesting lines of code are:
> >
> > int i;
> > char *output = buf;
> > ...
> > for (i = 0; buf[i] && isspace(buf[i]); i++)
> > ; /* do nothing */
> > ...
> > int offset;
> > offset = section_name_match(&buf[i], old_name);
> > if (offset > 0) {
> > ...
> > output += offset + i;
> > if (strlen(output) > 0) {
> > /*
> > * More content means there's
> > * a declaration to put on the
> > * next line; indent with a
> > * tab
> > */
> > output -= 1;
> > output[0] = '\t';
> > }
> > }
> >
> > So we do assign output to buf initially. Later we increment it based on
> > "offset" and "i" and then subtract "1" from it. That latter step is what
> > the compiler is complaining about; it could lead to going off the left
> > side of the array if "output == buf" at the moment of the subtraction.
> > For that to be the case, then "offset + i" would have to be 0. But that
> > can't happen:
> >
> > - we know that "offset" is at least 1, since we're in a conditional
> > block that checks that
> >
> > - we know that "i" is not negative, since it started at 0 and only
> > incremented over whitespace
> >
> > So the sum must be at least 1, and therefore it's OK to subtract one
> > from "output".
> >
> > But that's not quite the whole story. Since "i" is an int, it could in
> > theory be possible to overflow to negative (when counting whitespace on
> > a very large string). But we know that's impossible because we're
> > counting the 1024-byte buffer we just fed to fgets(), so it can never be
> > larger than that.
> >
> > Switching the type of "i" to "unsigned" makes the warning go away, so
> > let's do that.
> >
> > Arguably size_t is an even better type (for this and for the other
> > length fields), but switching to it produces a similar but distinct
> > warning:
> >
> > config.c: In function ‘git_config_copy_or_rename_section_in_file’:
> > config.c:3170:13: error: array subscript -1 is outside array bounds of ‘char[1024]’ [-Werror=array-bounds]
> > 3170 | output[0] = '\t';
> > | ~~~~~~^~~
> > config.c:3076:7: note: while referencing ‘buf’
> > 3076 | char buf[1024];
> > | ^~~
> >
> > If we were to ever switch off of fgets() to strbuf_getline() or similar,
> > we'd probably need to use size_t to avoid other overflow problems. But
> > for now we know we're safe because of the small fixed size of our
> > buffer.
> >
> > Signed-off-by: Jeff King <peff@peff.net>
> > ---
>
> Thanks. 80 lines of informative log message to explain a one liner
> was surprisingly pleasnt to read. Nicely done.
Agreed, and sorry that this took me so long to read (I thought that I
had read it when you sent it, but apparently not). Your reasoning is
sensible, and I agree that your fix is appropriate.
Reviewed-by: Taylor Blau <me@ttaylorr.com>
> > config.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/config.c b/config.c
> > index 8db9c77098..2b79fe76ad 100644
> > --- a/config.c
> > +++ b/config.c
> > @@ -3115,7 +3115,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
> > }
> >
> > while (fgets(buf, sizeof(buf), config_file)) {
> > - int i;
> > + unsigned i;
> > int length;
> > int is_section = 0;
> > char *output = buf;
Thanks,
Taylor
next prev parent reply other threads:[~2020-08-05 17:42 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-04 7:41 [PATCH 0/3] some compiler/asan/ubsan fixes Jeff King
2020-08-04 7:43 ` [PATCH 1/3] config: work around gcc-10 -Wstringop-overflow warning Jeff King
2020-08-04 16:30 ` Junio C Hamano
2020-08-05 15:15 ` Taylor Blau [this message]
2020-08-04 7:46 ` [PATCH 2/3] revision: avoid out-of-bounds read/write on empty pathspec Jeff King
2020-08-04 13:08 ` Derrick Stolee
2020-08-05 15:17 ` Taylor Blau
2020-08-04 7:50 ` [PATCH 3/3] revision: avoid leak when preparing bloom filter for "/" Jeff King
2020-08-04 13:09 ` Derrick Stolee
2020-08-05 15:19 ` Taylor Blau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200805151507.GC9546@syl.lan \
--to=me@ttaylorr.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=peff@peff.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.