The generated code copies an argument to a local (new) stack frame before 
allocating that stack frame (adjusting the stack pointer), allowing an 
interrupt to corrupt that value.  The argument is copied to memory, so that the 
argument's address can be passed to another function.  As long as an interrupt 
doesn't occur within the 2 instruction window between copying the argument and 
adjusting the stack pointer, everything works fine.

Compiler command line:

arm-elf-gcc -v -save-temps -c -mcpu=arm7tdmi -mbig-endian -Wall -Wpointer-
arith -Wstrict-prototypes -Winline -Wundef -Woverloaded-virtual -g -O2 -
ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fvtable-gc -finit-
priority -D__ECOS -Wp,-MD,HPIDrv.tmp -o HPIDrv.o HPIDrv.c > HPIDrv.out 2>&1

Compiler output:

Reading specs from /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/specs
Configured with: ../../gcc-3.2.1/configure --prefix=/home/tools/gnu-3.2.1 --
target=arm-elf -v --enable-languages=c,c++ --with-gnu-as --with-gnu-ld --with-
newlib --with-gxx-include-dir=/home/tools/gnu-3.2.1/arm-elf/include
Thread model: single
gcc version 3.2.1
 /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/cpp0 -lang-c -v -
iprefix /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/ -D__GNUC__=3 -
D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=1 -D__GXX_ABI_VERSION=102 -D__ELF__ -
D__ELF__ -D__OPTIMIZE__ -D__STDC_HOSTED__=1 -Acpu=arm -Amachine=arm -
D__ARM_ARCH_4T__ -D__APCS_32__ -D__ARMEB__ -D__ELF__ -D__USES_INITFINI__ -
D__arm__ -D__ECOS -MD HPIDrv.tmp HPIDrv.c -Wall -Wpointer-arith -Wstrict-
prototypes -Winline -Wundef -Woverloaded-virtual HPIDrv.i
GNU CPP version 3.2.1 (cpplib) (ARM/ELF)
ignoring nonexistent directory "/home/tools/gnu-tools/arm-elf/sys-include"
ignoring nonexistent directory "/home/tools/gnu-3.2.1/arm-elf/sys-include"
ignoring duplicate directory "/home/tools/gnu-3.2.1/lib/gcc-lib/arm-
elf/3.2.1/include"
ignoring duplicate directory "/home/tools/gnu-3.2.1/arm-elf/include"
#include "..." search starts here:
#include <...> search starts here:
 /home/tools/gnu-tools/lib/gcc-lib/arm-elf/3.2.1/include
 /home/tools/gnu-tools/arm-elf/include
 /home/tools/gnu-3.2.1/include
End of search list.
 /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/cc1 -fpreprocessed 
HPIDrv.i -quiet -dumpbase HPIDrv.c -mcpu=arm7tdmi -mbig-endian -g -O2 -Wall -
Wpointer-arith -Wstrict-prototypes -Winline -Wundef -Woverloaded-virtual -
version -ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fvtable-
gc -finit-priority -o HPIDrv.s
GNU CPP version 3.2.1 (cpplib) (ARM/ELF)
GNU C version 3.2.1 (arm-elf)
        compiled by GNU C version 3.2.2 20030222 (Red Hat Linux 3.2.2-5).
HPIDrv.c:20: warning: conflicting types for built-in function `memset'
 /home/tools/gnu-tools/bin/../lib/gcc-lib/arm-elf/3.2.1/../../../../arm-
elf/bin/as -EB -marm7tdmi -o HPIDrv.o HPIDrv.s

HPIDrv.i file:

# 1 "HPIDrv.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "HPIDrv.c"

typedef unsigned char uint8;
typedef unsigned short uint16;
typedef void tHPIDrv;
typedef struct hpi_info
{
        tHPIDrv *HPIDrv;
        unsigned int CfgMask;
        uint16 ChannelID;
} HPI_INFO;
# 19 "HPIDrv.c"
extern int diag_printf(const char *fmt, ...);
extern void memset(void *, int, unsigned int);

int HPIDrv_SendMessages(tHPIDrv *const pDrv, const uint16 Type, const uint16 
ChannelID,
        const uint8 NumBlocks, const uint16 *const pSize, const uint16 *const 
*const ppData)
{

        diag_printf("pDrv=0x%08X, Type=0x%04X, ChannelID=%d, NumBlocks=%d, 
Size=%d, pData=0x%08X\n",
                        pDrv, Type, ChannelID, NumBlocks, *pSize, *ppData);
        return 0;
}

inline int HPIDrv_SendMessage(tHPIDrv *const pDrv, const uint16 Type, const 
uint16 ChannelID,
        const uint16 Size, const uint16 *const pData)
{
        return HPIDrv_SendMessages(pDrv, Type, ChannelID, 1, &Size, &pData);
}


int testit(HPI_INFO *hpi)
{
        typedef struct parm
        {
                uint16 a;
                uint16 b;
                uint16 c[8];
        } parm_t;
        parm_t V42Parms;

        memset(&V42Parms, 0, sizeof(V42Parms));

        if (HPIDrv_SendMessage(hpi->HPIDrv, 0x0800|0x0002, (hpi->CfgMask & 
0x00000001)?0:hpi->ChannelID,
                sizeof(V42Parms)/sizeof(uint16), (uint16 *)&V42Parms) != 0)
        {
                return 0;
        }

        return 1;
}

Portion of HPIDrv.s file showing invalid code generation in HPIDrv_SendMessage
() function:

.Lfe2:
        .size   testit,.Lfe2-testit
        .section        .text.HPIDrv_SendMessage,"ax",%progbits
        .align  2
        .global HPIDrv_SendMessage
        .type   HPIDrv_SendMessage,function
HPIDrv_SendMessage:
.LFB3:
.LSM25:
        @ args = 4, pretend = 0, frame = 4
        @ frame_needed = 1, uses_anonymous_args = 0
        mov     ip, sp
.LCFI8:
        stmfd   sp!, {fp, ip, lr, pc}
.LCFI9:
        mov     r3, r3, asl #16
        sub     fp, ip, #4
.LCFI10:
        mov     r3, r3, asr #16
        sub     lr, fp, #12
        strh    r3, [fp, #-14]  @ movhi <-- This instruction is redundant
.LSM26:
        mov     r1, r1, asl #16
.LSM27:
        strh    r3, [lr, #-2]!  @ movhi <-- The 'Size' argument (register r3)
                                        is copied to the local stack frame
                                        here, BEFORE the stack frame is
                                        allocated (below).
.LSM28:
        mov     r2, r2, asl #16
.LSM29:
        sub     sp, sp, #12  <-- Stack frame allocated.
.LCFI11:
.LSM30:
        add     ip, fp, #4
.LSM31:
.LSM32:
        mov     r1, r1, lsr #16
        mov     r2, r2, lsr #16
        mov     r3, #1
        str     lr, [sp, #0]
        str     ip, [sp, #4]
        bl      HPIDrv_SendMessages
        ldmea   fp, {fp, sp, pc}
.LFE3:

-- 
           Summary: Improper code generation causes stack corruption
           Product: gcc
           Version: 3.2.1
            Status: UNCONFIRMED
          Severity: critical
          Priority: P2
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: jay at systech dot com
                CC: gcc-bugs at gcc dot gnu dot org
  GCC host triplet: i386-redhat-linux
GCC target triplet: arm-elf


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

Reply via email to