Below is a test-case and patch to support the cross-vendor C++ DSO Object Destruction API used by GCC 3.x and the Intel C/C++ compilers, defined at http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor Here is a quote from the web-page, describing the motivation/rationale behind this API: The C++ Standard requires that destructors be called for global objects when a program exits in the opposite order of construction. Most implementations have handled this by calling the C library atexit(3) routine to register the destructors. This is problematic because the 1999 C Standard only requires that the implementation support 32 register function, although most implementations support many more. More important, it does not deal at all with the ability in most implementations to remove DSOs (dynamic shared objects) from a running program image by calling dlclose(3) prior to program termination. The API specified below is intended to provide standard-conforming treatment during normal program exit, which includes executing atexit(3)-registered functions in the correct sequence relative to constructor-registered destructors, and reasonable treatment during early DSO unload (e.g. dlclose(3)). Fix: Currently, FreeBSD uses the crtstuff.c distributed with GCC (or the crtx*.o objects distributed with ICC), so the only thing missing is the implementation of __cxa_atexit() and __cxa_finalize(). This patch against src/lib/libc implements these functions and adjusts atexit(3) to use __cxa_atexit() as recommended at the web-page mentioned in the description. A few notes: 1. After applying this patch, the lang/icc port must be modified to not include its own (incorrect) implementations of __cxa_atexit() and __cxa_finalize(). In addition, devel/stlport-icc must be rebuilt with the new icc port to remove a local definitions of these 2 functions (since the icc port links with libcxa.a). In fact, all C++ libraries/programs compiled with icc will need to be (at the very least) relinked (for the same reason that devel/stlport-icc port must be rebuilt). 2. The system compiler does not current use __cxa_atexit(), so programs compiled with the system compiler will not benefit from this fix until the compiler defaults to using __cxa_atexit() (or the user explicitly uses -fuse-cxa-atexit). Once this patch is included in the base system, it should be possible to turn on use of __cxa_atexit() in the system compiler. Additionally, this change will preserve binary compatibility, since _fini() uses a weak reference to __cxa_finalize(). In fact, programs built with -fuse-cxa-atexit will continue to work on systems that do not have __cxa_finalize(), since _fini() works on a weak definition. The only difference is that global destructors will not be called *at all* in such cases. 3. It would probably make sense to bump __FreeBSD_version after applying this (since it is an ABI addition). This would allow (for example) the lang/icc port to detect whether or not its __cxa_atexit()/__cxa_finalize() workarounds are necessary. 4. This is my first patch submission to FreeBSD, so I may not have done somethings correctly. This patch can be used as-is, or with modifications to fit style(9) and other conventions. src-lib-libc.diff: ------------------------------------------------------------------------ How-To-Repeat: This test case reproduces the problem. Note: remove -fuse-cxa-atexit if testing without the included patch (otherwise the test will fail to link due to undefined symbols). Makefile: ------------------------------------------------------------------------ .if $(CXX) == "icpc" CXXFLAGS = -g # LFLAGS = -Qoption,ld,,-rpath,/usr/obj/usr/src/lib/libc \ # -L/usr/obj/usr/src/lib/libc -lc .else CXXFLAGS = -g -fuse-cxa-atexit # LFLAGS = -rpath /usr/obj/usr/src/lib/libc -L/usr/obj/usr/src/lib/libc -lc .endif all: app lib.so app: app.cpp $(CXX) $(CXXFLAGS) -g -o app app.cpp $(LFLAGS) lib.so: lib.cpp $(CXX) $(CXXFLAGS) -g -shared -o lib.so lib.cpp clean: rm -f app rm -f lib.so rm -f app.core ------------------------------------------------------------------------ app.cpp: ------------------------------------------------------------------------ #include <dlfcn.h> #include <stdio.h> #include <stdlib.h> struct APP { inline ~APP() { fprintf(stderr, "APP::~APP()\n"); } }; typedef void (*fn_t)(); void f() { fprintf(stderr, "app: f()\n"); static APP app; } void x() { printf("app: x()\n"); } void y() { printf("app: y()\n"); } int main(int, char **) { void *lib; fn_t gp; fprintf(stderr, "app: dlopen\n"); lib = dlopen("./lib.so", RTLD_LAZY); if (!lib) return 1; fprintf(stderr, "app: dlfunc\n"); gp = (fn_t) dlfunc(lib, "g"); if (!gp) return 1; fprintf(stderr, "app: calling lib, expect g()\n"); (*gp)(); f(); fprintf(stderr, "app: atexit(x)\n"); atexit(x); fprintf(stderr, "app: atexit(y)\n"); atexit(y); fprintf(stderr, "app: calling dlcose(), expect LIB::~LIB()\n"); dlclose(lib); fprintf(stderr, "app: done, expect y(), x(), and APP::~APP()\n"); return 0; } ------------------------------------------------------------------------ lib.cpp: ------------------------------------------------------------------------ #include <stdio.h> struct LIB { inline ~LIB() { fprintf(stderr, "LIB::~LIB()\n"); } }; extern "C" void g() { fprintf(stderr, "lib: g()\n"); static LIB lib;; } ------------------------------------------------------------------------
Responsible Changed From-To: freebsd-bugs->kan I will take care of this.
State Changed From-To: open->closed Commited modifies version of the patch, thanks!
http://www.freebsd.org/cgi/query-pr.cgi?pr=59552 Should not the new function(s) be declared in some header file? On FreeBSD-6.2 at the moment the only header, which declares __cxa_atexit(), is cxxabi.h (in /usr/include/c++/3.4/cxxabi.h), where the function is declared inside the __cxxabiv1 namespace... For a C-program finding the declaration is quite difficult too. A number of ports install shared libraries, which call atexit(). This leads to crashes, when the shared library is dlclose-ed. To correct them cleanly, port-maintainers need documentation (perhaps inside atexit(3)?). Currently `make -k cxa' shows nothing. -mi