[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: