This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Serious code generation/optimisation bug (I think)


I was debugging a function and by inserting the debug statement crashed
the system. Some investigation revealed that gcc 4.3.2 arm-eabi (compiled
from sources) with -O2 under some circumstances assumes that if a pointer
is dereferenced, it can not be NULL therefore explicite tests against
NULL can be later eliminated. Here is a short function that demonstrates
the erroneous behaviour:

extern void Debug( unsigned int x );

typedef struct s_head {

        struct s_head   *next;
        unsigned int    value;

} A_STRUCT;

void InsertByValue( A_STRUCT **queue, A_STRUCT *ptr )
{
A_STRUCT *tst;

   for ( tst = *queue ; ; queue = &tst->next, tst = *queue ) {

//     Debug( tst->value );

       if ( ! tst ) {
           ptr->next = (void *) 0;
           break;
       }

       if ( tst->value < ptr->value ) {
           ptr->next = tst;
           break;
       }
    }
    *queue = ptr;
}

Compiling this function with

arm-eabi-gcc -O2 -S foo.c

generates perfect code. However, if the Debug( tst->value ); is not
commented out, then the generated code looks like this:

InsertByValue:
        @ Function supports interworking.
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        stmfd   sp!, {r4, r5, r6, lr}
        mov     r6, r0
        ldr     r4, [r0, #0]
        mov     r5, r1
        b       .L3
.L2:
        mov     r6, r4
        ldr     r4, [r4, #0]
.L3:
        ldr     r0, [r4, #4]
        bl      Debug
        ldr     r2, [r4, #4]
        ldr     r3, [r5, #4]
        cmp     r2, r3
        bcs     .L2
        str     r4, [r5, #0]
        str     r5, [r6, #0]
        ldmfd   sp!, {r4, r5, r6, lr}
        bx      lr

As you can see, when 'tst' is fetched to R4, it is not checked against
being 0 anywhere and the whole if ( ! tst ) { ... } bit is completely
eliminated from the code. Indeed, the actual compiled code crashes because
the loop does not stop when the end of the list is reached.

I know that you are not supposed to dereference a NULL pointer, however,
on the microcontroller I have it is perfectly legal: what you get is an
element of the exception vector table that resides at 0x0.

I don't think that the compiler has a right to remove my test, just
because it assumes that if I derferenced a pointer then it surely was not
NULL. At least it should give me a warning (which it does not, not even
with -W -Wall -Wextra).

Zoltan



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]