You are right, let’s reason on some real code 
useless_and_unsafe.c
static int value = 0;
void
inc_value() {
++value;
}
int
get_value() {
return value;
}
This is a very simple and useless C code for a useless library. As you can see there is a value that is not accessible from outside that can be manipulated using inc_value and get_value. Unfortunately, our friendly C developer forgot to make them thread safe to be used…
Now we can write the -sys crate.
#[link(name = "useless_and_unsafe")]
extern "C" {
pub fn get_value() -> i32;
pub fn inc_value();
}
Pretty straightforward.
We also want to write down the safe crate, and people should use it instead of the -sys crate…
#[macro_use]
extern crate lazy_static;
extern crate useless_and_unsafe_sys;
use std::sync::Mutex;
lazy_static! {
static ref LIB_MUTEX: Mutex<i32> = Mutex::new(0);
}
pub fn get_value() -> i32 {
let _guard = LIB_MUTEX.lock().unwrap();
unsafe { useless_and_unsafe_sys::get_value() }
}
pub fn inc_value() {
let _guard = LIB_MUTEX.lock().unwrap();
unsafe { useless_and_unsafe_sys::inc_value() }
}
As you can see, we want a Mutex (silly and slow solution) to control that we can only modify the internal value atomically in multithread code.
Fantastic. Now someone else decide in his crate to use the -sys crate directly as a dependency. That’s very bad, because, even if there is a sort of locking mechanism, it will be different from the Mutex we are using. Maybe this developer has his reasons (using parking_lot::Mutex could be a very valid one).
The fact is, if someone is using both my crate and the one from the other developer, it is possible that the inner value is accessed concurrently from multiple threads, just because there are multiple locking mechanisms that are trying to avoid this problem. Obviously failing, because they can control what other code does.
My idea is that, even if the safe crate cannot avoid another crate that tries to do the same thing, it is conceptually possible that the -sys crate is only imported once. In this case both safe crate can compile flawlessly, but a project that includes both will not compile, just because the -sys crate can only be imported once.
I hope I have been able to clarify my idea. If not, I’ll try again, in a (hopefully) better way.