[Issue 14824] A stale function might get called when unloading shared libraries on FBSD

via Digitalmars-d-bugs digitalmars-d-bugs at puremagic.com
Thu Sep 10 07:13:05 PDT 2015


https://issues.dlang.org/show_bug.cgi?id=14824

ponce <aliloko at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |aliloko at gmail.com

--- Comment #1 from ponce <aliloko at gmail.com> ---
I'm hitting a very similar bug on OS X 10.10.4, let me explain.



== Setup ==

Here the host program source.

What it does is:
 - for each dynlib in command line:
    - load dynlibs
    - call the VSTPluginMain function if it exist, 
    - unload it

--------------------- ldvst.cpp --------------------

#include <dlfcn.h>
#include <cstdio>
#include <cstring>
#include <vector>

typedef __cdecl void* (*VSTPluginMain_t)(void*);

int main(int argc, char**argv)
{
    std::vector<char*> dllPaths;
    if (argc < 2)
    {
        printf("usage: ldvst [-lazy] <thing.vst>\n");
        return 1;
    }

    bool lazy = false;

    for (int i = 1; i < argc; ++i)
    {
        char* arg = argv[i];
        if (strcmp(arg, "-lazy") == 0)
            lazy = true;
        else if (strcmp(arg, "-now") == 0)
            lazy = false;
        else
            dllPaths.push_back(arg);
    }

    for (int i = 0; i < dllPaths.size(); ++i)
    {
        char* dllPath = dllPaths[i];

        printf("dlopen(%s)\n", dllPath);
        void* handle = dlopen(dllPath, lazy ? RTLD_LAZY : RTLD_NOW);
        if (handle == NULL)
        {
            printf("error: dlopen of %s failed\n", dllPath);
            return 2;
        }

        VSTPluginMain_t VSTPluginMain = (VSTPluginMain_t) dlsym(handle,
"VSTPluginMain");
        printf("dlsym returned %p\n", (void*)VSTPluginMain);

        if (VSTPluginMain != NULL)
        {
            void* result = VSTPluginMain(NULL);
            printf("VSTPluginMain returned %p\n", result);
        }

        printf("dlclose(%s)\n\n", dllPath);
        dlclose(handle);
    }
    return 0;
}
-----------------------------------------------------

The host is compiled with:

$ clang++ ldvst.cpp -o ldvst-cpp


Here the whole dynlib source:

----------------- distort.d -------------------------

extern(C) void* VSTPluginMain(void* hostCallback)
{
    import core.runtime;
    Runtime.initialize();
    import std.stdio;
    import core.stdc.stdio;
    printf("Hello !\n");
    Runtime.terminate();
    return null;
}

------------------------------------------------------

This dynlib can be built with ldc:

$ ldc2 -shared -oflibdistort.so -g -w -I. distort.d -relocation-model=pic

or with dmd

$ dmd -c -ofdistort.o -debug -g -w -version=Have_distort -I. distort.d -fPIC
$ dmd -oflibdistort.so distort.o -shared -g


For the purpose of demonstration you need another C dynlib, for example 
/System/Library/Frameworks/Cocoa.framework/Cocoa on OS X.


Now the bug triggers when calling:


== How to reproduce ==

$ ldvst-cpp libdistort.so 
   => works

$ ldvst-cpp libdistort.so libdistort.so 
   => works

$ ldvst-cpp /System/Library/Frameworks/Cocoa.framework/Cocoa libdistort.so 
   => works

$ ldvst-cpp libdistort.so /System/Library/Frameworks/Cocoa.framework/Cocoa
   => FAIL, and that's precisely the case that happen in production :(

$ ldvst-cpp /System/Library/Frameworks/Cocoa.framework/Cocoa libdistort.so
/System/Library/Frameworks/Cocoa.framework/Cocoa
   => works

In other words, if the host program loads a D dynlib first, then a C dynlib,
then the second dlopen fail.

This has eluded me for a complete month.

--


More information about the Digitalmars-d-bugs mailing list