On 2012/5/21 1:24, Konstantin Belousov wrote:
On Sun, May 20, 2012 at 06:42:35PM +0200, Alberto Villa wrote:
On Sun, May 20, 2012 at 8:03 AM, David Xu<listlog2...@gmail.com>  wrote:
qdbus segfaults on my machine too, I tracked it down, and found the problem
is in QT,
it deleted current_thread_data_key,  but it still uses it in some cxa hooks,
  I  applied the
following patch,  and it works fine.
Thanks for the analysis David!

I think the bug depends on linking order in QT library ? if the
qthread_unix.cpp is linked
as lastest module, the key will be deleted after all cxa hooks run, then it
will be fine,
otherwise, it would crash.
Is this really possible?
No, I do not think it is possible.

The only possibility for something weird happen is for atexit/__cxa_atexit
functions to be registered from another atexit function, and then we
indeed could call the newly registered function too late.

I wonder if the following hack makes any change in the observed behaviour.

diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
index 511172a..bab850c 100644
--- a/lib/libc/stdlib/atexit.c
+++ b/lib/libc/stdlib/atexit.c
@@ -72,6 +72,7 @@ struct atexit {
  };

  static struct atexit *__atexit;               /* points to head of LIFO stack 
*/
+static int atexit_gen;

  /*
   * Register the function described by 'fptr' to be called at application
@@ -107,6 +108,7 @@ atexit_register(struct atexit_fn *fptr)
                __atexit = p;
        }
        p->fns[p->ind++] = *fptr;
+       atexit_gen++;
        _MUTEX_UNLOCK(&atexit_mutex);
        return 0;
  }
@@ -162,7 +164,7 @@ __cxa_finalize(void *dso)
        struct dl_phdr_info phdr_info;
        struct atexit *p;
        struct atexit_fn fn;
-       int n, has_phdr;
+       int atexit_gen_prev, n, has_phdr;

        if (dso != NULL)
                has_phdr = _rtld_addr_phdr(dso,&phdr_info);
@@ -170,6 +172,8 @@ __cxa_finalize(void *dso)
                has_phdr = 0;

        _MUTEX_LOCK(&atexit_mutex);
+retry:
+       atexit_gen_prev = atexit_gen;
        for (p = __atexit; p; p = p->next) {
                for (n = p->ind; --n>= 0;) {
                        if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
@@ -196,6 +200,8 @@ __cxa_finalize(void *dso)
                        _MUTEX_LOCK(&atexit_mutex);
                }
        }
+       if (atexit_gen_prev != atexit_gen)
+               goto retry;
        _MUTEX_UNLOCK(&atexit_mutex);
        if (dso == NULL)
                _MUTEX_DESTROY(&atexit_mutex);
I have tried your patch, it does not fix the problem. As I said, it is a bug in QT, the bug is pthread key current_thread_data_key is deleted by a global C++ object too early, other C++ global objects still need this pthread key. The following procedure
shows how I found the problem:

davidxu@xyf:~%gdb qdbus
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...(no debugging symbols found)...
(gdb) break __cxa_finalize
Function "__cxa_finalize" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (__cxa_finalize) pending.
(gdb) run
Starting program: /usr/local/bin/qdbus
(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...[New LWP 100077] (no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)...Breakpoint 2 at 0x2864ac26
Pending breakpoint "__cxa_finalize" resolved
(no debugging symbols found)...[New Thread 29007300 (LWP 100077/qdbus)]
(no debugging symbols found)...:1.0
 org.gnome.SessionManager
:1.11
:1.111
:1.12
:1.13
 org.gtk.vfs.Daemon
:1.143
:1.15
 org.pulseaudio.Server
:1.17
 org.gnome.Panel
:1.18
:1.19
:1.20
 org.gtk.Private.HalVolumeMonitor
:1.21
 org.gtk.Private.GPhoto2VolumeMonitor
:1.22
:1.24
 org.gnome.ScreenSaver
:1.25
:1.27
:1.28
:1.29
:1.30
:1.31
 org.gnome.panel.applet.WnckletFactory
:1.32
:1.33
:1.34
:1.35
 org.gnome.panel.applet.CPUFreqAppletFactory
:1.36
 org.gnome.panel.applet.NotificationAreaAppletFactory
:1.37
 org.gnome.panel.applet.MultiLoadAppletFactory
:1.38
:1.39
:1.4
 org.gnome.GConf
:1.41
 org.gnome.panel.applet.ClockAppletFactory
:1.49
:1.5
 org.gnome.SettingsDaemon
:1.50
:1.53
:1.64
:1.7
 org.freedesktop.secrets
 org.gnome.keyring
:1.75
 org.gtk.vfs.Metadata
:1.76
 org.gnome.Terminal.Display_0_0
:1.77
org.freedesktop.DBus
[Switching to Thread 29007300 (LWP 100077/qdbus)]

Breakpoint 2, 0x2864ac26 in __cxa_finalize () from /lib/libc.so.7
(gdb) print current_thread_data_key
$1 = 0
(gdb) thread tsd
Key 0, destructor 0x281d77f0 <_Z27destroy_current_thread_dataPv>
Key 1, destructor 0x28732dc0 <g_thread_create_full>
Key 2, destructor 0x28726a00 <g_slice_get_config>
Key 3, destructor 0x0 <???>


Here you can find that the function destroy_current_thread_data() is registered.


(gdb) bt
#0  0x2864ac26 in __cxa_finalize () from /lib/libc.so.7
#1  0x285efe1a in exit () from /lib/libc.so.7
#2  0x08051db5 in main ()
(gdb) break QThreadData::current()
Breakpoint 3 at 0x281d7856
(gdb) info breakpoints
Num Type           Disp Enb Address    What
2   breakpoint     keep y   0x2864ac26 <__cxa_finalize+6>
    breakpoint already hit 1 time
3   breakpoint     keep y   0x281d7856 <QThreadData::current()+6>
(gdb) delete 2
(gdb) cont
Continuing.

Breakpoint 3, 0x281d7856 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4
(gdb) bt
#0 0x281d7856 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4 #1 0x281d4747 in QThread::currentThread () from /usr/local/lib/qt4/libQtCore.so.4 #2 0x28097248 in QDBusConnectionPrivate::deleteYourself () from /usr/local/lib/qt4/libQtDBus.so.4 #3 0x2808f2ea in QDBusConnection::~QDBusConnection () from /usr/local/lib/qt4/libQtDBus.so.4
#4  0x2864ad8f in __cxa_finalize () from /lib/libc.so.7
#5  0x285efe1a in exit () from /lib/libc.so.7
#6  0x08051db5 in main ()
(gdb) thread tsd
Key 1, destructor 0x0 <???>
Key 2, destructor 0x0 <???>
Key 3, destructor 0x0 <???>

Here you can see the destroy_current_thread_data() was executed, and unregistered.
the key current_thread_key_data which is index 0 is deleted.


(gdb) cont
Continuing.

Breakpoint 3, 0x281d7856 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4
(gdb) bt
#0 0x281d7856 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4
#1  0x282f58e3 in QObject::QObject () from /usr/local/lib/qt4/libQtCore.so.4
#2  0x281d4710 in QThread::QThread () from /usr/local/lib/qt4/libQtCore.so.4
#3 0x281d5a9e in QAdoptedThread::QAdoptedThread () from /usr/local/lib/qt4/libQtCore.so.4 #4 0x281d7934 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4 #5 0x281d4747 in QThread::currentThread () from /usr/local/lib/qt4/libQtCore.so.4 #6 0x28097248 in QDBusConnectionPrivate::deleteYourself () from /usr/local/lib/qt4/libQtDBus.so.4 #7 0x2808f2ea in QDBusConnection::~QDBusConnection () from /usr/local/lib/qt4/libQtDBus.so.4
#8  0x2864ad8f in __cxa_finalize () from /lib/libc.so.7
#9  0x285efe1a in exit () from /lib/libc.so.7
#10 0x08051db5 in main ()

now the stupid code starts to create a new thread...

(gdb) cont
Continuing.

Breakpoint 3, 0x281d7856 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4
(gdb) bt
#0 0x281d7856 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4
#1  0x282f58e3 in QObject::QObject () from /usr/local/lib/qt4/libQtCore.so.4
#2  0x281d4710 in QThread::QThread () from /usr/local/lib/qt4/libQtCore.so.4
#3 0x281d5a9e in QAdoptedThread::QAdoptedThread () from /usr/local/lib/qt4/libQtCore.so.4 #4 0x281d7934 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4
#5  0x282f58e3 in QObject::QObject () from /usr/local/lib/qt4/libQtCore.so.4
#6  0x281d4710 in QThread::QThread () from /usr/local/lib/qt4/libQtCore.so.4
#7 0x281d5a9e in QAdoptedThread::QAdoptedThread () from /usr/local/lib/qt4/libQtCore.so.4 #8 0x281d7934 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4 #9 0x281d4747 in QThread::currentThread () from /usr/local/lib/qt4/libQtCore.so.4 #10 0x28097248 in QDBusConnectionPrivate::deleteYourself () from /usr/local/lib/qt4/libQtDBus.so.4 #11 0x2808f2ea in QDBusConnection::~QDBusConnection () from /usr/local/lib/qt4/libQtDBus.so.4
#12 0x2864ad8f in __cxa_finalize () from /lib/libc.so.7
#13 0x285efe1a in exit () from /lib/libc.so.7
#14 0x08051db5 in main ()
(gdb)
#0 0x281d7856 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4
#1  0x282f58e3 in QObject::QObject () from /usr/local/lib/qt4/libQtCore.so.4
#2  0x281d4710 in QThread::QThread () from /usr/local/lib/qt4/libQtCore.so.4
#3 0x281d5a9e in QAdoptedThread::QAdoptedThread () from /usr/local/lib/qt4/libQtCore.so.4 #4 0x281d7934 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4
#5  0x282f58e3 in QObject::QObject () from /usr/local/lib/qt4/libQtCore.so.4
#6  0x281d4710 in QThread::QThread () from /usr/local/lib/qt4/libQtCore.so.4
#7 0x281d5a9e in QAdoptedThread::QAdoptedThread () from /usr/local/lib/qt4/libQtCore.so.4 #8 0x281d7934 in QThreadData::current () from /usr/local/lib/qt4/libQtCore.so.4 #9 0x281d4747 in QThread::currentThread () from /usr/local/lib/qt4/libQtCore.so.4 #10 0x28097248 in QDBusConnectionPrivate::deleteYourself () from /usr/local/lib/qt4/libQtDBus.so.4 #11 0x2808f2ea in QDBusConnection::~QDBusConnection () from /usr/local/lib/qt4/libQtDBus.so.4
#12 0x2864ad8f in __cxa_finalize () from /lib/libc.so.7
#13 0x285efe1a in exit () from /lib/libc.so.7
#14 0x08051db5 in main ()
(gdb)

dead-loop in QT library until the stack overflow.

As I said, it depends on ordering the global objects are destructed, if the object which deleting the current_thread_data_key is destructed lastly, the problem wont happen, but now it is destructed too early. I believe there is no specification said that which C++ object should be destructed first if they are in different compiled module and then are linked together to generated
a shared object, .so file.




_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to