That's not really the case. Not all C APIs are inherently unsafe by construction, and I've always appreciated when someone has wrapped a C library and produced two crates:
- a pure binding crate, which exposes the C lib libraries API, and
- a wrapper library that performs some basic improvements
Stuff in the second category typically includes adding Drop impls to resources that need to be released, translating "accepts pointer + len" into "accepts slices" (or vice versa on return), and "check return value of C call and turn it into a Result, possibly with a stringified error".
All of those are also good examples of local reasoning about unsafety. If a C API returns a buffer + size, it's unsafe to turn it into a reference/slice. But if you check the function succeeded, you unsafely make the slice/reference, and return it from a safe function. If it crashes, you've either not upheld the C calls preconditions (your fault, check how to call the C function), or the C code has a bug (not your fault, the bug is elsewhere).