Note: This is a beta release of Red Hat Bugzilla 5.0. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Also email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback here.
Bug 154641 - dlclose() generates SIGSEGV in destructors of shared libraries
Summary: dlclose() generates SIGSEGV in destructors of shared libraries
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Fedora
Classification: Fedora
Component: glibc
Version: 3
Hardware: i686
OS: Linux
medium
high
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact: Brian Brock
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2005-04-13 09:45 UTC by Evgeny Baskakov
Modified: 2007-11-30 22:11 UTC (History)
1 user (show)

Fixed In Version: 2.3.5-3
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2005-04-28 12:33:48 UTC


Attachments (Terms of Use)


Links
System ID Priority Status Summary Last Updated
Sourceware 1081 None None None Never

Description Evgeny Baskakov 2005-04-13 09:45:37 UTC
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 12:33:48 UTC
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.