Fw: Problems with compiling autogen with GCC8 or newer versions
Bruce Korb
bruce.korb@gmail.com
Sun Jan 10 19:28:14 GMT 2021
Hi Martin,
On 1/10/21 11:01 AM, Martin Sebor wrote:
> On 1/8/21 12:38 PM, Bruce Korb via Gcc wrote:
>> This is the code that must be confusing to GCC. "def_str" points to
>> the second character in the 520 byte buffer. "def_scan" points to a
>> character that we already know we're going to copy into the
>> destination, so the "spn" function doesn't look at it:
>>
>> {
>> char * end = spn_ag_char_map_chars(def_scan + 1, 31);
>> size_t len = end - def_scan;
>> if (len >= 256)
>> goto fail_return;
>> memcpy(def_str, def_scan, len);
>> def_str += len;
>> *def_str = '\0';
>> def_scan = end;
>> }
In the function preamble, "def_str" points to the first character
(character "0") of a 520 byte buffer. Before this fragment, "*def_str"
is set to an apostrophe and the pointer advanced. After execution passes
through this fragment, "def_str" is pointing to a NUL byte that can be
as far as 257 bytes into the buffer (character "257"). That leaves 263
more bytes. The "offending" sprintf is:
sprintf(def_str, " %s'", name_bf);
GCC correctly determines that "name_bf" cannot contain more than 255
bytes. Add 3 bytes of text and a NUL byte and the sprintf will be
dropping *AT MOST* 259 characters into the buffer. The buffer is 4 bytes
longer than necessary.
>
> GCC 8 also doesn't warn but it does determine the size. Here's
> the output for the relevant directive (from the output of
> -fdump-tree-printf-return-value in GCC versions prior to 10, or
> -fdump-tree-strlen in GCC 10 and later). objsize is the size
> of the destination, or 520 bytes here (this is in contrast to
> the 255 in the originally reported message). The Result numbers
> are the minimum and maximum size of the output (between 0 and
> 255 characters).
>
> Computing maximum subobject size for def_str_146:
> getdefs.c:275: sprintf: objsize = 520, fmtstr = " %s'"
> Directive 1 at offset 0: " ", length = 2
> Result: 2, 2, 2, 2 (2, 2, 2, 2)
> Directive 2 at offset 2: "%s"
> Result: 0, 255, 255, 255 (2, 257, 257, 257)
> Directive 3 at offset 4: "'", length = 1
> Result: 1, 1, 1, 1 (3, 258, 258, 258)
> Directive 4 at offset 5: "", length = 1
>
> Besides provable overflow, it's worth noting that -Wformat-overflow
It can /not/ overflow. Those compiler stats are not decipherable by me.
> also diagnoses a subset of cases where it can't prove that overflow
> cannot happen. One common case is:
>
> extern char a[8], b[8];
> sprintf (a, "a=%s", b);
My example would have the "a" array sized at 16 bytes and "b" provably
not containing more than 7 characters (plus a NUL). There would be no
overflow.
> ... The solution is to either use precision
> to constrain the amount of output or in GCC 10 and later to assert
> that b's length is less than 7.
See the fragment below to see where the characters in name_bf can
*/NOT/* be more than 255. There is no need for either a precision
constraint or an assertion, based on that code fragment.
>
> So if in the autogen file def_str is ever less than 258 bytes/[259 --
> NUL byte, too]/
> I'd expect the warning to trigger with a message close to
> the original.
It can not be less than 263. For the sake of those not reading the code,
here is the fragment that fills in "name_bf[256]":
{
char * end = spn_ag_char_map_chars(def_scan + 1, 26);
size_t len = end - def_scan;
if (len >= 256)
goto fail_return;
memcpy(name_bf, def_scan, len);
name_bf[len] = '\0';
def_scan = end;
}
More information about the Gcc
mailing list