This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Bug in dlopen() (or following) code in Cygwin1.dll v 1.5.19-4


Hi,

With the release of Cygwin-1.5.19-4, we have had
silent crashes of the Computer Algebra System SAGE at
startup. I have traced these to an invalid memory
access in pthread_key_create() which SHOULD be caught
and processed by the fault handler in
verifyable_object_isvalid(). However, the program
always dies in the return from this routine.

After some research, I believe that the crash occurs
when loading a dll via
 dlopen() and the cygwin dll intialization code calls
 dll:init() which calls
 run_ctors()  which calls (eventually) 
 pthread::once() which calls 
 init_routine() and init_routine() happens to be
fc_key_init().
 fc_key_init() sets up the pthread_key_t object, calls

 _sigfe_pthread_key_create() which jumps into 
 pthread_key_create() which calls 
 verifyably_object_isvalid() and we crash.

------------------------------------------------
I think that this is happening if one dlopen()s a dll
that is created with -lstdc++. 
If ANY dll which is created with -lstdc++ is LINKED
into the executable, everything gets initialized
properly and pthread_key_create() catches the SIGSEGV
and continues
normally.

Here is a simplified test to show what is going on:

------Simple script to put everything together:
#!/bin/sh
#NOTE: add -DHARDLINKTEST to ct.c compile to get
#      a non-crashing exe
#1st dll to be dlopen()ed only:
gcc -DDEBUG -gstabs+ -g3 -fno-strict-aliasing -Wall -c
CrashTest.cc -o CrashTest.o
g++ -shared  ./CrashTest.o -o CrashTest.dll -lstdc++

#2nd dll to linked directly by exe
gcc -DDEBUG -gstabs+ -g3 -fno-strict-aliasing -Wall -c
Crash2.cc -o Crash2.o
g++ -shared -Wl,--out-implib=libCrash2.dll.a
-Wl,--export-all-symbols -Wl,--enable-auto-import
-Wl,--whole-archive Crash2.o -Wl,--no-whole-archive -o
Crash2.dll -lstdc++

#3rd dll without -lstdc++
gcc -DDEBUG -gstabs+ -g3 -fno-strict-aliasing -Wall -c
OK.cc -o OK.o
g++ -shared  ./OK.o -o OK.dll -lstdc++

#exe test program
gcc -DDEBUG -gstabs+ -g3 ct.c -o ct.exe -L./ -lCrash2


------Code for exe (ct.c):
#include <windows.h>
#include <winbase.h>
#include <stdio.h>
extern void test();   /* test function in dlls */

void TestLinked(char* pszdll);
void TestLoad(char* pszdll);

int main(int argc, char** argv)
{
    int     ret;
/* NOTE: -DHARDLINKTEST in makefile if you want this 
         to run
 */
#ifdef HARDLINKTEST
    TestLinked("./Crash2.dll");
#endif
    TestLoad("./OK.dll");
    TestLoad("./CrashTest.dll");

    printf("THAT'S ALL FOLKS\n");
}


#ifdef HARDLINKTEST
void TestLinked(char* pszdll)
{
    printf("Testing build time linked %s\n", pszdll);
    _Z4testv(); /* call test() in dll - real code
would
                   have __declspec(dllexport), etc and
                   extern "C" syntactic sugar
                 */
}
#endif

typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);

void TestLoad(char* pszdll)
{
    printf("dlopening %s\n", pszdll);

    HANDLE  hDLL = (HANDLE)dlopen(pszdll);

    if(hDLL){
        printf("Getting proc address for test\n");

        LPFNDLLFUNC1    lpfnDllFunc1 =
(LPFNDLLFUNC1)GetProcAddress(hDLL,
                                                      
             "_Z4testv");

        if (!lpfnDllFunc1){
            // handle the error
            printf("Failed to get the function: %d\n",
GetLastError());
            FreeLibrary(hDLL);
            return;
        }
        else {
            // call the function
            printf("Calling test\n");
            UINT uReturnVal = lpfnDllFunc1(0,0);
            printf("Back from test\n");
        }
    }
    else
        printf("Error %d dlopening %s\n",
GetLastError(), pszdll);
}

------Code for 1st dll (CrashTest.cc):
#include <iostream>
using namespace std;

void test()
{
        cout << "\tCRASHTEST: This is a test." << endl
<< "Did you crash?" << endl;
}

------Code for 2nd dll (Crash2.cc):
#include <iostream>
#include "Crash2.h"
using namespace std;
void test()
{
        cout << "\tCRASH2: This is a test." << endl <<
"Did you crash?" << endl;
}
------Code for 3rd dll (OK.c):
#include <windows.h>
#include <stdio.h>
void test()
{
        printf("\tOK: This is a test.\n");
}

----------------------------------------------
NOTE: I have also tested all of this with 
      __declspec(dllexport) and
      __declspec(dllimport) 
      and everything works exactly the same

Thanks,
Gary





__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]