chore: clear clippy errors, document all unsafe blocks, deny new SAFETY debt
Audit-driven cleanup pass. End state:
- cargo clippy --release --all-targets: 0 errors (was 4)
- undocumented_unsafe_blocks warnings: 0 (was 67)
- Cargo.toml: undocumented_unsafe_blocks escalated warn -> deny
Clippy correctness errors fixed:
- src/bin/{sw_encode_bench,vaapi_import_bench}.rs: receive_first_frame
rewritten per Oracle plan with total 10s deadline + 200ms wait slice +
while-let drain of all control events. The previous loop body always
exited on first iteration (never_loop); the new version actually retries
and matches production's repeated-poll semantics in state_portal.rs.
- src/avhw.rs: hash_sampled_y_plane tests now use a row_range(row, stride,
width) helper instead of inline stride * N. Preserves the row-index
intent across all sibling tests without tripping erasing_op (row==0) or
identity_op (row==1).
Machine-applicable clippy autofixes applied via 'cargo clippy --fix':
- unnecessary_cast, manual_is_multiple_of, needless_borrows_for_generic_args
- manual_abs_diff, derivable_impls, new_without_default
- unnecessary_map_or, unneeded_struct_pattern, redundant_locals
webrtc_gop_formula test rewritten to wrap the (fps * 2).max(20) formula in
a runtime lambda. The previous clippy --fix pass had constant-folded the
5fps case into assert_eq!(20, 20), silently stripping the floor-case
coverage. The lambda blocks the fold while keeping the formula exercisable.
67 SAFETY comments added across 7 files (cap_portal.rs 26, sw_encode_bench
21, state_portal.rs 7, vaapi_import_bench.rs 6, avhw.rs 5, state.rs 1,
main.rs 1). Two sites carry load-bearing invariant documentation:
- cap_portal.rs:806 process callback documents the PipeWire raw_buf
ownership contract across all 10 exit paths (audited: every path
correctly requeues; fd ownership via dup() is independent and also
exactly-once closed).
- avhw.rs:341 unsafe impl Send for EncState documents the single-thread
exclusivity assumption referenced by AGENTS.md.
All 97 unit tests + 3 integration tests still pass; cargo build --release
finishes clean. Lint escalation to deny freezes the SAFETY baseline: any
future patch adding an unsafe block without a // SAFETY: comment will fail
clippy at compile time.
This commit is contained in:
+22
-3
@@ -478,6 +478,10 @@ impl StatePortal {
|
||||
|
||||
if let Some(enc) = self.enc.as_mut() {
|
||||
// 将 DMA-BUF 帧零拷贝导入 VAAPI 硬件帧池
|
||||
// SAFETY: delegates to avhw::import_dma_buf_to_vaapi (itself an unsafe fn);
|
||||
// frames_rgb pointer is a valid AVBufferRef owned by enc, and frame's
|
||||
// fd/width/height/format/modifier/stride/offset come straight from the
|
||||
// PipeWire-formatted PwDmaBufFrame. See that function's own SAFETY contract.
|
||||
let mut vaapi_frame = unsafe {
|
||||
avhw::import_dma_buf_to_vaapi(
|
||||
enc.frames_rgb().as_ptr(),
|
||||
@@ -495,6 +499,8 @@ impl StatePortal {
|
||||
let t_encode_start = Instant::now();
|
||||
|
||||
// 设置帧的显示时间戳(PTS),基于已编码帧序号
|
||||
// SAFETY: vaapi_frame is the freshly-imported valid AVFrame returned by
|
||||
// import_dma_buf_to_vaapi above; pts is a plain i64 field on AVFrame.
|
||||
unsafe {
|
||||
(*vaapi_frame.as_mut_ptr()).pts = pts;
|
||||
}
|
||||
@@ -515,6 +521,8 @@ impl StatePortal {
|
||||
};
|
||||
self.stats.record_encode(&timings);
|
||||
} else if let Some(import) = self.enc_import.as_mut() {
|
||||
// SAFETY: same contract as the enc branch above — frames_rgb owned by
|
||||
// import, frame fields come from the PipeWire PwDmaBufFrame.
|
||||
let mut vaapi_frame = unsafe {
|
||||
avhw::import_dma_buf_to_vaapi(
|
||||
import.frames_rgb().as_ptr(),
|
||||
@@ -527,6 +535,7 @@ impl StatePortal {
|
||||
frame.offset,
|
||||
)
|
||||
}?;
|
||||
// SAFETY: vaapi_frame is the valid AVFrame returned above; pts is plain i64.
|
||||
unsafe {
|
||||
(*vaapi_frame.as_mut_ptr()).pts = pts;
|
||||
}
|
||||
@@ -756,7 +765,7 @@ fn webrtc_thread_loop(
|
||||
let should_send = match last_sent_bitrate {
|
||||
None => true,
|
||||
Some(last) => {
|
||||
let diff = if bwe > last { bwe - last } else { last - bwe };
|
||||
let diff = bwe.abs_diff(last);
|
||||
diff * 10 > last
|
||||
}
|
||||
};
|
||||
@@ -946,7 +955,12 @@ fn resolve_drm_device(args: &Args) -> Result<Option<PathBuf>> {
|
||||
/// 用于验证 DMA-BUF 元数据映射的正确性。
|
||||
#[cfg(test)]
|
||||
fn build_drm_descriptor(frame: &PwDmaBufFrame) -> ffmpeg_next::ffi::AVDRMFrameDescriptor {
|
||||
let mut desc: ffmpeg_next::ffi::AVDRMFrameDescriptor = unsafe { std::mem::zeroed() };
|
||||
let mut desc: ffmpeg_next::ffi::AVDRMFrameDescriptor = {
|
||||
// SAFETY: AVDRMFrameDescriptor is a POD struct from FFmpeg's C API with no
|
||||
// pointers orDrop fields; all-zero is a valid initial state. Every field is
|
||||
// explicitly overwritten in the lines below before the descriptor is used.
|
||||
unsafe { std::mem::zeroed() }
|
||||
};
|
||||
desc.nb_objects = 1; // 单个 DMA-BUF 对象
|
||||
desc.objects[0].fd = frame.fd.as_raw_fd(); // DMA-BUF 文件描述符
|
||||
desc.objects[0].size = 0; // 大小设为 0(内核自动确定)
|
||||
@@ -969,6 +983,9 @@ mod tests {
|
||||
fn make_test_frame() -> PwDmaBufFrame {
|
||||
// Create a dummy fd from stderr (always valid fd 2)
|
||||
// 使用 stderr(fd 2)的副本作为虚拟文件描述符
|
||||
// SAFETY: stderr (fd 2) is always-open in any process; libc::dup(2) returns
|
||||
// a fresh fd we solely own. OwnedFd::from_raw_fd takes ownership and closes
|
||||
// it on Drop. Test-only; the fd is never actually memory-mapped.
|
||||
let fd = unsafe { OwnedFd::from_raw_fd(libc::dup(2)) };
|
||||
PwDmaBufFrame {
|
||||
fd,
|
||||
@@ -1091,8 +1108,10 @@ mod tests {
|
||||
/// 测试:使用自定义偏移量和 stride 构建 DRM 描述符
|
||||
#[test]
|
||||
fn build_drm_descriptor_custom_offset_and_stride() {
|
||||
// SAFETY: same as make_test_frame — dup of stderr (fd 2), test-only.
|
||||
let test_fd = unsafe { OwnedFd::from_raw_fd(libc::dup(2)) };
|
||||
let frame = PwDmaBufFrame {
|
||||
fd: unsafe { OwnedFd::from_raw_fd(libc::dup(2)) },
|
||||
fd: test_fd,
|
||||
offset: 4096, // 4KB 对齐偏移
|
||||
stride: 3840 * 4, // 4K 宽度 × 4 字节
|
||||
modifier: 0x0100000000000001, // AMD modifiers
|
||||
|
||||
Reference in New Issue
Block a user