Mapping &Foo and Option<&Foo> directly to pointers in FFI


#1

My understanding is that if Foo is a struct, &Foo is represented as a non-null pointer in memory and Option<&Foo> is represented as a nullable pointer in memory. Is this always the case?

If it is always the case, should I write &Foo as an argument type on the Rust side of FFI and as const* Foo on the C side of FFI when the pointer must not be null and Option<&Foo> in Rust and const* Foo in C when the pointer may be null?

It seems that rusty-cheddar doesn’t currently do this. Is there a reason of the “don’t do that” sort why rusty-cheddar doesn’t do this automatically or is this just a matter of rusty-cheddar not having type rewriting rules that match rustc’s pointer optimizations yet?


Nullable Pointers in FFI
#2

While what you’ve said is true, insofar as I know, it isn’t guaranteed.

Also, it’s somewhat poor form; you should really be testing to make sure the pointers C is giving you are actually, really, no fooling, actually not null. Because if they are null, bad things will happen.


#3

(I should have said “in the extern "C" calling convention” instead of saying “in memory”.) Anyway, it’s pretty annoying if references being pointers in the extern "C" isn’t guaranteed. At least the effect of Option around a non-nullable Rust pointer type is documented. (If that case of “documented” doesn’t equal “guaranteed”, it would be pretty bad.)

Well, functions exposed to C are unsafe anyway: If you materialize a slice from a pointer and a length, you can’t check that you get a slice of valid memory anyway.


#4

I just double-checked and couldn’t find any assurances in the language reference, the stdlib docs or in the nomicon.

Also, as far as I’m aware, types in Rust don’t magically get different representations when used through FFI; either their natural representation is identical to their C representation, or it isn’t. This is denoted using #[repr(C)] on non-primitive types.

That’s a property of the individual function, not of the C ABI.


#5

OK. Thanks. I guess I’ll use *const and *mut in Rust, then, instead of treating the calling convention as an implied transmute.