* An optimization bug in egcs 1.0.2?
@ 1998-03-23 15:11 H.J. Lu
1998-03-23 19:24 ` John Carr
0 siblings, 1 reply; 7+ messages in thread
From: H.J. Lu @ 1998-03-23 15:11 UTC (permalink / raw)
To: egcs
Hi,
While compiling glibc 2.0.7 with egcs 1.0.2, I noticed that egcs 1.0.2
turns
if (imap->l_global)
{
/* This object is in the global scope list. Remove it. */
struct link_map **tail = _dl_global_scope_end;
do
--tail;
while (*tail != imap);
--_dl_global_scope_end;
memcpy (tail, tail + 1,
(void *) _dl_global_scope_end - (void *) tail);
_dl_global_scope_end[0] = NULL;
_dl_global_scope_end[1] = NULL;
}
into
if (imap->l_global)
{
/* This object is in the global scope list. Remove it. */
struct link_map **tail = _dl_global_scope_end;
do
--tail;
while (*tail != imap);
--_dl_global_scope_end;
_dl_global_scope_end[0] = NULL;
_dl_global_scope_end[1] = NULL;
memcpy (tail, tail + 1,
(void *) _dl_global_scope_end - (void *) tail);
_dl_global_scope_end[1] = NULL;
}
when I use -O2 -fPIC. As the result, the resuling binary doesn't work
since _dl_global_scope_end[0] is within (void *) tail + 1 and
(void *) tail + 1 + (void *) _dl_global_scope_end - (void *) tail.
Is that normal for a C compiler to do it?
BTW, I changed it to
if (imap->l_global)
{
/* This object is in the global scope list. Remove it. */
struct link_map **tail = _dl_global_scope_end;
do
--tail;
while (*tail != imap);
memcpy (tail, tail + 1,
(void *) _dl_global_scope_end - (void *) tail);
--_dl_global_scope_end;
}
since _dl_global_scope_end [0] and _dl_global_scope_end [1] are
always NULL to begin with. It works fine for me.
Thanks.
--
H.J. Lu (hjl@gnu.org)
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: An optimization bug in egcs 1.0.2?
1998-03-23 15:11 An optimization bug in egcs 1.0.2? H.J. Lu
@ 1998-03-23 19:24 ` John Carr
1998-03-23 19:24 ` H.J. Lu
0 siblings, 1 reply; 7+ messages in thread
From: John Carr @ 1998-03-23 19:24 UTC (permalink / raw)
To: H.J. Lu; +Cc: egcs
The code calls memcpy with overlapping objects. That is undefined in
ANSI C; use memmove instead. (It also subtracts pointers to void so
the authors presumably didn't care about ANSI C, but the misuse of
memcpy is a real problem.)
There may also be a bug in egcs in addition to the bug in the code.
Can you generate a standalone test case with annotated assembly code?
> if (imap->l_global)
> {
> /* This object is in the global scope list. Remove it. */
> struct link_map **tail = _dl_global_scope_end;
> do
> --tail;
> while (*tail != imap);
> --_dl_global_scope_end;
> memcpy (tail, tail + 1,
> (void *) _dl_global_scope_end - (void *) tail);
> _dl_global_scope_end[0] = NULL;
> _dl_global_scope_end[1] = NULL;
> }
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: An optimization bug in egcs 1.0.2?
1998-03-23 19:24 ` John Carr
@ 1998-03-23 19:24 ` H.J. Lu
1998-03-23 23:47 ` Jeffrey A Law
1998-03-24 11:16 ` Richard Henderson
0 siblings, 2 replies; 7+ messages in thread
From: H.J. Lu @ 1998-03-23 19:24 UTC (permalink / raw)
To: John Carr; +Cc: egcs, Ulrich Drepper
>
>
> The code calls memcpy with overlapping objects. That is undefined in
> ANSI C; use memmove instead. (It also subtracts pointers to void so
> the authors presumably didn't care about ANSI C, but the misuse of
> memcpy is a real problem.)
It is from the dynamic linker in glibc 2. memcpy is safe there.
memcpy is used for optimization.
>
> There may also be a bug in egcs in addition to the bug in the code.
> Can you generate a standalone test case with annotated assembly code?
I don't think there is a question on egcs. I don't want to spend
any more time on it since it has been fixed in glibc 2. If you really
want to look into it, I can do it when I find time.
>
>
> > if (imap->l_global)
> > {
> > /* This object is in the global scope list. Remove it. */
> > struct link_map **tail = _dl_global_scope_end;
> > do
> > --tail;
> > while (*tail != imap);
> > --_dl_global_scope_end;
> > memcpy (tail, tail + 1,
> > (void *) _dl_global_scope_end - (void *) tail);
> > _dl_global_scope_end[0] = NULL;
> > _dl_global_scope_end[1] = NULL;
> > }
>
--
H.J. Lu (hjl@gnu.org)
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: An optimization bug in egcs 1.0.2?
1998-03-23 19:24 ` H.J. Lu
@ 1998-03-23 23:47 ` Jeffrey A Law
1998-03-24 11:16 ` Richard Henderson
1 sibling, 0 replies; 7+ messages in thread
From: Jeffrey A Law @ 1998-03-23 23:47 UTC (permalink / raw)
To: H.J. Lu; +Cc: John Carr, egcs, Ulrich Drepper
In message < m0yHHxm-00058JC@ocean.lucon.org >you write:
> >
> >
> > The code calls memcpy with overlapping objects. That is undefined in
> > ANSI C; use memmove instead. (It also subtracts pointers to void so
> > the authors presumably didn't care about ANSI C, but the misuse of
> > memcpy is a real problem.)
>
> It is from the dynamic linker in glibc 2. memcpy is safe there.
> memcpy is used for optimization.
Is the compiler producing an inline expansion of memcpy? If so
you'll need to compile with -fno-builtin.
jeff
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: An optimization bug in egcs 1.0.2?
1998-03-24 11:16 ` Richard Henderson
@ 1998-03-24 8:29 ` H.J. Lu
1998-03-24 9:27 ` H.J. Lu
1 sibling, 0 replies; 7+ messages in thread
From: H.J. Lu @ 1998-03-24 8:29 UTC (permalink / raw)
To: rth; +Cc: egcs, drepper
>
> On Mon, Mar 23, 1998 at 04:53:09PM -0800, H.J. Lu wrote:
> > It is from the dynamic linker in glibc 2. memcpy is safe there.
> > memcpy is used for optimization.
>
> No, memcpy on overlapping objects is wrong.
>
> memcpy (tail, tail + 1,
> (void *) _dl_global_scope_end - (void *) tail);
>
> This may happen to work on the particular implementation
> of memcpy used on i386, but will fail for others.
>
I was wrong. The bug was in glibc 2.0.7. Here is the code in question.
As you can see, _dl_global_scope_end is adjusted before calling
memmove, which, BTW, is not inlined by egcs 1.0.2. The dynamic linker
will then call fixup () where there is
*_dl_global_scope_end = NULL;
As the result, when memmove is entered, memory pointed to by tail + 1
has been already changed.
Ulrich, we should go over every place in dl where _dl_global_scope_end
is used to double check if there is a similar bug.
Thanks.
--
H.J. Lu (hjl@gnu.org)
----
#include <string.h>
#include <link.h>
void
_dl_remove (struct link_map *map)
{
struct link_map **tail = _dl_global_scope_end;
do
--tail;
while (*tail != map);
--_dl_global_scope_end;
memmove (tail, tail + 1,
(char *) _dl_global_scope_end - (char *) tail);
_dl_global_scope_end [0] = NULL;
_dl_global_scope_end [1] = NULL;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: An optimization bug in egcs 1.0.2?
1998-03-24 11:16 ` Richard Henderson
1998-03-24 8:29 ` H.J. Lu
@ 1998-03-24 9:27 ` H.J. Lu
1 sibling, 0 replies; 7+ messages in thread
From: H.J. Lu @ 1998-03-24 9:27 UTC (permalink / raw)
To: rth; +Cc: egcs, drepper
>
> On Mon, Mar 23, 1998 at 04:53:09PM -0800, H.J. Lu wrote:
> > It is from the dynamic linker in glibc 2. memcpy is safe there.
> > memcpy is used for optimization.
>
> No, memcpy on overlapping objects is wrong.
>
> memcpy (tail, tail + 1,
> (void *) _dl_global_scope_end - (void *) tail);
>
> This may happen to work on the particular implementation
> of memcpy used on i386, but will fail for others.
>
That has nothing to do with memcpy. I extracted the miscompiled
portion from glibc 2.0.7 into a separate file. I am enclosing
the source code and the asm output. I believe something is wrong.
--
H.J. Lu (hjl@gnu.org)
----dl-remove.c---
#include <string.h>
#include <link.h>
void
_dl_remove (struct link_map *map)
{
struct link_map **tail = _dl_global_scope_end;
do
--tail;
while (*tail != map);
--_dl_global_scope_end;
memmove (tail, tail + 1,
(char *) _dl_global_scope_end - (char *) tail);
_dl_global_scope_end [0] = NULL;
_dl_global_scope_end [1] = NULL;
}
----
.file "dl-remove.c"
.version "01.01"
/ GNU C version egcs-2.90.27 980315 (egcs-1.0.2 release) (i586-unknown-linux-gnulibc1) compiled by GNU C version egcs-2.90.26 980308 (egcs-1.0.2 prerelease).
/ options passed: -g -g0 -O2 -Wall -Winline -Wno-parentheses
/ -Wstrict-prototypes -Wwrite-strings -fno-exceptions -fPIC -fno-common
/ options enabled: -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks
/ -fexpensive-optimizations -fthread-jumps -fstrength-reduce -fpeephole
/ -fforce-mem -ffunction-cse -finline -fkeep-static-consts -fcaller-saves
/ -fpcc-struct-return -frerun-cse-after-loop -frerun-loop-opt
/ -fschedule-insns2 -fPIC -fverbose-asm -fgnu-linker -fregmove
/ -falias-check -fargument-alias -m80387 -mhard-float -mno-soft-float
/ -mieee-fp -mfp-ret-in-387 -mcpu=pentium -march=pentium
gcc2_compiled.:
.text
.align 4
.globl _dl_remove
.type _dl_remove,@function
_dl_remove:
pushl %ebp
movl %esp,%ebp
pushl %ebx
call .L9
.L9:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L9],%ebx
movl _dl_global_scope_end@GOT(%ebx),%eax
movl 8(%ebp),%ecx
movl (%eax),%edx
.align 4
.L5:
addl $-4,%edx
cmpl %ecx,(%edx)
jne .L5
movl _dl_global_scope_end@GOT(%ebx),%eax
addl $-4,(%eax)
movl _dl_global_scope_end@GOT(%ebx),%eax
movl (%eax),%eax
subl %edx,%eax
pushl %eax
leal 4(%edx),%eax
pushl %eax
pushl %edx
call memmove@PLT
movl _dl_global_scope_end@GOT(%ebx),%eax
movl (%eax),%eax
movl $0,(%eax)
movl _dl_global_scope_end@GOT(%ebx),%eax
movl (%eax),%eax
movl $0,4(%eax)
movl -4(%ebp),%ebx
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size _dl_remove,.Lfe1-_dl_remove
.ident "GCC: (GNU) egcs-2.90.27 980315 (egcs-1.0.2 release)"
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: An optimization bug in egcs 1.0.2?
1998-03-23 19:24 ` H.J. Lu
1998-03-23 23:47 ` Jeffrey A Law
@ 1998-03-24 11:16 ` Richard Henderson
1998-03-24 8:29 ` H.J. Lu
1998-03-24 9:27 ` H.J. Lu
1 sibling, 2 replies; 7+ messages in thread
From: Richard Henderson @ 1998-03-24 11:16 UTC (permalink / raw)
To: H.J. Lu; +Cc: egcs, Ulrich Drepper
On Mon, Mar 23, 1998 at 04:53:09PM -0800, H.J. Lu wrote:
> It is from the dynamic linker in glibc 2. memcpy is safe there.
> memcpy is used for optimization.
No, memcpy on overlapping objects is wrong.
memcpy (tail, tail + 1,
(void *) _dl_global_scope_end - (void *) tail);
This may happen to work on the particular implementation
of memcpy used on i386, but will fail for others.
r~
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~1998-03-24 11:16 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1998-03-23 15:11 An optimization bug in egcs 1.0.2? H.J. Lu
1998-03-23 19:24 ` John Carr
1998-03-23 19:24 ` H.J. Lu
1998-03-23 23:47 ` Jeffrey A Law
1998-03-24 11:16 ` Richard Henderson
1998-03-24 8:29 ` H.J. Lu
1998-03-24 9:27 ` H.J. Lu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).