FFI代码审查
ffi-code-review
by anderskev
Reviews Rust FFI code for type safety, memory layout compatibility, string handling, callback patterns, and unsafe boundary correctness. Use when reviewing extern blocks, #[repr(C)] types, bindgen output, or code calling C/C++ libraries.
安装
claude skill add --url https://github.com/openclaw/skills文档
FFI Code Review
Review Workflow
- Check Cargo.toml -- Note Rust edition (2024 has breaking changes to extern blocks and unsafe attributes),
build-dependencies(bindgen, cc, pkg-config),crate-type(cdylib,staticlib), andlinkskey - Check build.rs -- Verify link directives (
cargo:rustc-link-lib,cargo:rustc-link-search), bindgen configuration, and C source compilation - Check extern blocks -- Verify calling conventions, symbol declarations, and safety annotations
- Check type layout -- Every type crossing FFI must be
#[repr(C)]or a primitive FFI type - Check string and pointer handling -- CStr/CString usage, null checks, ownership transfers
- Check callbacks --
extern "C" fnpointers, panic safety across FFI boundary - Verify before reporting -- Load
beagle-rust:review-verification-protocolbefore submitting findings
Output Format
Report findings as:
[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.
Quick Reference
| Issue Type | Reference |
|---|---|
| C-to-Rust type mapping, repr(C) layout, enums, opaque types | references/type-mapping.md |
| Safe wrappers, ownership transfer, callbacks, build.rs, testing | references/safety-patterns.md |
Review Checklist
extern Blocks and Calling Conventions
- Foreign function declarations use
extern "C"(explicit, not bareextern) - Edition 2024:
extern "C" {}blocks written asunsafe extern "C" {} - Functions exposed to C use
extern "C" fn(not default Rust calling convention) - Calling convention matches the foreign library (
"C","system"for Win32 API) -
#[link(name = "...")]specifies the correct library name -
#[link(name = "...", kind = "static")]used when statically linking
Symbol Management
- Exported functions use
#[no_mangle]to preserve symbol names - Edition 2024:
#[no_mangle]written as#[unsafe(no_mangle)] - Edition 2024:
#[export_name = "..."]written as#[unsafe(export_name = "...")] -
#[link_name = "..."]used when Rust name differs from C symbol - Exported items are
pub(only public#[no_mangle]symbols appear in library output)
Type Layout
- Every struct/union crossing FFI has
#[repr(C)]-- Rust's default layout is undefined - Primitive types use
std::ffi/std::os::rawequivalents (c_int,c_char,c_void) - No bare
i32where C usesint-- usec_int(width varies by platform) - Quirky C types like
__be32use byte arrays ([u8; 4]), not Rust integers - Enums crossing FFI use
#[repr(C)]or#[repr(u8)]/#[repr(u32)]with explicit discriminants - C-style bitflag enums use a newtype around an integer (or
bitflagscrate), not a Rust enum -
#[non_exhaustive]on enums representing C enumerations that may gain new values
String Handling
- C strings use
CStr(borrowed) orCString(owned), never&strorString -
CString::new()result is checked for interior null bytes (returnsErron\0) -
CStringoutlives any*const c_charpointer derived from it via.as_ptr() - Incoming
*const c_charvalidated withCStr::from_ptr()insideunsafe - No assumption that C strings are valid UTF-8 -- use
to_str()which returnsResult - OS paths use
OsStr/OsStringandCStr, not&str
Ownership and Allocation
- Clear ownership contract: who allocates, who frees
- Rust-allocated memory freed by Rust (
Box::from_raw), C-allocated freed by C -
Box::into_raw/Box::from_rawpaired correctly for heap transfers -
Vec::into_raw_partsused when passing arrays to C (pointer + length + capacity) - Destructor functions exposed for every opaque Rust type given to C
- No
Droprunning on C-allocated memory (and vice versa)
Callbacks
- Callback types are
extern "C" fn(...), not closures orfn(...) - Callbacks use
std::panic::catch_unwindto prevent panics from unwinding across FFI - Callback context passed as
*mut c_voidwith safe reconstruction at call site -
Option<extern "C" fn(...)>used for nullable function pointers (niche optimization)
Bindgen and Build Scripts
- Bindgen output reviewed for correctness (auto-generated types may need adjustment)
-
-syscrate pattern used for raw bindings, separate crate for safe wrappers -
build.rsusescargo:rustc-link-libandcargo:rustc-link-searchcorrectly -
linkskey inCargo.tomlprevents duplicate linking of the same native library - Platform-specific bindings generated per-build (not checked in for a single platform)
Safety Documentation
- Every
unsafeblock has a// SAFETY:comment explaining invariants - Every public FFI wrapper function documents safety requirements
- Edition 2024:
unsafe fnbodies use explicitunsafe {}blocks around unsafe ops
Severity Calibration
Critical (Block Merge)
- Missing
#[repr(C)]on types crossing FFI boundary (undefined memory layout) - Wrong string handling:
&str/StringwhereCStr/CStringrequired - Ownership confusion: freeing C-allocated memory with Rust's allocator (or vice versa)
- Panic unwinding across FFI boundary without
catch_unwind - Using Rust enum for C bitflags (invalid discriminant = undefined behavior)
- Passing closure where
extern "C" fnpointer required
Major (Should Fix)
- Missing safety documentation on
unsafeblocks or public FFI functions - No null pointer check on incoming
*const T/*mut Tbefore dereferencing CStringdropped before its pointer is used by C (dangling pointer)- Missing
#[link(name = "...")]causing link failures on some platforms - Edition 2024:
externblock not markedunsafe extern - Edition 2024:
#[no_mangle]not wrapped in#[unsafe(...)]
Minor (Consider Fixing)
- Using
i32instead ofc_intfor Cint(correct on most platforms but not portable) - Missing
#[non_exhaustive]on enums mapping to extensible C enumerations - Verbose manual bindings where bindgen would be more maintainable
- Checked-in bindings without platform guards
Informational
- Suggestions to split raw bindings into a
-syscrate - Suggestions to add opaque wrapper types for distinct
*mut c_voidpointers - Suggestions to use
Option<NonNull<T>>for nullable pointers
Valid Patterns (Do NOT Flag)
unsafe extern "C" {}in edition 2024 -- correct form for foreign declarations#[unsafe(no_mangle)]in edition 2024 -- correct form for symbol exportOption<extern "C" fn(...)>for nullable callbacks -- niche optimization guaranteedOption<NonNull<T>>for nullable pointers -- zero-cost nullable pointer pattern*mut c_voidfor opaque C types -- standard when internal layout is irrelevant- Distinct empty structs wrapping
c_voidfor type-safe opaque pointers -- prevents pointer confusion CStr::from_bytes_with_nul_uncheckedwith compile-time literal -- safe when literal is known null-terminatedextern "C-unwind"for controlled unwinding -- valid per RFC 2945include!(concat!(env!("OUT_DIR"), "/bindings.rs"))in bindgen crates -- standard patternBox::into_raw/Box::from_rawpairs for ownership transfer -- correct pattern when paired
Before Submitting Findings
Load and follow beagle-rust:review-verification-protocol before reporting any issue.
相关 Skills
前端设计
by anthropics
面向组件、页面、海报和 Web 应用开发,按鲜明视觉方向生成可直接落地的前端代码与高质感 UI,适合做 landing page、Dashboard 或美化现有界面,避开千篇一律的 AI 审美。
✎ 想把页面做得既能上线又有设计感,就用前端设计:组件到整站都能产出,难得的是能避开千篇一律的 AI 味。
网页应用测试
by anthropics
用 Playwright 为本地 Web 应用编写自动化测试,支持启动开发服务器、校验前端交互、排查 UI 异常、抓取截图与浏览器日志,适合调试动态页面和回归验证。
✎ 借助 Playwright 一站式验证本地 Web 应用前端功能,调 UI 时还能同步查看日志和截图,定位问题更快。
网页构建器
by anthropics
面向复杂 claude.ai HTML artifact 开发,快速初始化 React + Tailwind CSS + shadcn/ui 项目并打包为单文件 HTML,适合需要状态管理、路由或多组件交互的页面。
✎ 在 claude.ai 里做复杂网页 Artifact 很省心,多组件、状态和路由都能顺手搭起来,React、Tailwind 与 shadcn/ui 组合效率高、成品也更精致。
相关 MCP 服务
GitHub
编辑精选by GitHub
GitHub 是 MCP 官方参考服务器,让 Claude 直接读写你的代码仓库和 Issues。
✎ 这个参考服务器解决了开发者想让 AI 安全访问 GitHub 数据的问题,适合需要自动化代码审查或 Issue 管理的团队。但注意它只是参考实现,生产环境得自己加固安全。
Context7 文档查询
编辑精选by Context7
Context7 是实时拉取最新文档和代码示例的智能助手,让你告别过时资料。
✎ 它能解决开发者查找文档时信息滞后的问题,特别适合快速上手新库或跟进更新。不过,依赖外部源可能导致偶尔的数据延迟,建议结合官方文档使用。
by tldraw
tldraw 是让 AI 助手直接在无限画布上绘图和协作的 MCP 服务器。
✎ 这解决了 AI 只能输出文本、无法视觉化协作的痛点——想象让 Claude 帮你画流程图或白板讨论。最适合需要快速原型设计或头脑风暴的开发者。不过,目前它只是个基础连接器,你得自己搭建画布应用才能发挥全部潜力。