Pulse-Eight / libcec

USB CEC Adapter communication Library http://libcec.pulse-eight.com/
Other
714 stars 287 forks source link

Segfault on second call to LibCecInitialise in Linux #555

Open kmdewaal opened 3 years ago

kmdewaal commented 3 years ago

The MythTV application segfaults in dlsym called by LibCecInitialize in the following calling sequence:

LibCecInitialise
UnloadLibCEC
LibCecInitialise
....segfault....

I have traced this back to a bug in /usr/include/libcec/cecloader.h. This file has a global variable g_libCEC which is used to store the return value of the dlopen call for libcec.so. This handle is used in LibCecInitialise to lookup the value of symbol CECInitialise. The file cecloader.h contains both a Windows and a Linux version of LibCecInitialise and UnloadLibCec. The Windows version of UnloadLibCec sets g_libCEC to NULL but the Linux version does NOT. On Linux, the second time LibCecInitialise is called the now invalid g_libCEC handle is used for the symbol lookup and this is what causes dlsym to crash.

The solution is to set g_libCEC to NULL after dlclose like it is done in the Windows version of the code.

For reference, this is the WIndows version as found in /usr/include/libcec/cecloader.h of Fedora 33:

 69 void UnloadLibCec(CEC::ICECAdapter *device)
 70 {
 71   typedef void (__cdecl*_DestroyLibCec)(void * device);
 72   _DestroyLibCec DestroyLibCec;
 73   DestroyLibCec = (_DestroyLibCec) (GetProcAddress(g_libCEC, "CECDestroy"));
 74   if (DestroyLibCec)
 75     DestroyLibCec(device);
 76 
 77   FreeLibrary(g_libCEC);
 78   g_libCEC = NULL;
 79 }

This is the Linux code from the same file:

148 void UnloadLibCec(CEC::ICECAdapter *device)
149 {
150   typedef void* _DestroyLibCec(CEC::ICECAdapter *);
151   _DestroyLibCec *DestroyLibCec = (_DestroyLibCec*) dlsym(g_libCEC, "CECDestroy");
152   if (DestroyLibCec)
153     DestroyLibCec(device);
154 
155   dlclose(g_libCEC);
156 }