Auto derived clone segfaults for newtype from FFI binding

I use bindgen to create the rust bindings for a C-API.
For the generated binding code looks like this:

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct clingo_model {
    _unused: [u8; 0],
}
#[doc = "! Object representing a model."]
pub type clingo_model_t = clingo_model;

In my library i create a newtype:

#[derive(Debug, Copy, Clone)]
pub struct Model(clingo_model_t);

When I try to clone a model something goes wrong. If i try to invoke a method on the clone i get a segfault.

...
println!("1:{:?}", model);
println!("number : {}", model.number().unwrap());
let model2 = model.clone();
println!("2:{:?}", model2);
println!("number : {}", model2.number().unwrap());

See the test case here.

Has anyone an idea why and maybe how to fix it?

Guessing here a bit, but: the clingo_model thing is not the actual representation of the object. The Copy and Clone on it therefore doesn't do a proper clone ‒ it just copies 0 bytes from the beginning of the old object, not caring that:

  • The object likely has different size
  • There might be some semantic behind that that is being ignored (eg. deep-copying some pointers the C thing has behind the scenes, causing a double-free after both copies are dropped).

So the root cause is probably bindgen generating (or being asked to generate) that Copy and Clone in the first place. To copy the C object, you need to call some C code, not just copy the sentinel fake object here.

3 Likes