rust-lang / rust-lang/rust-bindgen
[c++] Invalid free when destroying a class with an std::string member
Open
Nobody has claimed this yet.
A-C++
I-needs-docs
- Dominant language
- Rust
- Stars
- 5.3k
- Forks
- 829
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 15
Description
Input C/C++ Header
#include <string>
namespace MySpace {
class MyString {
std::string internal;
public:
MyString();
~MyString();
};
MyString::MyString() {printf("constructing MyString\n");}
MyString::~MyString(){printf("destructing MyString\n");}
}
Bindgen Invocation
let wl = "MySpace.*";
bindgen::Builder::default()
.header("wrapper.hpp")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.clang_arg("-x")
.clang_arg("c++")
.opaque_type("std::.*")
.whitelist_var(wl)
.whitelist_type(wl)
.whitelist_function(wl)
.generate()
Actual Results
pub type std_string = [u64; 4usize];
#[repr(C)]
#[derive(Debug)]
pub struct MySpace_MyString {
pub internal: std_string,
}
#[test]
fn bindgen_test_layout_MySpace_MyString() {
assert_eq!(
::std::mem::size_of::<MySpace_MyString>(),
32usize,
concat!("Size of: ", stringify!(MySpace_MyString))
);
assert_eq!(
::std::mem::align_of::<MySpace_MyString>(),
8usize,
concat!("Alignment of ", stringify!(MySpace_MyString))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<MySpace_MyString>())).internal as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(MySpace_MyString),
"::",
stringify!(internal)
)
);
}
extern "C" {
#[link_name = "\u{1}_ZN7MySpace8MyStringC1Ev"]
pub fn MySpace_MyString_MyString(this: *mut MySpace_MyString);
}
extern "C" {
#[link_name = "\u{1}_ZN7MySpace8MyStringD1Ev"]
pub fn MySpace_MyString_MyString_destructor(this: *mut MySpace_MyString);
}
impl MySpace_MyString {
#[inline]
pub unsafe fn new() -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
MySpace_MyString_MyString(__bindgen_tmp.as_mut_ptr());
__bindgen_tmp.assume_init()
}
#[inline]
pub unsafe fn destruct(&mut self) {
MySpace_MyString_MyString_destructor(self)
}
}
this looks fine, but if I run
let mut val = MySpace_MyString::new();
val.destruct();
I get the output
constructing MyString
destructing MyString
free(): invalid pointer
Aborted (core dumped)
Expected Results
There should be no invalid free, the code looks fine to me. And it works if I use C++ instead of rust.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the issue using the inline wrapper.hpp header and the bindgen::Builder invocation, then inspect the generated MySpace_MyString bindings and their constructor/destructor entry points. Compare the Rust destruction path with the C++ class behavior and verify the fix by rerunning the example so destroying the value produces no invalid free.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, rust
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100