Bug 48985

Summary: bogus buffer overflow warning and abort on static flexible array member
Product: gcc Reporter: Martin Sebor <msebor>
Component: cAssignee: Richard Biener <rguenth>
Status: RESOLVED FIXED    
Severity: normal Keywords: wrong-code
Priority: P3    
Version: 4.6.0   
Target Milestone: 4.6.1   
Host: Target:
Build: Known to work: 4.6.1, 4.7.0
Known to fail: 4.3.0, 4.6.0 Last reconfirmed: 2011-05-13 09:27:38
Bug Depends on: 49063    
Bug Blocks:    

Description Martin Sebor 2011-05-12 23:02:28 UTC
GCC emits a bogus warning on the program below which then aborts at runtime. Note that when the strncpy (s.c, "012", 4) call in line 24 is removed GCC doesn't emit a warning but the program still aborts even though there is no buffer overflow.

For statically allocated flexible array members I would expect __builtin_object_size() to report the actual size of the array rather than zero, analogously to the case when the array is allocated dynamically.

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

struct s {
    int i;
    char c[];
} s = { 1, "01234" };

size_t f (void) { return __builtin_object_size(&s.c, 0); }

size_t g (struct s *p) { return __builtin_object_size(p->c, 0); }

int main (void) {
    struct s *p;
    p = (struct s*)malloc (sizeof *p + 6);

    printf ("%zu %zu\n", f (), g (p));
    fflush (stdout);

    strncpy (p->c, "012", strlen(s.c));

    if (puts ("###"))
        strncpy (s.c, "012", 4);   /* line 24 */
    strncpy (s.c, "012", strlen(s.c) + 1);

    return 0;
}
In file included from /usr/include/string.h:642:0,
                 from z.c:3:
In function ‘strncpy’,
    inlined from ‘main’ at z.c:24:17:
/usr/include/bits/string3.h:121:3: warning: call to __builtin___strncpy_chk will always overflow destination buffer [enabled by default]
0 6
###
*** buffer overflow detected ***: ./a.out terminated
...
Aborted (core dumped)
Comment 1 Richard Biener 2011-05-13 09:27:38 UTC
The issue is that the type of the static declaration is never adjusted and
we take the total size from the type instead of from the decl.

Instead doing sth like

Index: gcc/tree-object-size.c
===================================================================
--- gcc/tree-object-size.c      (revision 173724)
+++ gcc/tree-object-size.c      (working copy)
@@ -205,6 +205,12 @@ addr_object_size (struct object_size_inf
        pt_var_size = size_int (sz);
     }
   else if (pt_var
+          && DECL_P (pt_var)
+          && host_integerp (DECL_SIZE_UNIT (pt_var), 1)
+          && (unsigned HOST_WIDE_INT)
+               tree_low_cst (DECL_SIZE_UNIT (pt_var), 1) < offset_limit)
+    pt_var_size = DECL_SIZE_UNIT (pt_var);
+  else if (pt_var
           && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
           && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
           && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)

fixes it for me (returns 6).

I suppose returning zero for a field that has incomplete type is wrong-code.
We should return -1 instead.
Comment 2 Richard Biener 2011-05-19 10:45:29 UTC
Author: rguenth
Date: Thu May 19 10:45:26 2011
New Revision: 173901

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=173901
Log:
2011-05-19  Richard Guenther  <rguenther@suse.de>

	PR middle-end/48985
	* tree-object-size.c (addr_object_size): If the pointed-to
	variable is a decl use DECL_SIZE_UNIT instead of TYPE_SIZE_UNIT.

	* gcc.dg/builtin-object-size-11.c: New testcase.

Added:
    trunk/gcc/testsuite/gcc.dg/builtin-object-size-11.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/tree-object-size.c
Comment 3 Richard Biener 2011-05-31 12:25:59 UTC
Author: rguenth
Date: Tue May 31 12:25:52 2011
New Revision: 174476

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=174476
Log:
2011-05-31  Richard Guenther  <rguenther@suse.de>

	Backport from mainline
	2011-05-19  Richard Guenther  <rguenther@suse.de>

	PR middle-end/48985
	* tree-object-size.c (addr_object_size): If the pointed-to
	variable is a decl use DECL_SIZE_UNIT instead of TYPE_SIZE_UNIT.

	* gcc.dg/builtin-object-size-11.c: New testcase.

Added:
    branches/gcc-4_6-branch/gcc/testsuite/gcc.dg/builtin-object-size-11.c
Modified:
    branches/gcc-4_6-branch/gcc/ChangeLog
    branches/gcc-4_6-branch/gcc/testsuite/ChangeLog
    branches/gcc-4_6-branch/gcc/tree-object-size.c
Comment 4 Richard Biener 2011-05-31 12:26:26 UTC
Fixed for 4.6.1.