What happens to the thread spawned by a shared library, upon dlclose - multithreading

This is the scenario:
I have an application (main.exe) which dynamically loads a library libA.so using dlopen(). libA.so has dependency on another library libB.so.
Now libB.so has a constructor that spawns a thread (in detached state) and blocks on reading from a named pipe.
What happens to the thread , when libA.so is unloaded using dlclose() - (i assume this will unload libB.so as well)?.
I get segmentation fault in the thread after the dlclose(libA.so).
Pseudo code:
main.c (main.exe):
handle = dlopen(libA.so)
// function calls
dlclose(handle)
libA.so depends on libB.so
b.c (libB.so):
__attribute_constructor__void start() {
pthread_create(ThreadFunction)
void ThreadFunction() {
while(1) {
fd = open("path_to_pipe", READONLY)
read(fd, buffer, size)
//Process the content
}

Unloading a shared library which is still in use is Undefined Behaviour. Calling dlclose() on a handle is a declaration that neither the functions nor the data objects provided through that handle are still required.
There is no way for dlclose() to verify this fact. If you still have a pointer to a function or data object in the loadable module, those pointers become invalid and may not be used. If there is a pointer into a loaded function on the call stack of any thread -- which will be the case if the thread is waiting on a file descriptor -- then that thread may not return into that call frame. (Longjmp to a prior frame might work, if the stack can be unwound without reference to the unloaded module. That will likely work in C, but throwing a C++ exception to escape from an unloaded function is likely to fail.

Congratulations - you've rediscovered that a non-nop dlclose implementation is fundamentally unsafe. The C language makes no provision for code or pseudo-static-storage data whose lifetime is anything other than the whole lifetime of the program, and in general library code cannot be safely removed since there are all sorts of ways that references to it may have leaked and still be reachable. You've actually found an exceptionally good example; common implementations attempt to catch and "fix" leaks via atexit and such by running the handlers at dlclose time, but there doesn't seem to be any way to catch and fix a thread left running.
As a workaround, there is a special ELF flag you can set by passing -Wl,-z,nodelete when linking the shared library libB.so (or libA.so if that's more convenient, e.g. if you don't have control over how libB.so is linked) that will prevent it from being unloaded by dlclose. Unfortunately, this design is backwards. Unloading is fundamentally unsafe unless a library is specifically written to be safe against unloading, so the default should be "nodelete" with an explicit option required to make unloading possible. Unfortunately there's little chance this will ever be fixed.
Another way to prevent unloading is have a constructor call dlopen on itself to leak a reference, so that the reference count will always be positive and dlclose will do nothing.

Related

Analyzing a crash from a rust-generated C library

I needed to call Rust code from my Go code. Then I used C as my interface. I did this:
I've created a Rust library that takes a CStr as a parameter, and returns a new processed string back as CStr.
This code is statically compiled to a static C library my_lib.a.
Then, this library is statically linked with my Go code, that then calls the library API using CGo (Go's representation to C String, just like Rusts's Cstr).
The final Go binary is sitting inside a docker container in my kubernetes. Now, my problem is that is some cases where the library's API is called, my pod (container) is crashing. Due to the nature of using CStr and his friends, I must use unsafe scopes in some places, and I highly suspect a segfault that is caused by one of the ptrs used in my code, but I have no way of communicating the error back to the Go code that could be then printed OR alternatively get some sort of a core dump from Rust/C so I can point out the problematic code. The pod just crashes with no info whatsoever, at least to my knowledge..
So my question is, how can I:
Recover from panic/crashes that happen inside an unsafe code? or maybe wrap it with a recoverable safe scope?
Override the SIG handlers so I can at least "catch" the errors and not crash? So I can debug it.
Perhaps communicate a signal interruption that was caused in my c-lib that was generated off Rust back to the caller?
I realize that once Rust is compiled to a c-library, it is a matter of C, but I have no idea how to tackle this one.
Thanks!
I've created a Rust library that takes a CStr as a parameter, and returns a new processed string back as CStr.
Neither operation seems OK:
the CStr documentation specifically notes that CStr is not repr(C)
CStr is a borrowed string, a "new processed string" would have to be owned (so a CString, which also isn't repr(C)).
Due to the nature of using CStr and his friends, I must use unsafe scopes in some places, and I highly suspect a segfault that is caused by one of the ptrs used in my code, but I have no way of communicating the error back to the Go code that could be then printed OR alternatively get some sort of a core dump from Rust/C so I can point out the problematic code. [...] Recover from panic/crashes that happen inside an unsafe code? or maybe wrap it with a recoverable safe scope?
If you're segfaulting there's no panic or crash which Rust can catch or manipulate in any way. A segfault means the OS itself makes your program go away. However you should have a core dump the usual way, this might be a configuration issue with your container thing.
Override the SIG handlers so I can at least "catch" the errors and not crash? So I can debug it.
You can certainly try to handle SIGSEGV, but after a SIGSEGV I'd expect the program state to be completely hosed, this is not an innocuous signal.

Hook function to shared library unloading

I want to add hook function, which will be called when shared library is unloaded. Library is linked on complitaion. Is it possible to do such thing? Maybe gcc has flag for it?
I saw similar solution for loading library on runtime, but it doesn't meet my expectations.
For Linux systems, the dlopen()/dlclose() man page explains how to add such a function to your library:
Initialization and finalization functions
Shared objects may export functions using the __attribute__((constructor)) and
__attribute__((destructor)) function attributes. Constructor functions are executed before dlopen() returns, and destructor
functions are executed before dlclose() returns. A shared object may
export multiple constructors and destructors, and priorities can be
associated with each function to determine the
order in which they are executed. See the gcc info pages (under "Function attributes") for further information.
An older method of (partially) achieving the same result is via
the use of two special symbols recognized by the linker: _init and
_fini. If a dynamically loaded shared object exports a routine named _init(), then that code is executed after loading a shared
object, before dlopen() returns. If the shared object exports a
routine named _fini(), then that routine is called just before the
object is unloaded. In this case, one must avoid linking against the
system startup files, which contain default versions of these files;
this can be done by using the gcc(1) -nostartfiles command-line
option.
Use of _init and _fini is now deprecated in favor of the
aforementioned constructors and destructors, which among other
advantages, permit multiple initialization and finalization
functions to be
defined.
Solaris and GNU/Linux support the LD_AUDIT interface in their dynamic linkers. You need to load an auditor module which implements the la_objclose callback function:
Runtime Linker Auditing Interface
The implementation can be as simple as this:
unsigned int
la_objclose (uintptr_t *cookie)
{
printf ("objclose\n");
return 0;
}
In order to determine which object is being closed, you also need to implement la_objsearch (and possibly la_objopen), to establish a cookie value which somehow refers to the information you need at close time (you could store a pointer to a heap-allocated struct in the cookie, for example).

Is it safe to call dlclose(NULL)?

I experience a crash when I pass a null pointer to dlclose.
Should I check for null before calling dlclose?
POSIX tells nothing about this:
http://pubs.opengroup.org/onlinepubs/7908799/xsh/dlclose.html
Is it undefined behaviour or a bug in dlclose implementation?
This is tricky. POSIX states that
if handle does not refer to an open object, dlclose() returns a non-zero value
from which you could infer that it should detect, for an arbitrary pointer, whether that pointer refers to an open object. The Linux/Glibc version apparently does no such check, so you'll want to check for NULL yourself.
[Aside, the Linux manpage isn't very helpful either. It's quite implicit about libdl functions' behavior, deferring to POSIX without very clearly claiming conformance.]
It also says nothing about being accepting a NULL and not crashing. We can assume from your test that it doesn't do an explicit NULL check, and it does need to use the pointer somehow to perform the closing action … so there you have it.
Following the malloc/free convention (1), it is a bug. If it follows the fopen/fclose convention (2) it is not. So if there is a bug, it is in the standard because it lacks convention for dealing with zombies.
Convention (1) works well with C++11 move semantics
Convention (2) leaves more responsibility to the caller. In particular, a dtor must explicitly check for null if a move operation has been done.
I think this is something that should be revised for an upcoming POSIX revision in order to avoid confusion.
Update
I found from this answer https://stackoverflow.com/a/6277781/877329, and then reading man pthread_join that you can call pthread_join with an invalid tid, supporting the malloc/free convension. Another issue I have found with the dynamic loader interface is that it does not use the standard error handling system, but has its own dlerrorfunction.

Multithreading (pthreads)

I'm working on a project where I need to make a program run on multiple threads. However, I'm running into a bit of an issue.
In my program, I have an accessory function called 'func_call'.
If I use this in my code:
func_call((void*) &my_pixels);
The program runs fine.
However, if I try to create a thread, and then run the function on that, the program runs into a segmentation fault.
pthread_t thread;
pthread_create (&thread, NULL, (void*)&func_call, (void*) &my_pixels);
I've included pthread.h in my program. Any ideas what might be wrong?
You are not handling data in a thread safe manner:
the thread copies data from the thread argument, which is a pointer to the main thread's my_pixels variable; the main thread may exit, making my_pixles invalid.
the thread uses scene, main thread calls free_scene() on it, which I imagine makes it invalid
the thread calls printf(), the main thread closes stdout (kind of unusual itself)
the thread updates the picture array, the main thread accesses picture to output data from it
It looks like you should just wait for the thread to finish its work after creating it - call pthread_join() to do that.
For a single thread, that would seem to be pointless (you've just turned a multi-threaded program into a single threaded program). But on the basis of code that's commented out, it looks like you're planning to start up several threads that work on chunks of the data. So, when you get to the point of trying that again, make sure you join all the threads you start. As long as the threads don't modify the same data, it'll work. Note that you'll need to use separate my_pixels instances for each thread (make an array of them, just like you did with pthreads), or some threads will likely get parameters that are intended for a different thread.
Without knowing what func_call does, it is difficult to give you an answer. Nevertheless, here are few possibilities
Does func_call use some sort of a global state - check if that is initialized properly from within the thread. The order of execution of threads is not always the same for every execution
Not knowing your operating system (AIX /Linux/Solaris etc) it is difficult to answer this, but please check your compilation options
Please provide the signal trapped and atleast a few lines of the stack-trace - for all the threads. One thing you can check for yourself is to print the threads' stack-track (using threads/thread or pthread and thread current <x> based on the debugger) and and if there is a common data that is being accessed. It is most likely that the segfault occurred when two threads were trying to read off the other's (uncommitted) change
Hope that helps.
Edit:
After checking your code, I think the problem is the global picture array. You seem to be modifying that in the thread function without any guards. You loop using px and py and all the threads will have the same px and py and will try to write into the picture array at the same time. Please try to modify your code to prevent multiple threads from stepping on each other's data modifications.
Is func_call a function, or a function pointer? If it's a function pointer, there is your problem: you took the address of a function pointer and then cast it.
People are guessing because you've provided only a fraction of the program, which mentions names like func_call with no declaration in scope.
Your compiler must be giving you diagnostics about this program, because you're passing a (void *) expression to a function pointer parameter.
Define your thread function in a way that is compatible with pthread_create, and then just call it without any casts.

Is synchronization needed inside FinalConstruct()/FinalRelease()?

In my free-threaded in-proc COM object using ATL I want to add a member variable that will be set only in FinalConstruct() and read only in FinalRelease(). No other code will ever manipulate that member variable.
I doubt whether I need synchronization when accessing that member variable. I carefully read ATL sources and looks like those methods are always called no more than once and therefore from one thread only.
Is that correct assumption? Can I omit synchronization?
Yes, the assumption is correct. Think of it as an extension of the C++ constructor and destructor. In theory, you could call a method on a COM object from a different thread, while FinalRelease() is executing. Although, that is undefined behaviour, and not an expected occurrence. You shouldn't try to protect yourself from it, just as you wouldn't try to protect yourself from other threads in a destructor. If you have to protect yourself in the destructor, the design is generally broken (it would indicate that you do not have a proper termination protocol between your threads).
The only way FinalRelease() could be called from another thread, is when the client code does not have a valid reference count to your object, or if some other parts of your code is releasing twice. This is a hard error, and will probably end up in a crash anyway, totally unrelated to any synchronization errors you might have. The ATL code for managing object reference count is thread safe, and will not leave any race conditions open.
As for FinalConstruct(), a reference to the object is not returned to any client before FinalConstruct() has finished with a successful return code.

Resources