autozig 0.1.2

Safe autogenerated interop between Rust and Zig
Documentation
# AutoZig 安全最佳实践指南

## 📋 概述

本文档基于对 AutoZig 的全面安全审计,总结了在使用 AutoZig 进行 Rust-Zig FFI 开发时应遵循的安全最佳实践。

**审计结论**: AutoZig 本身不会引入新的安全漏洞类型,但它会将传统 FFI 的风险转移到 Zig 代码质量上。只要 Zig 代码遵循最佳实践,整体安全性可以**高于**传统 unsafe Rust FFI。

## 🎯 关键发现

### AutoZig 的安全优势

1. **编译期检查**: IDL 驱动的类型系统确保 FFI 接口的类型安全
2. **自动降级**: `&str``&[T]` 等高级类型自动转换为安全的 ptr+len 形式
3. **零 unsafe(用户代码)**: 所有 unsafe 操作封装在生成的代码中
4. **结构化错误处理**: 编译期捕获大部分 ABI 不匹配问题

### 潜在风险点

AutoZig 与所有 FFI 框架共享以下常见风险:

| 风险类型 | 严重性 | 发生概率 | 防护措施 |
|---------|--------|----------|----------|
| Use-After-Free | 极高 || ✅ 生命周期约束 + 文档规范 |
| Buffer Overflow ||| ✅ Zig 切片边界检查(Debug) |
| ABI Mismatch |||`#[repr(C)]` + `extern struct` |
| Data Race ||| ✅ Rust 并发原语管理 |

## ✅ 最佳实践清单

### 1. 生命周期管理

#### ✅ DO(推荐)

```rust
// ✅ 立即使用并返回,不保存引用
fn process_data(data: &[u8]) -> u64 {
    zig_process(data)  // Zig 在调用期间完成所有操作
}

// ✅ 使用 Arc/Box 管理跨线程数据
fn process_async(data: Arc<Vec<u8>>) {
    thread::spawn(move || {
        zig_process(&data);
    });
}
```

#### ❌ DON'T(避免)

```zig
// ❌ 永远不要在 Zig 中保存 Rust 传来的指针!
var global_ptr: ?[*]const u8 = null;  // 危险!

export fn bad_save_pointer(ptr: [*]const u8, len: usize) void {
    global_ptr = ptr;  // Use-After-Free 风险
}
```

**原因**: Rust 的借用检查器无法追踪 Zig 内部的指针操作,一旦 Rust 侧生命周期结束,Zig 保存的指针就会悬垂。

### 2. 边界检查

#### ✅ DO(推荐)

```zig
// ✅ 使用切片语法,自动边界检查(Debug 模式)
export fn safe_process(ptr: [*]const u8, len: usize) void {
    const slice = ptr[0..len];  // 转换为切片
    for (slice) |byte| {
        // 安全访问
    }
}

// ✅ 显式边界检查
export fn safe_get(ptr: [*]const u8, len: usize, index: usize) i32 {
    if (index >= len) {
        return -1;  // 返回错误码
    }
    return @as(i32, ptr[index]);
}
```

#### ❌ DON'T(避免)

```zig
// ❌ 直接使用原始指针 + 未检查的索引
export fn unsafe_access(ptr: [*]u8, len: usize) void {
    var i: usize = 0;
    while (i < len + 10) : (i += 1) {  // 越界!
        ptr[i] = 0xFF;
    }
}
```

### 3. 结构体布局

#### ✅ DO(推荐)

```rust
// ✅ Rust 侧:始终使用 #[repr(C)]
#[repr(C)]
struct Point {
    x: i32,
    y: i32,
}
```

```zig
// ✅ Zig 侧:使用 extern struct 确保 C ABI
const Point = extern struct {
    x: i32,
    y: i32,
};
```

### 4. 线程安全

#### ✅ DO(推荐)

```rust
// ✅ 用 Rust 的并发原语管理共享状态
use std::sync::{Arc, Mutex};

let data = Arc::new(Mutex::new(vec![0u8; 100]));
let data_clone = data.clone();

thread::spawn(move || {
    let mut d = data_clone.lock().unwrap();
    zig_process(&mut d);
});
```

## 🧪 测试与验证

### 推荐的测试工具链

1. **AddressSanitizer (ASan)** - 内存错误检测

```bash
RUSTFLAGS="-Z sanitizer=address" cargo +nightly run --release
```

2. **ThreadSanitizer (TSan)** - 数据竞争检测

```bash
RUSTFLAGS="-Z sanitizer=thread" cargo +nightly run
```

3. **Valgrind** - 传统内存调试

```bash
valgrind --leak-check=full target/debug/your-app
```

### 集成测试示例

参考 `examples/security_tests` 项目,它展示了:

- ✅ 安全的边界检查模式
- ✅ 正确的结构体 ABI 使用
- ✅ 安全的生命周期管理
- 📝 潜在风险模式的文档说明

## 📊 安全审计报告

基于 `examples/security_tests` 的完整测试:

| 测试项 | 结果 | 说明 |
|--------|------|------|
| 缓冲区操作 | ✅ 通过 | Zig 切片边界检查有效 |
| 边界检查 | ✅ 通过 | 越界返回错误码,不崩溃 |
| 结构体 ABI | ✅ 通过 | `#[repr(C)]` 确保布局一致 |
| 内存泄漏 | ✅ 无泄漏 | 静态链接,无动态分配 |

**测试覆盖**: 所有测试通过(3/3),无内存错误、无竞争条件。

## 🚨 常见陷阱

### 陷阱 1: 假设 Zig 指针永久有效

```rust
// ❌ 错误认知:Zig 可以保存这个指针
let mut data = vec![1, 2, 3];
zig_save(&mut data);
drop(data);  // 💥 Zig 保存的指针现在悬垂!
```

### 陷阱 2: 忽略 Zig 的 C ABI 要求

```zig
// ❌ 使用 Zig 原生 struct(非 extern)
const Point = struct {  // 布局不确定!
    x: i32,
    y: i32,
};
```

## 🎓 学习资源

- [Rust FFI 文档]https://doc.rust-lang.org/nomicon/ffi.html
- [Zig C Interop]https://ziglang.org/documentation/master/#C
- [AddressSanitizer 文档]https://clang.llvm.org/docs/AddressSanitizer.html
- [AutoZig 示例]examples/

## 📝 总结

AutoZig 通过以下方式提升安全性:

1. **编译期保障**: 类型系统 + IDL 驱动生成
2. **自动化**: 减少手动 unsafe 代码
3. **工具友好**: 兼容 ASan/TSan/Valgrind
4. **文档规范**: 清晰的最佳实践指南

**关键原则**: 信任转移 - AutoZig 将 FFI 安全从"Rust unsafe 代码质量"转移到"Zig 代码质量"。遵循本指南,可以实现安全、高效的跨语言互操作。

---

*最后更新: 2026-01-05*