Summary: | Application segfaults when throwing an exception that destroys an fstream | ||
---|---|---|---|
Product: | gcc | Reporter: | Jonathan Briggs <zlynx> |
Component: | libstdc++ | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | RESOLVED INVALID | ||
Severity: | normal | CC: | gcc-bugs, hjl.tools, rguenth |
Priority: | P3 | ||
Version: | 4.4.1 | ||
Target Milestone: | --- | ||
Host: | ia64-redhat-linux | Target: | |
Build: | Known to work: | 4.3.0 | |
Known to fail: | 4.4.1 4.4.2 | Last reconfirmed: | |
Attachments: | reproduce |
Description
Jonathan Briggs
2009-07-23 20:37:54 UTC
First of all, please provide a complete, small, self contained, snippet showing the problem. Thanks. Created attachment 18247 [details]
reproduce
Also note that this seems to be a IA64 problem, not x86. I see, I can't reproduce it on x86_64-linux, maybe Richard can help for ia64 testing... If that's really the case, however, probably not a libstdc++-proper issue. The actual segfault seems to happen in the .plt section. I am not entirely clear on how this is laid out and how to find what symbol is where. But on entry to the plt code, the r1 register is set to an invalid memory location and it is then read from. It appears that r1 is supposed to be set from r35 much earlier, perhaps it gets overwritten. It sort of looks like the exception unwinder changed the register value but the code expects the register to still hold the right offset to the PLT. It works for me on RHEL 4 with gcc 4.4.1: [hjl@gnu-14 tmp]$ cat foo.cc #include <fstream> using namespace std; void f(const char * filename) { ifstream is; throw 2; } int main() { try { f("v3"); } catch(int e) { } } [hjl@gnu-14 tmp]$ /usr/gcc-4.4/bin/g++ foo.cc -Wl,-rpath,/usr/gcc-4.4/lib [hjl@gnu-14 tmp]$ ldd a.out linux-gate.so.1 => (0xa000000000000000) libstdc++.so.6 => /usr/gcc-4.4/lib/libstdc++.so.6 (0x2000000000044000) libm.so.6.1 => /lib/tls/libm.so.6.1 (0x2000000000240000) libgcc_s.so.1 => /usr/gcc-4.4/lib/libgcc_s.so.1 (0x20000000002fc000) libunwind.so.7 => /usr/gcc-4.4/lib/libunwind.so.7 (0x2000000000330000) libc.so.6.1 => /lib/tls/libc.so.6.1 (0x200000000035c000) /lib/ld-linux-ia64.so.2 (0x2000000000000000) [hjl@gnu-14 tmp]$ ./a.out [hjl@gnu-14 tmp]$ /usr/gcc-4.4/bin/g++ -v Using built-in specs. Target: ia64-unknown-linux-gnu Configured with: /net/gnu-13/export/gnu/src/gcc-4.4/gcc/configure --enable-clocale=gnu --with-system-zlib --enable-checking=assert --with-demangler-in-ld --enable-shared --enable-threads=posix --enable-haifa --prefix=/usr/gcc-4.4 --with-local-prefix=/usr/local Thread model: posix gcc version 4.4.1 (GCC) [hjl@gnu-14 tmp]$ ld -V GNU ld (Linux/GNU Binutils) 2.19.51.0.14.20090722 Supported emulations: elf64_ia64 [hjl@gnu-14 tmp]$ It works on SLES11 as well. rguenther@scandium:/tmp> g++ -v Using built-in specs. Target: ia64-suse-linux Configured with: ../configure --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib --libexecdir=/usr/lib --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.3 --enable-ssp --disable-libssp --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --disable-libgcj --disable-libmudflap --with-slibdir=/lib --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-version-specific-runtime-libs --program-suffix=-4.3 --enable-linux-futex --with-system-libunwind --build=ia64-suse-linux Thread model: posix gcc version 4.3.2 [gcc-4_3-branch revision 141291] (SUSE Linux) rguenther@scandium:/tmp> ld --version GNU ld (GNU Binutils; SUSE Linux Enterprise 11) 2.19 Copyright 2007 Free Software Foundation, Inc. This program is free software; you may redistribute it under the terms of the GNU General Public License version 3 or (at your option) a later version. This program has absolutely no warranty. rguenther@scandium:/tmp> g++ -o t t.cpp rguenther@scandium:/tmp> ldd t linux-gate.so.1 => (0xa000000000000000) libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x2000000000090000) libm.so.6.1 => /lib/libm.so.6.1 (0x2000000000270000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x2000000000350000) libunwind.so.7 => /lib/libunwind.so.7 (0x2000000000380000) libc.so.6.1 => /lib/libc.so.6.1 (0x20000000003d0000) /lib/ld-linux-ia64.so.2 (0x2000000000000000) rguenther@scandium:/tmp> ./t One difference seems to be that Fedora builds with --disable-libunwind-exceptions. I will work on trying it with libunwind and then with binutils 2.19. Those seem to be the differences so far. I built GCC using libunwind and binutils 2.19.1 and there is the same problem. The registers are *not* being restored to the right values after the exception return. In the following assembly code you can clearly see that it expects the value in r37 to remain useful after the call to f. It doesn't. mov r37=r1 addl r38=112,r1;; ld8 r38=[r38] nop.i 0x0 nop.m 0x0 nop.i 0x0 br.call.sptk.many b0=4000000000000f80 <f(char const*)> mov r1=r37 nop.i 0x0 br.few 4000000000001210 <main+0x190>;; (Well, ok, it actually jumps to the exception catch block, but that block also does mov r1=r37 to get a PLT offset.) I erased every trace of experimental GCC versions and support libraries. Then I rebuilt GCC 4.4.2 (from SVN) using the system provided GCC 4.3. The problem went away. It still worries me some because it seems to indicate that the GCC bootstrap process was not pure and was somehow using a bad version of GCC or libraries. |