Add: windows mvp - transparent bugs not fixed

This commit is contained in:
DaZuo0122
2026-02-12 22:58:33 +08:00
commit 61825f647d
147 changed files with 28498 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
---
id: ffi-10
original_id: P.UNS.FFI.10
level: P
impact: CRITICAL
---
# Exported Rust Functions Must Be Designed for Thread-Safety
## Summary
Functions exported to C with `#[no_mangle] extern "C"` may be called from multiple threads. Ensure they are thread-safe.
## Rationale
- C code doesn't know about Rust's thread safety guarantees
- C may call your function from any thread
- Global state must be synchronized
- Race conditions are undefined behavior
## Bad Example
```rust
// DON'T: Unsynchronized global state
static mut COUNTER: i32 = 0;
#[no_mangle]
pub extern "C" fn increment() -> i32 {
unsafe {
COUNTER += 1; // Data race if called from multiple threads!
COUNTER
}
}
// DON'T: Thread-local assuming single thread
thread_local! {
static CONFIG: RefCell<Config> = RefCell::new(Config::default());
}
#[no_mangle]
pub extern "C" fn set_config(value: i32) {
// Different threads get different configs!
// Is that what the C caller expects?
CONFIG.with(|c| c.borrow_mut().value = value);
}
// DON'T: Non-Send types in globals
static mut HANDLE: Option<Rc<Data>> = None; // Rc is not Send!
```
## Good Example
```rust
use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::{Mutex, OnceLock};
// DO: Use atomics for simple counters
static COUNTER: AtomicI32 = AtomicI32::new(0);
#[no_mangle]
pub extern "C" fn increment() -> i32 {
COUNTER.fetch_add(1, Ordering::SeqCst) + 1
}
// DO: Use Mutex for complex state
static CONFIG: OnceLock<Mutex<Config>> = OnceLock::new();
fn get_config() -> &'static Mutex<Config> {
CONFIG.get_or_init(|| Mutex::new(Config::default()))
}
#[no_mangle]
pub extern "C" fn set_config_value(value: i32) -> i32 {
match get_config().lock() {
Ok(mut config) => {
config.value = value;
0 // Success
}
Err(_) => -1 // Lock poisoned
}
}
// DO: Document thread safety requirements
/// Initializes the library. NOT thread-safe.
/// Must be called once from main thread before any other function.
#[no_mangle]
pub extern "C" fn init() -> i32 {
// One-time initialization
0
}
/// Processes data. Thread-safe.
/// May be called from multiple threads concurrently.
#[no_mangle]
pub extern "C" fn process(data: *const u8, len: usize) -> i32 {
// Uses only local state or synchronized globals
0
}
// DO: Make non-thread-safe APIs explicit
/// Handle for single-threaded use only.
///
/// # Thread Safety
///
/// This handle must only be used from the thread that created it.
struct SingleThreadHandle {
data: *mut Data,
_not_send: std::marker::PhantomData<*const ()>, // !Send
}
```
## Synchronization Patterns
| Pattern | Use Case |
|---------|----------|
| `AtomicT` | Simple counters, flags |
| `Mutex<T>` | Complex shared state |
| `RwLock<T>` | Read-heavy shared state |
| `OnceLock<T>` | Lazy one-time init |
| `thread_local!` | Per-thread state (document!) |
## Checklist
- [ ] Does my exported function access global state?
- [ ] Is that state properly synchronized?
- [ ] Have I documented thread-safety guarantees?
- [ ] Are any types !Send/!Sync exposed across FFI?
## Related Rules
- `ptr-01`: Don't share raw pointers across threads
- `safety-05`: Send/Sync implementation safety