ToT glibc build problem with ToT GCC

Martin Sebor msebor@gmail.com
Thu Aug 29 17:28:00 GMT 2019


On 8/29/19 10:26 AM, Steve Ellcey wrote:
> I am building the latest glibc with the latest GCC and getting an error.
> I see where, in locale/programs/charmap.h we declare bytes as a zero
> length array in charseq but I am not sure where the write in
> locale/programs/ld-ctype.c is.  The only line references that GCC seems
> to be outputing refer to the declaration, not the use.
> 
> Is anyone else seeing this?  Any ideas on what we should be changed?
> The declaration?  The use?  Or is this a bogus warning from GCC that
> we want to ignore?  I think that GCC is reporting this now due to Martin
> Sebor's GCC patch for PR 83431 but I haven't verified that.

Yes, that's the most likely change.  It's unfortunate that GCC
doesn't show the exact location of the assignment but the warning
could be caused by the following in ctype_finish in ld-ctype.c:

	static struct charseq replace[2];

	if (!warned)
	  {
	    record_error (0, 0, _("\
not all characters used in `outdigit' are available in the charmap"));
	    warned = 1;
	  }

	replace[0].nbytes = 1;
	replace[0].bytes[0] = '?';
	replace[0].bytes[1] = '\0';
	ctype->mboutdigits[cnt] = &replace[0];
       }

struct charseq is defined like so in charmap.h:

   struct charseq
   {
     const char *name;
     uint32_t ucs4;
     int nbytes;
     unsigned char bytes[0];
   };

Like Jeff said, the code certainly looks fishy.  AFAICS,
the assignment "replace[0].bytes[0] = '?'" overwrites the first
byte of replace[1].name and the warning is correct in pointing
it out.

GCC allows past-the-end accesses to flexible array mebers (including
trailing zero length arrays) in dynamically allocated objects but
not in statically allocated ones, except when using memcpy (and
even that is questionable).  When the assignments are replaced by
the equivalent call to strcpy (but not memcpy), GCC issues a similar
warning and with _FORTIFY_SOURCE abort at runtime:

   $ cat z.c && gcc -D_FORTIFY_SOURCE=2 -O2 z.c && ./a.out
   #include <string.h>

   struct charseq
   {
     const char *name;
     unsigned ucs4;
     int nbytes;
     unsigned char bytes[0];
   };

   void *p;

   int main ()
   {
     static struct charseq replace[2];

     replace[0].nbytes = 1;
     const char s[] = "?";
     strcpy (replace[0].bytes, s);
     p = replace;
   }

   In file included from /usr/include/string.h:494,
                    from z.c:1:
   In function ‘strcpy’,
       inlined from ‘main’ at z.c:19:3:
   /usr/include/bits/string_fortified.h:90:10: warning: 
‘__builtin___memcpy_chk’ writing 2 bytes into a region of size 0 
overflows the destination [-Wstringop-overflow=]
      90 |   return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
         |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *** buffer overflow detected ***: ./a.out terminated
   Aborted (core dumped)

If it's too difficult to fix the code to avoid the out-of-bounds
access it's still possible to work around it by using memcpy.
But as GCC gets better about detecting these misuses every day
the warning will likely come back.

A longer term solution is to replace the array with a suitably
aligned char buffer and write the data into it, e.g., like this:

   union {
     struct charseq replace[2];
     char buf[sizeof (struct charseq) * 2];
   } u;

   u.replace[0].nbytes = 1;
   const char s[] = "?";
   memcpy (u.buf + offsetof (struct charseq, bytes), "?", 2);

This is still iffy but it won't trigger an out-of-bounds warning.
This code should still be flagged for the declaration of an object
with an internal zero-length array, so that will need to be dealt
with when such a warning is introduced (e.g., by suppressing
the warning).

Martin

> 
> Steve Ellcey
> sellcey@marvell.com
> 
> 
> 
> cc1: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=]
> In file included from programs/repertoire.h:24,
>                   from programs/localedef.h:32,
>                   from programs/ld-ctype.c:35:
> programs/charmap.h:63:17: note: destination object declared here
>     63 |   unsigned char bytes[0];
>        |                 ^~~~~
> cc1: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=]
> programs/charmap.h:63:17: note: destination object declared here
> cc1: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=]
> programs/charmap.h:63:17: note: destination object declared here
> cc1: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=]
> programs/charmap.h:63:17: note: destination object declared here
> cc1: all warnings being treated as errors
> ../o-iterator.mk:9: recipe for target '/home/sellcey/tot/obj/glibc64/locale/ld-ctype.o' failed
> make[2]: *** [/home/sellcey/tot/obj/glibc64/locale/ld-ctype.o] Error 1
> 



More information about the Libc-alpha mailing list