I'm currently in the process of writing a crate that provides a high-level interface to low-level FFI bindings to a certain library.
During testing, I uncovered that a certain method is prone to undefined behavior when called in a multi-threaded environment.
I landed on serializing access to the problematic method using a static Mutex, but I'm curious if there are drawbacks to this approach and if there are other common ways to work around such a problem.
The main drawback is one that applies to every other potential solution as well — that you can't be 100% sure that everyone is participating in using your wrapper to ensure serialized access. The cargo links key exists to help mitigate this issue but at the end of the day there's no 100% watertight way to prevent it and we have to concede to reality here.
A more practical drawback is that you're introducing synchronization overhead around a function where it theoretically might not be necessary (after all, the underlying library doesn't have any). If the function is not called in a hot loop, this is typically a correct tradeoff to be made. However, it can be avoided by taking a mutual exclusion token (e.g. &mut LibToken) which indicates that the lock is held instead of internally taking that lock. If most functions take some LibSystem*C parameter, using the existence of that system object as your token is often the way to go, guarding system init to only ever init one system at a time.