From owner-freebsd-hackers@FreeBSD.ORG Mon Dec 31 17:22:02 2007 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8365716A417 for ; Mon, 31 Dec 2007 17:22:02 +0000 (UTC) (envelope-from markus.hoenicka@mhoenicka.de) Received: from rrzmta1.rz.uni-regensburg.de (rrzmta1.rz.uni-regensburg.de [194.94.155.51]) by mx1.freebsd.org (Postfix) with ESMTP id 1DFF713C447 for ; Mon, 31 Dec 2007 17:22:01 +0000 (UTC) (envelope-from markus.hoenicka@mhoenicka.de) Received: from rrzmta1.rz.uni-regensburg.de (localhost [127.0.0.1]) by localhost (Postfix) with SMTP id 9774950A2A for ; Mon, 31 Dec 2007 18:02:07 +0100 (CET) Received: from yeti.mininet (rrzras1-10.rz.uni-regensburg.de [132.199.208.20]) by rrzmta1.rz.uni-regensburg.de (Postfix) with ESMTP id 3A2905091D for ; Mon, 31 Dec 2007 18:02:05 +0100 (CET) X-Mailer: emacs 21.3.1 (via feedmail 8 Q); VM 7.19 under Emacs 21.3.1 From: "Markus Hoenicka" MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <18297.6718.750894.937199@yeti.mininet> Date: Mon, 31 Dec 2007 17:35:10 +0100 To: freebsd-hackers@freebsd.org X-Mailman-Approved-At: Mon, 31 Dec 2007 17:50:17 +0000 Subject: dlopen(), atexit() crash on FreeBSD (testcase included) X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 31 Dec 2007 17:22:02 -0000 Hi, I've been redirected by Giorgos Keramidas to this list after reporting a problem on the freebsd-questions list. I'd greatly appreciate if you could have a look at the following problem. Apparently programs are doomed to segfault on FreeBSD if dlopen()ed modules install exit handlers via atexit(). Similar problem reports have cropped up before, see e.g. http://www.imagemagick.org/pipermail/magick-developers/2006-March/002523.html My system runs: FreeBSD yeti.mininet 6.1-RELEASE FreeBSD 6.1-RELEASE #1: Mon Aug 28 22:24:48 CEST 2006 markus@yeti.mininet:/usr/src/sys/i386/compile/YETI i386 I'm one of the developers of libdbi, a database abstraction layer for C, see http://libdbi.sourceforge.net. libdbi is a library for programs which are supposed to be able to access different database engines with a unified API. libdbi essentially maps generic API calls to the specific database client library calls of a particular database engine. To do this, libdbi loads available database drivers at runtime via dlopen() calls. Each of these drivers is linked against one database client library. E.g. the Firebird driver is linked against libfbclient.so. When libdbi is properly shut down, it unloads all loaded drivers by calling dlclose() on each of them. This design works well on all supported platforms and with all supported database engines, with one exception: the Firebird driver on FreeBSD invariably causes a segfault when the application linked against libdbi exits: #0 0x28514fe4 in ?? () #1 0x281507c3 in __cxa_finalize () from /lib/libc.so.6 #2 0x281503fe in exit () from /lib/libc.so.6 #3 0x0804a40f in main (argc=1, argv=0xbfbfe754) at test_dbi.c:419 The reason appears to be that the Firebird client libraries install exit handlers via atexit(). Remember that due to libdbi's design to load all available drivers whether or not they are used later, libdbi will cause a crash even if no Firebird database is accessed - it is sufficient that the driver has been loaded. As per Giorgos' suggestion it is simple to circumvent this segfault by avoiding the call to dlclose() before exiting, but I wonder whether there is a more robust solution for this problem. The attached minimal testcase is sufficient to illustrate the problem. atexitmod.c defines a module which is loaded by datest.c Make sure to fix the hardcoded path in datest.c before building the app. To build the test program and watch it crash, do the following: gcc -shared -o atexitmod.so atexitmod.c gcc -o datest datest.c ./datest Commenting out either the atexit() call in atexitmod.c or the dlclose() call in datest.c prevent the segfault. If you find some solution, please cc me as I'm not subscribed to freebsd-hackers. regards, Markus --8< datest.c --- #include #include #include int main (void) { void *dlhandle; void (*hellodriver) (void); dlhandle = dlopen("/home/markus/prog/datest/atexitmod.so", RTLD_LAZY); if (!dlhandle) { printf("cannot open module\n"); exit(1); } hellodriver = dlsym(dlhandle, "hellodriver"); if (!hellodriver) { printf("cannot locate function\n"); exit(1); } hellodriver(); dlclose(dlhandle); exit(0); } --8<------------- --8< atexitmod.c --- #include #include void exithandler(void); void hellodriver(void) { printf("hello driver\n"); fflush(stdout); atexit(exithandler); } void exithandler(void) { printf("now exiting\n"); fflush(stdout); } --8<------------- -- Markus Hoenicka markus.hoenicka@cats.de (Spam-protected email: replace the quadrupeds with "mhoenicka") http://www.mhoenicka.de