Bug 154641 - dlclose() generates SIGSEGV in destructors of shared libraries
dlclose() generates SIGSEGV in destructors of shared libraries
Status: CLOSED RAWHIDE
Product: Fedora
Classification: Fedora
Component: glibc (Show other bugs)
3
i686 Linux
medium Severity high
: ---
: ---
Assigned To: Jakub Jelinek
Brian Brock
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2005-04-13 05:45 EDT by Evgeny Baskakov
Modified: 2007-11-30 17:11 EST (History)
1 user (show)

See Also:
Fixed In Version: 2.3.5-3
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2005-04-28 08:33:48 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)


External Trackers
Tracker ID Priority Status Summary Last Updated
Sourceware 1081 None None None Never

  None (edit)
Description Evgeny Baskakov 2005-04-13 05:45:37 EDT
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2

Description of problem:
The attached program causes SIGSEGV on Fedora Core 3 with latest updates. 

The updates were appiled on 4.12.2005 using the "yum update" command.
Most probably the buggy code is in glibc-2.3.5-0.fc3.1.src.rpm.

The program consists of four files:

----- main.c --------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

static void *maindll = NULL;
static void (*entry)() = NULL;

static void check_non_null(void *v, char *msg) {
   if(!v) {
      printf("ERROR: %s\n", msg);
      abort();
   }
}

int main() {
   printf("Program started\n");
   maindll = dlopen("./libmain.so", RTLD_LAZY);
   check_non_null(maindll, dlerror());
   entry = dlsym(maindll, "Entry");
   check_non_null(entry, dlerror());
   printf("Entering the main entry\n");
   entry();
   dlclose(maindll);
   printf("Program ended\n");
   return 0;
}
---------------------------------------------------

----- maindll.c -----------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

static void *child = NULL;

static void check_non_null(void *v, char *msg) {
   if(!v) {
      printf("ERROR: %s\n", msg);
      abort();
   }
}

void __attribute__ ((constructor)) init0() {
   printf("constructor of libmain.so\n");
}


void __attribute__ ((destructor)) fini0() {
   printf("destructor of libmain.so\n");
}


void Entry() {
   printf("[main] Entry of libmain.so started\n");
   child = dlopen("./libchild1.so", RTLD_LAZY);
   check_non_null(child, dlerror());
   printf("[main] Child library loaded\n");
   dlclose(child);
   printf("[main] Child library closed\n");
   printf("[main] Main libmain.so ended\n");
}
---------------------------------------------------

----- child1.c ------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

static void *child = NULL;

static void check_non_null(void *v, char *msg) {
   if(!v) {
      printf("ERROR: %s\n", msg);
      abort();
   }
}

void __attribute__ ((constructor)) init1() {
   printf("constructor of child 1 started\n");
   child = dlopen("./libchild2.so", RTLD_LAZY);
   check_non_null(child, dlerror());
   printf("constructor of child 1 ended\n");
}


void __attribute__ ((destructor)) fini1() {
   printf("destructor of child 1 started\n");
   check_non_null(child, "CHILD IS NULL");
   dlclose(child);
   printf("destructor of child 1 ended\n");
}
---------------------------------------------------

----- child2.c ------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

static void *child = NULL;

static void check_non_null(void *v, char *msg) {
   if(!v) {
      printf("ERROR: %s\n", msg);
      abort();
   }
}

void __attribute__ ((constructor)) init2() {
   printf("constructor of child 2 started\n");
   child = dlopen("./libmain.so", RTLD_LAZY);
   check_non_null(child, dlerror());
   printf("constructor of child 2 ended\n");
}


void __attribute__ ((destructor)) fini2() {
   printf("destructor of child 2 started\n");
   check_non_null(child, "CHILD IS NULL");
   dlclose(child);
   printf("destructor of child 2 ended\n");
}
---------------------------------------------------


Version-Release number of selected component (if applicable):
2.3.5-0.fc3.1

How reproducible:
Always

Steps to Reproduce:
To watch the program's behavior,

0) Save four attached files (main.c, maindll.c, child1.c, child2.c)

1) Compile them:

gcc -g -shared child1.c -o libchild1.so
gcc -g -shared child2.c -o libchild2.so
gcc -g -shared maindll.c -o libmain.so
gcc -g main.c -o main -ldl

3) Run ./main


Actual Results:  The typical output is:

$ ./main
Program started
contructor of libmain.so
Entering the main entry
[main] Entry of libmain.so started
contructor of child 1 started
contructor of child 2 started
contructor of child 2 ended
contructor of child 1 ended
[main] Child library loaded
destructor of child 1 started
destructor of child 2 started
Segmentation fault


Expected Results:  This program works fine on RedHat 8, SuSE 8.0, and Fedora Core 3 without any updates applied. The right output is:

$ ./main
Program started
constructor of libmain.so
Entering the main entry
[main] Entry of libmain.so started
constructor of child 1 started
constructor of child 2 started
constructor of child 2 ended
constructor of child 1 ended
[main] Child library loaded
destructor of child 1 started
destructor of child 2 started
destructor of child 2 ended
destructor of child 1 ended
[main] Child library closed
[main] Main libmain.so ended
destructor of libmain.so
Program ended


Additional info:
Comment 1 Jakub Jelinek 2005-04-28 08:33:48 EDT
Should be fixed in CVS:
http://sources.redhat.com/ml/libc-hacker/2005-04/msg00014.html
and in the current rawhide build.

Note You need to log in before you can comment on or make changes to this bug.