-
Notifications
You must be signed in to change notification settings - Fork 537
Fix FFI allocator mismatch by properly handling Rust/C ownership #2078
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Fix FFI allocator mismatch by properly handling Rust/C ownership #2078
Conversation
cfsmp3
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this important fix! Allocator mismatch between C and Rust is a real source of undefined behavior, and this PR correctly identifies the problem.
However, the implementation could be improved to follow better Rust patterns. Here are the issues I found:
1. Layout calculation duplicated across files (UB risk)
The same layout calculation now appears in 4 places:
Layout::array::<dtvcc_symbol>(CCX_DTVCC_MAX_COLUMNS as usize)window.rs:164(allocation)window.rs:675(allocation in tests)window.rs:706(allocation in tests)lib.rs:278(deallocation - new in this PR)
If anyone changes the allocation size without updating all deallocation sites, it's instant UB. Allocation and deallocation logic should be encapsulated together.
Suggested fix: Create helper functions in decoder/mod.rs or decoder/window.rs:
fn row_layout() -> Layout {
Layout::array::<dtvcc_symbol>(CCX_DTVCC_MAX_COLUMNS as usize)
.expect("row layout calculation")
}
pub unsafe fn alloc_row() -> *mut dtvcc_symbol {
alloc_zeroed(row_layout()) as *mut dtvcc_symbol
}
pub unsafe fn dealloc_row(ptr: *mut dtvcc_symbol) {
if !ptr.is_null() {
dealloc(ptr as *mut u8, row_layout());
}
}Then lib.rs just calls decoder::dealloc_row(*row_ptr) - no Layout knowledge needed outside the module.
2. Duplicate free declarations
There are now TWO extern "C" fn free declarations:
demuxer/common_types.rs:8- privatelibccxr_exports/demuxer.rs:24- now public
Please consolidate these.
3. free exported from wrong module
// In simplexml.rs (encoder module)
use crate::libccxr_exports::demuxer::free;free() is a C stdlib function, not a demuxer-specific function. This is confusing.
Suggested fix: Create a central module for FFI memory helpers:
// src/rust/src/ffi_alloc.rs (new file)
use std::os::raw::c_void;
extern "C" {
fn free(ptr: *mut c_void);
}
/// Frees memory allocated by C code (malloc/calloc)
#[inline]
pub unsafe fn c_free<T>(ptr: *mut T) {
if !ptr.is_null() {
free(ptr as *mut c_void);
}
}Then use ffi_alloc::c_free(ptr) everywhere.
4. Making CCX_DTVCC_MAX_COLUMNS public
This leaks internal implementation details just for deallocation. With the alloc_row()/dealloc_row() approach above, this constant can stay private.
Summary
The fix is correct in principle, but please refactor to:
- Encapsulate row alloc/dealloc in helper functions (prevents Layout mismatch bugs)
- Create a central
ffi_allocmodule for C memory functions (or addlibccrate) - Remove duplicate
freedeclaration incommon_types.rs - Keep
CCX_DTVCC_MAX_COLUMNSprivate
Happy to discuss if you have questions!
|
@cfsmp3
All allocation/deallocation paths now match ownership correctly |
CCExtractor CI platform finished running the test files on linux. Below is a summary of the test results, when compared to test for commit 032cd1c...:
Your PR breaks these cases:
Congratulations: Merging this PR would fix the following tests:
It seems that not all tests were passed completely. This is an indication that the output of some files is not as expected (but might be according to you). Check the result page for more info. |
CCExtractor CI platform finished running the test files on windows. Below is a summary of the test results, when compared to test for commit 032cd1c...:
Your PR breaks these cases:
Congratulations: Merging this PR would fix the following tests:
It seems that not all tests were passed completely. This is an indication that the output of some files is not as expected (but might be according to you). Check the result page for more info. |
In raising this pull request, I confirm the following (please check boxes):
My familiarity with the project is as follows (check one):
Description
As discussed on Zulip, I had a question about memory ownership in stream_functions.rs. Some pointers coming from C (like the demuxer pointer) were being wrapped in Box::from_raw, which assumes Rust owns them and will free them. The allocation actually happens on the C side, which could cause undefined behavior (UB) and allocator mismatches.
So proper handling is needed, especially as the platform is moving towards Rust-managed memory for safety and maintainability.
Problem
Changes Made
Flowchart / Old vs New Behavior
Problems
Allocator mismatch
UB if C malloc and Rust dealloc mismatch
Miri and test errors
Benefits
Why Ownership Changed to Rust
Test Plan