Bug 1529549 - glibc 2.26.9000 pthread problems with giac on i386
Summary: glibc 2.26.9000 pthread problems with giac on i386
Alias: None
Product: Fedora
Classification: Fedora
Component: glibc
Version: rawhide
Hardware: i386
OS: Linux
Target Milestone: ---
Assignee: Florian Weimer
QA Contact: Fedora Extras Quality Assurance
Depends On: 1529979
TreeView+ depends on / blocked
Reported: 2017-12-28 16:53 UTC by Frederic Han
Modified: 2018-01-12 10:18 UTC (History)
11 users (show)

Fixed In Version: glibc-2.26.9000-35.fc28
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Last Closed: 2018-01-12 10:18:54 UTC
Type: Bug

Attachments (Terms of Use)

System ID Priority Status Summary Last Updated
Red Hat Bugzilla 1529982 unspecified CLOSED glibc: recompile glibc to fix incorrect CFI information on i386 2020-10-14 00:28:05 UTC

Internal Links: 1529982

Description Frederic Han 2017-12-28 16:53:52 UTC
Description of problem:
pthread instructions in giac gives a crash with fedora-rawhide-i386 but not with fedora-27-i386 and not with fedora-rawhide-x86_64 

Version-Release number of selected component (if applicable):
glibc-2.26.9000 giac- (but also earlier version of giac)

How reproducible:
any giac version on i386 with rawhide

Steps to Reproduce:
1.launch icas
2.enter any value, ex: 7
3.it crashes

Actual results:

Expected results:

Additional info:

Starting program: /usr/bin/icas 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
Missing separate debuginfo for /lib/sse2/libgf2x.so.1
Try: dnf --enablerepo='*debug*' install /usr/lib/debug/.build-id/77/abebab3e666aa911fcbfe609cbe9d4cf876a75.debug
// Using locale /usr/share/locale/
// fr_FR.UTF-8
// /usr/share/locale/
// giac
// UTF-8
// Maximum number of parallel threads 4
Help file /usr/share/giac/doc/fr/aide_cas not found
Added 165 synonyms
Welcome to giac readline interface
(c) 2001,2017 B. Parisse & others
Homepage http://www-fourier.ujf-grenoble.fr/~parisse/giac.html
Released under the GPL license 3.0 or above
See http://www.gnu.org for license details
May contain BSD licensed software parts (lapack, atlas, tinymt)
Press CTRL and D simultaneously to finish session
Type ?commandname for help
0>> 7
[New Thread 0xf4d73b40 (LWP 38)]

Thread 2 "icas" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xf4d73b40 (LWP 38)]
0x56878f90 in ?? ()
(gdb) bt
#0  0x56878f90 in ?? ()
#1  0xf6c443c9 in start_thread (arg=0xf4d73b40) at pthread_create.c:463
#2  0xf68337a6 in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:108

adding a break in pthread_exit gives:

0>> 7
[New Thread 0xf4d73b40 (LWP 40)]
[Switching to Thread 0xf4d73b40 (LWP 40)]

Thread 2 "icas" hit Breakpoint 1, __pthread_exit (value=value@entry=0x0) at pthread_exit.c:25
25	{
(gdb) n
26	  THREAD_SETMEM (THREAD_SELF, result, value);
28	  __do_cancel ();
0xf78c32c5 in std::imvector<giac::gen>::begin (this=<optimized out>) at vector.h:205
205	    iterator begin(){ return _taille>0?_begin_immediate_vect:((_Tp *) _tab); }
giac::in_thread_eval (arg=0x56722610) at global.cc:3544
3544	    gen g = (*v)[0];

Thread 2 "icas" received signal SIGSEGV, Segmentation fault.
0x56878f90 in ?? ()

Comment 1 Florian Weimer 2017-12-31 12:50:33 UTC
The crash seems to be happening in a destructor during unwinding:

0xf6906ce6 in _Unwind_ForcedUnwind (exc=<optimized out>, stop=<optimized out>, stop_argument=<optimized out>) at ../../../libgcc/unwind.inc:212
212     }
0xf6906ce8      212     }
0xf78c62c5 in std::imvector<giac::gen>::begin (this=<optimized out>) at vector.h:205
205     vector.h: No such file or directory.
giac::in_thread_eval (arg=0x56721e10) at global.cc:3544
3544    global.cc: No such file or directory.
0xf78c62ca      3544    in global.cc
0xf78c62cc      3544    in global.cc
0xf78c62cf      3544    in global.cc
0xf71cdf10 in giac::gen::~gen()@plt () from /lib/libgiac.so.0
0x56878790 in ?? ()

Upon entry into the PLT stub, the value of ebx appears to be invalid:

Dump of assembler code for function _ZN4giac3genD1Ev@plt:
=> 0xf71cdf10 <+0>:     jmp    *0x15dc(%ebx)
   0xf71cdf16 <+6>:     push   $0x2ba0
   0xf71cdf1b <+11>:    jmp    0xf71c87c0

(gdb) print/x $ebx
$2 = 0xf4d892a0
(gdb) print/x $ebx + 0x15dc
$3 = 0xf4d8a87c

This does not match the address of the .got:

        0xf7fa4fb4 - 0xf7facfec is .got in /lib/libgiac.so.0

In the exception handler landing pad, %ebx is restored from %esi:

   0xf78c62c5 <+533>:   mov    %eax,%edi
   0xf78c62c7 <+535>:   mov    -0x60(%ebp),%eax
   0xf78c62ca <+538>:   mov    %esi,%ebx
   0xf78c62cc <+540>:   mov    %eax,(%esp)
   0xf78c62cf <+543>:   call   0xf71cdf10 <_ZN4giac3genD1Ev@plt>

Upon entry to pthread_exit, both ebx and esi have the correct value:

Thread 2 "icas" hit Breakpoint 1, __pthread_exit (value=value@entry=0x0) at pthread_exit.c:25
25      {
(gdb) print/x $ebx
$1 = 0xf7fa4fb4
(gdb) info symb 0xf7fa4fb4
_GLOBAL_OFFSET_TABLE_ in section .got of /lib/libgiac.so.0
(gdb) print/x $esi
$2 = 0xf7fa4fb4

This means that either the exception handling information is faulty or not correctly processed by the libgcc unwinder, or glibc incorrectly clobbers register contents.

Comment 2 Florian Weimer 2017-12-31 13:04:52 UTC
Does not reproduce with glibc-2.26.9000-27.fc28.i686.

Comment 3 Florian Weimer 2017-12-31 14:48:13 UTC
Seems to be caused by -fstack-clash-protection.  Yuck.

Comment 4 Florian Weimer 2017-12-31 15:22:46 UTC
Looks like __pthread_unwind is miscompiled.  Compiling nptl/unwind.c with -fno-stack-clash-protection fixes this.

(gdb) disassemble __pthread_unwind
Dump of assembler code for function __pthread_unwind:
   0xf6879790 <+0>:     push   %esi
   0xf6879791 <+1>:     push   %ebx
   0xf6879792 <+2>:     push   %esi
   0xf6879793 <+3>:     pop    %esi
   0xf6879794 <+4>:     call   0xf68712dd <__x86.get_pc_thunk.dx>
   0xf6879799 <+9>:     add    $0x71867,%edx
   0xf687979f <+15>:    sub    $0x4,%esp
   0xf68797a2 <+18>:    mov    %eax,%esi
   0xf68797a4 <+20>:    mov    0x38f4(%edx),%eax
   0xf68797aa <+26>:    test   %eax,%eax
   0xf68797ac <+28>:    jne    0xf68797cd <__pthread_unwind+61>
   0xf68797ae <+30>:    mov    $0x14,%eax
   0xf68797b3 <+35>:    call   *%gs:0x10
   0xf68797ba <+42>:    mov    $0x9,%ecx
   0xf68797bf <+47>:    mov    %eax,%ebx
   0xf68797c1 <+49>:    mov    $0x25,%eax
   0xf68797c6 <+54>:    call   *%gs:0x10
   0xf68797cd <+61>:    mov    0x38e0(%edx),%edx
   0xf68797d3 <+67>:    mov    %esi,%eax
   0xf68797d5 <+69>:    ror    $0x9,%edx
   0xf68797d8 <+72>:    xor    %gs:0x18,%edx
   0xf68797df <+79>:    call   *%edx
End of assembler dump.

CFI data:

000000b0 0000002c 000000b4 FDE cie=00000000 pc=00000180..000001d1
  DW_CFA_advance_loc: 1 to 00000181
  DW_CFA_def_cfa_offset: 8
  DW_CFA_offset: r6 (esi) at cfa-8
  DW_CFA_advance_loc: 1 to 00000182
  DW_CFA_def_cfa_offset: 12
  DW_CFA_offset: r3 (ebx) at cfa-12
  DW_CFA_advance_loc: 1 to 00000183
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (esi) at cfa-16
  DW_CFA_advance_loc: 1 to 00000184
  DW_CFA_restore: r6 (esi)
  DW_CFA_def_cfa_offset: 12
  DW_CFA_advance_loc: 14 to 00000192
  DW_CFA_def_cfa_offset: 20
  DW_CFA_advance_loc: 51 to 000001c5
  DW_CFA_def_cfa_offset: 24
  DW_CFA_advance_loc: 1 to 000001c6
  DW_CFA_def_cfa_offset: 28
  DW_CFA_advance_loc: 1 to 000001c7
  DW_CFA_def_cfa_offset: 32

GCC produces this assembly:

        .globl  __GI___pthread_unwind
        .hidden __GI___pthread_unwind
        .type   __GI___pthread_unwind, @function
        .loc 1 112 0
        pushl   %esi
        .cfi_def_cfa_offset 8
        .cfi_offset 6, -8
        pushl   %ebx
        .cfi_def_cfa_offset 12
        .cfi_offset 3, -12
        pushl   %esi
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        popl    %esi
        .cfi_restore 6
        .cfi_def_cfa_offset 12
        call    __x86.get_pc_thunk.bx
        addl    $_GLOBAL_OFFSET_TABLE_, %ebx
        subl    $8, %esp
        .cfi_def_cfa_offset 20
        .loc 1 112 0
        movl    %eax, %esi
        .loc 1 118 0
        xorl    %edx, %edx
        .loc 1 114 0
# 114 "unwind.c" 1
        movl %gs:8,%ecx
# 0 "" 2
        .loc 1 118 0
        xorl    %eax, %eax
# 118 "unwind.c" 1
        movl %eax,%gs:592
        movl %edx,%gs:596
# 0 "" 2
        .loc 1 119 0
        leal    unwind_cleanup@GOTOFF(%ebx), %eax
# 119 "unwind.c" 1
        movl %eax,%gs:600
# 0 "" 2
        .loc 1 121 0
        leal    unwind_stop@GOTOFF(%ebx), %eax
        addl    $592, %ecx
        pushl   %esi
        .cfi_def_cfa_offset 24
        pushl   %eax
        .cfi_def_cfa_offset 28
        pushl   %ecx
        .cfi_def_cfa_offset 32
        call    _Unwind_ForcedUnwind@PLT
        .loc 1 125 0
        call    abort@PLT
        .size   __GI___pthread_unwind, .-__GI___pthread_unwind
        .globl  __pthread_unwind
        .set    __pthread_unwind,__GI___pthread_unwind

I wonder if the push/pop combination of %esi causes the problem because it could obscure the earlier saved value of %esi, so that the unwinder is not able to restore it anymore.

Comment 5 Florian Weimer 2017-12-31 19:49:15 UTC
I'm now pretty confident this is a GCC bug.

I posted a test case upstream:


Comment 6 Florian Weimer 2018-01-12 10:18:54 UTC
Fixed by the rebuild in glibc-2.26.9000-35.fc28.

Note You need to log in before you can comment on or make changes to this bug.