Bug 47418 - warning: array subscript is above array bounds at O2 with sin6_addr
Summary: warning: array subscript is above array bounds at O2 with sin6_addr
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.5.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: 56456
  Show dependency treegraph
 
Reported: 2011-01-23 00:10 UTC by Dan McGee
Modified: 2013-02-26 09:48 UTC (History)
2 users (show)

See Also:
Host: x86_64-unknown-linux-gnu
Target: x86_64-unknown-linux-gnu
Build: x86_64-unknown-linux-gnu
Known to work:
Known to fail:
Last reconfirmed: 2011-01-25 11:24:58


Attachments
Preprocessed test case (674 bytes, application/octet-stream)
2011-01-23 00:10 UTC, Dan McGee
Details
simpler testcase (240 bytes, text/x-csrc)
2011-01-23 02:06 UTC, Xavier
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dan McGee 2011-01-23 00:10:42 UTC
Created attachment 23083 [details]
Preprocessed test case

Originally from http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=43491

Preprocessed stripped test case (<100 lines) attached.

Only occurs on x86_64. At -O1 or -O0 this does not warn. It obviously also warns at -O3.

$ pacman -Q glibc
glibc 2.13-1
$ uname -a
Linux galway 2.6.36-ARCH #1 SMP PREEMPT Sat Jan 8 14:15:27 CET 2011 x86_64 Intel(R) Core(TM)2 Quad CPU Q9400 @ 2.66GHz GenuineIntel GNU/Linux
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: /build/src/gcc-4.5.2/configure --prefix=/usr --enable-languages=c,c++,fortran,objc,obj-c++,ada --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-gnu-unique-object --enable-lto --enable-plugin --enable-gold --with-plugin-ld=ld.gold --disable-multilib --disable-libstdcxx-pch --with-system-zlib --with-ppl --with-cloog --with-cloog-include=/usr/include/cloog-ppl --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info
Thread model: posix
gcc version 4.5.2 (GCC) 


$ gcc -O2 -Wall -c ftp-stripped.i 
ftp-stripped.i: In function ‘main’:
ftp-stripped.i:86:30: warning: array subscript is above array bounds
ftp-stripped.i:86:22: warning: array subscript is above array bounds
ftp-stripped.i:86:14: warning: array subscript is above array bounds
ftp-stripped.i:86:6: warning: array subscript is above array bounds
ftp-stripped.i:85:28: warning: array subscript is above array bounds
ftp-stripped.i:85:20: warning: array subscript is above array bounds
ftp-stripped.i:85:13: warning: array subscript is above array bounds
ftp-stripped.i:85:6: warning: array subscript is above array bounds



On i686, no warnings at any optimization level occur.

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-linux-gnu/4.5.2/lto-wrapper
Target: i686-pc-linux-gnu
Configured with: /build/src/gcc-4.5.2/configure --prefix=/usr --enable-languages=c,c++,fortran,objc,obj-c++,ada --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-gnu-unique-object --enable-lto --enable-plugin --enable-gold --with-plugin-ld=ld.gold --disable-multilib --disable-libstdcxx-pch --with-system-zlib --with-ppl --with-cloog --with-cloog-include=/usr/include/cloog-ppl --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info
Thread model: posix
gcc version 4.5.2 (GCC)
Comment 1 Dan McGee 2011-01-23 00:15:29 UTC
Also of note is the commented bit in the test case- if you instead dereference the s6_addr bit of the union, it all works without warnings.

In the preprocessed source, replace
  ap = (char *)&u.sin6.sin6_addr;

with:
  ap = (char *)&u.sin6.sin6_addr.__in6_u.__u6_addr8;
Comment 2 Xavier 2011-01-23 02:02:18 UTC
(In reply to comment #1)
> Also of note is the commented bit in the test case- if you instead dereference
> the s6_addr bit of the union, it all works without warnings.
> 
> In the preprocessed source, replace
>   ap = (char *)&u.sin6.sin6_addr;
> 
> with:
>   ap = (char *)&u.sin6.sin6_addr.__in6_u.__u6_addr8;

Actually it works with any member from __in6.u union.

It seems gcc gets confused with the other anonymous union, and use the size of struct sockaddr instead of struct sockaddr_in6.

I've got a simpler testcase which shows another interesting information : gcc gets confused when the sign of ap is the same as the size of the smallest struct/array of the union, and different from the sign of the big member that should be used.
Comment 3 Xavier 2011-01-23 02:06:35 UTC
Created attachment 23084 [details]
simpler testcase

$ gcc -O3 -Wall -c small-test.c 
small-test.c: In function 'main':
small-test.c:18:51: warning: array subscript is above array bounds
small-test.c:18:43: warning: array subscript is above array bounds
small-test.c:18:35: warning: array subscript is above array bounds

so gcc seems to think that the size of ap is 13 instead of 16.
It's important that ap and sa_data are both char, and u6_addr8 is unsigned char.
Same warning if ap and sa_data are unsigned char and u6_addr8 is char.
But other combinations apparently do not give any warning.
Comment 4 Richard Biener 2011-01-25 11:24:58 UTC
VRP sees

<bb 2>:
  D.2725_3 = u.sa_data[15];
  D.2726_4 = (int) D.2725_3;
  D.2728_6 = u.sa_data[14];
  D.2729_7 = (int) D.2728_6;
...
  D.2769_47 = u.sa_data[0];
  D.2770_48 = (int) D.2769_47;
  test_func (0, D.2770_48, D.2768_46, D.2765_43, D.2762_40, D.2759_37, D.2756_34, D.2753_31, D.2750_28, D.2747_25, D.2744_22, D.2741_19, D.2738_16, D.2735_13, D.2732_10, D.2729_7, D.2726_4);
  return 0;

because of our fancy way of re-building non-addressed components.

With 4.6 the warning is gone and we instead have (thanks to MEM-REF):

<bb 2>:
  D.2695_3 = MEM[(char *)&u + 15B];
  D.2696_4 = (int) D.2695_3;
  D.2698_6 = MEM[(char *)&u + 14B];
  D.2699_7 = (int) D.2698_6;
...
  D.2740_48 = (int) D.2739_47;
  test_func (0, D.2740_48, D.2738_46, D.2735_43, D.2732_40, D.2729_37, D.2726_34, D.2723_31, D.2720_28, D.2717_25, D.2714_22, D.2711_19, D.2708_16, D.2705_13, D.2702_10, D.2699_7, D.2696_4);
  return 0;

thus, no more array access and still non-address-taken u.  4.4 also warns
about

small-test.c: In function 'main':
small-test.c:18: warning: array subscript is above array bounds
small-test.c:18: warning: array subscript is above array bounds
small-test.c:18: warning: array subscript is above array bounds
small-test.c:18: warning: 'u' is used uninitialized in this function

4.3 doesn't warn at all.

Confirmed.  I'd close it as fixed in 4.6 and add a testcase (no time for
that right now).