[parisc-linux] [hppa-linux, gcc-3.2 regression] structure copy clobbers stores to substructure

tausq@debian.org tausq@debian.org
Tue, 28 Jan 2003 21:04:20 -0800 (PST)


>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