Date: Tue, 31 Mar 2009 17:34:45 GMT From: Michael Moller <moller.michael10@yahoo.com> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/133246: dlclose gives segfault when called in the fini function of another module Message-ID: <200903311734.n2VHYjv1017491@www.freebsd.org> Resent-Message-ID: <200903311740.n2VHe1Jq072219@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 133246 >Category: kern >Synopsis: dlclose gives segfault when called in the fini function of another module >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Mar 31 17:40:01 UTC 2009 >Closed-Date: >Last-Modified: >Originator: Michael Moller >Release: 7.1-RELEASE >Organization: Sybase, Inc. >Environment: FreeBSD xxxx 7.1-RELEASE FreeBSD 7.1-RELEASE #0: Thu Jan 1 14:37:25 UTC 2009 root@logan.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386 >Description: Dlopened ELF module A dlopens ELF module B and keeps a handle to it in a static C++ object. When the process exits, rtld_exit is called and the fini function for A is called. This function calls the object static destructor and it tries to dlclose the handle to B. This gives a segfault, and stack corruption. >How-To-Repeat: See attachment for a repro. The attachment contains 5 files, separated by === cut here ===. Separate the files, and run "build.sh" to create the shared objects and executable "prog" which will repro the problem. >Fix: Patch attached with submission follows: There are 5 files included below: build.sh ctest.h ctest1.c ctest2.c prog.c To compile, enter: ./build.sh To run the repro, enter: ./prog Result: Segmentation fault: 11 (core dumped) ==================== cut here ==================== #!/bin/bash rm *.o rm *.so rm prog g++ -g -Wall -fPIC -c ctest2.c g++ -g -shared -Wl,-soname,libctest2.so -o libctest2.so ctest2.o g++ -g -Wall -fPIC -c ctest1.c g++ -g -shared -Wl,-soname,libctest1.so -o libctest1.so ctest1.o g++ -g -Wall -I. prog.c -o prog ==================== cut here ==================== // ***************************************************** // ctest.h // ***************************************************** #ifndef CTEST_H #define CTEST_H #include <stdio.h> #ifdef __cplusplus extern "C" { #endif void LibInit_1(void); void LibFini_1(void); void LibInit_2(void); void LibFini_2(void); void ctest1(int *); void ctest2(int *); #ifdef __cplusplus } #endif class an_init_fini_execute_me_1 { public: an_init_fini_execute_me_1 () { LibInit_1(); } ~an_init_fini_execute_me_1 () { LibFini_1(); } }; class an_init_fini_execute_me_2 { public: an_init_fini_execute_me_2 () { LibInit_2(); } ~an_init_fini_execute_me_2 () { LibFini_2(); } }; #endif ==================== cut here ==================== // ***************************************************** // ctest1.c // ***************************************************** #include <stdlib.h> #include <dlfcn.h> #include "ctest.h" static int init_fini_call_count_1 = 0 ; static class an_init_fini_execute_me_1 execute_me_1; static void *lib_handle = NULL; void LibInit_1( void ) { init_fini_call_count_1++ ; if( init_fini_call_count_1 == 1 ) { fprintf( stderr, "LibInit/Fini - %s of %s\n", "Beg Init", "1" ); lib_handle = dlopen("libctest2.so", RTLD_LAZY); fprintf( stderr, "LibInit/Fini - %s of %s\n", "End Init", "1" ); } } void LibFini_1( void ) { init_fini_call_count_1-- ; if( init_fini_call_count_1 == 0 ) { fprintf( stderr, "LibInit/Fini - %s of %s\n", "Beg Fini", "1" ); if( lib_handle != NULL ) { dlclose(lib_handle); lib_handle = NULL; } fprintf( stderr, "LibInit/Fini - %s of %s\n", "End Fini", "1" ); } } void ctest1(int *i) { *i = 1; } ==================== cut here ==================== // ***************************************************** // ctest2.c // ***************************************************** #include "ctest.h" static int init_fini_call_count_2 = 0 ; static class an_init_fini_execute_me_2 execute_me_2; void LibInit_2( void ) { init_fini_call_count_2++ ; if( init_fini_call_count_2 == 1 ) { fprintf( stderr, "LibInit/Fini - %s of %s\n", "Beg Init", "2" ); fprintf( stderr, "LibInit/Fini - %s of %s\n", "End Init", "2" ); } } void LibFini_2( void ) { init_fini_call_count_2-- ; if( init_fini_call_count_2 == 0 ) { fprintf( stderr, "LibInit/Fini - %s of %s\n", "Beg Fini", "2" ); fprintf( stderr, "LibInit/Fini - %s of %s\n", "End Fini", "2" ); } } void ctest2(int *i) { *i = 2; } ==================== cut here ==================== // ***************************************************** // prog.c // ***************************************************** #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include "ctest.h" int main(int argc, char **argv) { void *lib_handle; lib_handle = dlopen("libctest1.so", RTLD_LAZY); if (!lib_handle) { fprintf(stderr, "%s\n", dlerror()); exit(1); } dlclose(lib_handle); return 0; } >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903311734.n2VHYjv1017491>