Bug#634261: More debugging info
Some more debugging information:
In the failing case stdout get flipped to an unaligned value in
_IO_check_libio function defined in libio/oldstdfiles.c, which
contains the following code:
static void
_IO_check_libio ()
{
if (&_IO_stdin_used == NULL)
{
/* We are using the old one. */
_IO_stdin = stdin = (_IO_FILE *) &_IO_stdin_;
_IO_stdout = stdout = (_IO_FILE *) &_IO_stdout_;
_IO_stderr = stderr = (_IO_FILE *) &_IO_stderr_;
[...]
Why we are taking the 'if' branch is a bit of a mystery to me, because
_IO_stdin_used appears to be defined, as this bit of gdb session
illustrates:
(gdb) break _IO_check_libio
Function "_IO_check_libio" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (_IO_check_libio) pending.
(gdb) run
Starting program: /home/jurij/libc/tmp/foo
Breakpoint 1, _IO_check_libio () at oldstdfiles.c:79
warning: Source file is more recent than executable.
79 if (&_IO_stdin_used == NULL)
(gdb) print _IO_stdin_used
$1 = 131073
(gdb) print &_IO_stdin_used
$2 = (const int *) 0x10638
(gdb) next
78 {
(gdb) next
79 if (&_IO_stdin_used == NULL)
(gdb) next
82 _IO_stdin = stdin = (_IO_FILE *) &_IO_stdin_;
(gdb) next
83 _IO_stdout = stdout = (_IO_FILE *) &_IO_stdout_;
(gdb) print stdout
$3 = (FILE *) 0x207c0
(gdb) print &_IO_stdout_
$4 = (struct _IO_FILE_plus *) 0xf7fc3114
After this line is executed, stdout starts pointing to the new
unaligned location, eventually leading to a segfault. An important
observation is that symbol is unaligned even in libc, which obviously
should not be happening:
jurij@debian:~/libc/tmp$ nm /usr/lib/debug/lib/sparc-linux-gnu/libc-2.13.so | grep _IO_stdout_
0017f114 D _IO_stdout_
To answer why we are hitting the &_IO_stdin_used == NULL check, I've
looked at the assembly code, relevant parts of it look like that:
.LLADDPC0:
jmp %o7+8
add %o7, %l7, %l7
#NO_APP
.align 4
.align 32
.type _IO_check_libio, #function
.proc 020
_IO_check_libio:
.LLFB71:
.file 1 "oldstdfiles.c"
.loc 1 78 0
.cfi_startproc
save %sp, -96, %sp
.LLCFI0:
.cfi_def_cfa_register 30
.cfi_window_save
.loc 1 79 0
sethi %hi(_IO_stdin_used), %g1
.loc 1 78 0
sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %l7
call .LLADDPC0
add %l7, %lo(_GLOBAL_OFFSET_TABLE_+4), %l7
.cfi_register 15, 31
.loc 1 79 0
or %g1, %lo(_IO_stdin_used), %g1
ld [%l7+%g1], %g1
cmp %g1, 0
[...]
So it's not simply using _IO_stdin_used address, but doing some
resolution of it, which, indeed, returns a NULL.
I don't think I can make any further progress on this bug without
investing significant amount of time into it, but we have enough
debugging information for a good upstream bug report, and I would be
glad to provide additional info if needed. One of the main questions
we should try to answer is why the _IO_std{in,out,err}_ symbols end up
to be not 8-byte aligned in libc, even though it looks like they
should be.
Best regards,
--
Jurij Smakov jurij@wooyd.org
Key: http://www.wooyd.org/pgpkey/ KeyID: C99E03CC
Reply to: