>Submitter-Id: net >Originator: Randolph Chung >Organization: Debian >Confidential: no >Synopsis: Structure copy clobbers subsquent stores to structure >Severity: serious >Priority: medium >Category: optimization >Class: wrong-code >Release: 3.2.2 20030124 (Debian prerelease) >Environment:
System: Linux legolas 2.4.20-pa18 #110 Mon Jan 27 23:44:18 PST 2003 parisc unknown unknown GNU/Linux Architecture: parisc host: hppa-unknown-linux-gnu build: hppa-unknown-linux-gnu target: hppa-unknown-linux-gnu configured with: ../src/configure -v --enable-languages=c,c++,f77,proto,pascal,objc,ada --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.2 --enable-shared --with-system-zlib --enable-nls --without-included-gettext --enable-__cxa_atexit --enable-clocale=gnu --enable-objc-gc hppa-linux >Description: When -O2 is applied, the attach program generates incorrect output. This test case is extracted from a miscompilation in the linux kernel. The code does a structure copy then an assignment to a member of the structure. At -O2 (-O1 -fschedule-insns) the assignment is moved before the structure copy, and subsequently gets clobbered. >How-To-Repeat: Compile the following piece of code with gcc-3.2 -O2 /* ** Test to reproduce storing into a substructure getting ** clobbered by a structure copy. ** ** Compile with: gcc -O2 -o pty_test pty_test.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> typedef unsigned char cc_t; typedef unsigned int tcflag_t; typedef unsigned int __kernel_size_t; typedef int __kernel_ssize_t; typedef unsigned short kdev_t; struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t c_line; cc_t c_cc[19]; }; struct tty_driver { int magic; const char *driver_name; const char *name; int name_base; short major; short minor_start; short num; short type; short subtype; struct termios init_termios; int flags; int *refcount; }; struct termios tty_std_termios = {1, 2, 3, 4, 5}; static int pty_refcount; static struct tty_driver pty_driver; int main(void) { memset(&pty_driver, 0, sizeof(struct tty_driver)); pty_driver.magic = 0x5402; pty_driver.driver_name = "pty_master"; pty_driver.name = "pty"; pty_driver.major = 2; pty_driver.minor_start = 0; pty_driver.num = 256; pty_driver.type = 0x0004; pty_driver.subtype = 0x0001; pty_driver.init_termios = tty_std_termios; pty_driver.init_termios.c_iflag = 0; pty_driver.init_termios.c_oflag = 0; pty_driver.init_termios.c_cflag = 0000017 | 0000060 | 0000200; pty_driver.init_termios.c_lflag = 0; pty_driver.refcount = &pty_refcount; pty_driver.flags = 0x0002 | 0x0004; /* clobber the arg registers so the c_lflag value gets reloaded */ close(10); printf("pty_driver.init_termios.c_lflag = %d (should be 0)\n", pty_driver.init_termios.c_lflag); return 0; } >Fix: putting a reorder barrier (e.g. asm("")) before the store to c_lflag will workaround the bug