>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


Reply via email to