With optimization level -Os or -O2, the function below will generate code that
does not perform the conditional test.  The test is necessary on embedded
systems where de-referencing a pointer to address 0 may be legitimate and would
not cause an exception in the de-reference of b (line 4).  The defect occurs in
all tested versions of gcc including native and cross compilers: 

   host:i686-pc-cygwin/target:arm-elf-gcc/build:3.4.0, 
   host:i686-pc-cygwin/target:arm-elf-gcc/build:4.2.0 (GNUARM)
   host:i686-pc-cygwin/target:i686-pc-cygwin/build:3.4.4
   host:i486-linux-gnu/target:i486-linux-gnu/build:4.1.2 (20061115 prerelease -
debian4.1.1-21)

The assembly output shows that the assignment d=c (on line 8) is performed
without performing the conditional test for a non-null value of b (line 7):

-------------------------------------------------

void bad_code(void *a)
{
   int *b = a;
   int c = *b;
   static int d;

   if (b) {
      d = c;
   }
}

$ arm-elf-gcc -c -g -MD -I. -mcpu=arm7tdmi -mthumb-interwork -std=c99 -Os -Wall
 -Werror test.c -o test.o

$ arm-elf-objdump -S test.o

test.o:     file format elf32-littlearm

Disassembly of section .text:

00000000 <bad_code>:
   int c = *b;
   static int d;

   if (b) {
      d = c;
   0:   e5902000        ldr     r2, [r0]
   4:   e59f3004        ldr     r3, [pc, #4]    ; 10 <.text+0x10>
   8:   e5832000        str     r2, [r3]
   }
}
   c:   e12fff1e        bx      lr
  10:   00000000        andeq   r0, r0, r0

Same code compiled with native cygwin compiler: (3.4.4)

$ gcc -O2 -c test.c -o test.o

$ objdump -S test.o

test.o:     file format pe-i386

Disassembly of section .text:

00000000 <_bad_code>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 08                mov    0x8(%ebp),%eax
   6:   5d                      pop    %ebp
   7:   8b 00                   mov    (%eax),%eax
   9:   a3 00 00 00 00          mov    %eax,0x0
   e:   c3                      ret
   f:   90                      nop


Same code compiled on Native linux-gnu (4.1.2):

foo.o:     file format elf32-i386

Disassembly of section .text:

00000000 <bad_code>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 08                mov    0x8(%ebp),%eax
   6:   5d                      pop    %ebp
   7:   8b 00                   mov    (%eax),%eax
   9:   a3 00 00 00 00          mov    %eax,0x0
   e:   c3                      ret    


It appears that the optimizer takes the dereference of b as an implicit sign
that b can be assumed to be non-zero after that point in the code - certainly,
on a cygwin or linux system, dereferencing a zero address causes a segmentation
fault, but on an embedded arm system, this is the most practical way to access
the interrupt vectors from C.


-- 
           Summary: bad code with -O2 if pointer dereference followed by
                    null test
           Product: gcc
           Version: 4.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: david_albert at axiometric dot com
 GCC build triplet: 4.2.1
  GCC host triplet: i486-linux-gnu
GCC target triplet: arm-elf-gcc


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33629

Reply via email to