GCSE bug with global register variables
Bruno Haible
bruno@clisp.org
Tue Apr 13 11:14:00 GMT 2004
>Submitter-Id: net
>Originator: Bruno Haible
>Organization: GNU
>Confidential: no
>Synopsis: GCSE bug with global register variables
>Severity: serious
>Priority: low
>Category: optimization
>Class: wrong-code
>Release: 3.3.1 (SuSE Linux)
>Environment:
System: Linux linuix 2.4.21-99-default #1 Wed Sep 24 13:30:51 UTC 2003 i686 athlon i386 GNU/Linux
Architecture: i686
<machine, os, target, libraries (multiple lines)>
host: i586-suse-linux-gnu
build: i586-suse-linux-gnu
target: i586-suse-linux-gnu
configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib --enable-languages=c,c++,f77,objc,java,ada --disable-checking --enable-libgcj --with-gxx-include-dir=/usr/include/g++ --with-slibdir=/lib --with-system-zlib --enable-shared --enable-__cxa_atexit i586-suse-linux
>Description:
In a function using a global register variable, that conditionally calls
a nonreturning function, the GCSE omits the last update (a decrement)
of the global register variable.
>How-To-Repeat:
================================= bug.c ====================================
typedef void * object;
register object* STACK __asm__("%ebx");
typedef struct {
object GCself;
unsigned int tfl;
unsigned int data[0];
} * Sstring;
typedef struct {
object GCself;
unsigned int tfl;
object enc_eol;
object enc_towcs_error;
object enc_tombs_error;
object enc_charset;
object enc_mblen;
object enc_mbstowcs;
object enc_wcslen;
object enc_wcstombs;
object enc_range;
object enc_table;
unsigned int min_bytes_per_char;
unsigned int max_bytes_per_char;
} * Encoding;
extern void __attribute__((__noreturn__)) fehler_notreached (const char * file, unsigned int line);
extern object allocate_s32string (unsigned int len);
object n_char_to_string (const char * srcptr, unsigned int blen, object encoding)
{
const unsigned char * bptr = (const unsigned char *)srcptr;
const unsigned char * bendptr = bptr + blen;
unsigned int clen = ((unsigned int (*) (object, const unsigned char *, const unsigned char *)) ((const void *)((void*)((unsigned long)(((Encoding)((unsigned long)(encoding)-1))->enc_mblen)))))(encoding,bptr,bendptr);
(STACK[0] = encoding, STACK += 1);
{
object obj = allocate_s32string(clen);
encoding = (STACK -= 1, STACK[0]);
{
unsigned int * cptr = &((Sstring)((unsigned long)(obj)-1))->data[0];
unsigned int * cendptr = cptr + clen;
((void (*) (object, object, const unsigned char **, const unsigned char *, unsigned int**, unsigned int*)) ((const void *)((void*)((unsigned long)(((Encoding)((unsigned long)(encoding)-1))->enc_mbstowcs)))))(encoding,(object)0,&bptr,bendptr,&cptr,cendptr);
if (!(cptr == cendptr))
fehler_notreached("encoding.d",1910);
}
return obj;
}
}
============================================================================
$ gcc -O2 -Wall -S bug.c
In the resulting bug.s, you see that %ebx is incremented by 4 (this
corresponds to the STACK += 1 expression) but is never decremented back
by 4 (as expected from the STACK -= 1 expression two lines below).
================================= bug.s ====================================
.file "bug.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "encoding.d"
.text
.p2align 4,,15
.globl n_char_to_string
.type n_char_to_string, @function
n_char_to_string:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
subl $36, %esp
movl 8(%ebp), %eax
movl 12(%ebp), %edx
movl 16(%ebp), %edi
addl %eax, %edx
movl %edx, -20(%ebp)
movl %eax, -16(%ebp)
pushl %edx
pushl %eax
pushl %edi
call *23(%edi)
movl %eax, %esi
movl %edi, (%ebx)
movl %eax, (%esp)
addl $4, %ebx
call allocate_s32string
movl %eax, -24(%ebp)
movl -4(%ebx), %edi
addl $7, %eax
movl %eax, -12(%ebp)
leal (%eax,%esi,4), %esi
movl %esi, -28(%ebp)
popl %ecx
popl %eax
leal -12(%ebp), %eax
pushl %esi
pushl %eax
leal -16(%ebp), %eax
movl -20(%ebp), %edx
pushl %edx
pushl %eax
pushl $0
pushl %edi
call *27(%edi)
movl -28(%ebp), %eax
addl $32, %esp
cmpl %eax, -12(%ebp)
jne .L4
movl -24(%ebp), %eax
leal -8(%ebp), %esp
popl %esi
popl %edi
popl %ebp
ret
.L4:
pushl %eax
pushl %eax
pushl $1910
pushl $.LC0
call fehler_notreached
.size n_char_to_string, .-n_char_to_string
.ident "GCC: (GNU) 3.3.1 (SuSE Linux)"
============================================================================
>Fix:
The bug goes away if -fno-gcse is passed to gcc.
More information about the Gcc-bugs
mailing list