Creating stack space allocation from whole cloth in unsafe

⚓ Rust    📅 2026-03-05    👤 surdeus    👁️ 3      

surdeus

I am wrapping an old C library and am therefore diving into the unsafe world. I want to be able to construct a rust object purely from the results of a C function, but the only solution I found requires that the object's type have Default, or otherwise be initialized somehow.

Here's what I mean.

I have a function which I have brought in via rust-bindgen which uses the typical C pattern of accepting a pointer and length argument, and constructing the object by writing to that memory, with the memory chunk being provided by the user.I want to take that memory chunk and trust that it's a valid rust struct once done.

Note: Not shown here, I use a proc macro to ensure the struct is a flat collection of f64s with #[repr(C)], which matches the layout expected. (I hope lol!)

I have a function provided by rust-bindgen with a signature similar to:

use std::ffi::c_void;

mod ffi {
  unsafe fn read(dest: *mut c_void, size: usize) -> *mut c_void;
}

I am wrapping this in the following code:

use std::ffi::c_void;

pub fn read<B: ReadableThingie>() -> Result<B, SomeError> {
  let size = size_of::<B>();

  let block: B = B::default();

  let ptr = &block as *const B;
  let ptr = ptr as *mut c_void;

  let result = { unsafe { ffi::read(ptr, size) } };

  if result.is_null() {
    Ok(block)
  } else {
    Err(SomeError)
  }
}

I believe this works as intended. I'm assuming, of course, that ReadableThingie meets the criteria of memory layout matching what's expected, and that it implements Default. By constructing the Default variant, I can be sure that the stack allocation has been made correctly, and that ptr is a good sane thing to send to C-land.

The thing is, and I admit this is kind of nit picky, I don't want to require ReadableThingie to impl Default. I don't care about what was in memory before since I am positive that every bit of the new struct will be initialized correctly. Also, a user may intruduce some shennanigans with an explicit impl Default that would be more complicated than just assigning each field to zero/some literal. Which is fine, but that's wasted work since I'm just going to clobber it inside of the ffi call. Also, though I don't enforce this, the only way a user should be constructing one of these is via this method anyways. There's no reason a user would want a default instance of one of these in practice.

Is there a way to get the stack space allocated uninitialized (or I would accept zero'd) and just transmute it?

Other techniques I've tried:

  • create an array of u8 with the size of B, and use one of the transmute variants to wish the object into being. Works fine if B is known, doesn't work in generics. Rust refuses to do the monomorphization here.
  • create a Vec and do something similar to above. Works even in a generic, but allocates heap which I feel is unnecessary.

I get why rust requires that block be initialized normally, but in this case I'm providing the constructor via the C function and don't necessarily need it initialized, just allocated.

I can also just live with requiring Default. But just for educational purposes, is there a way around this?

5 posts - 4 participants

Read full topic

🏷️ Rust_feed