4 ms·
To be clear, my playground link is calling libc's qsort. The FFI definition: extern "C" { fn qsort(ptr: *mut c_void, count: size_t, size: size_t, comp: ex
by MaulingMonkey 3y ago
To be clear, my playground link is calling libc's qsort. The FFI definition:
extern "C" { fn qsort(ptr: *mut c_void, count: size_t, size: size_t, comp: extern "C" fn(*const c_void, *const c_void) -> c_int); }
And the call:
unsafe { qsort(ptr, len, size_of::<E>(), comp_wrapper::<E, C>) };
Are both hidden away in the body of the wrapper fn.
- Ericson2314 3y agoI am writing a single abstract declaration (I suppose I should have used `extern "C" {...}` to be clear) that one can only use safely. You are writing some unsafe code with safe wrapper. These are not the same.
- MaulingMonkey 3y ago> I am writing a single abstract declaration (I suppose I should have used `extern "C" {...}` to be clear) that one can only use safely. Your abstract declaration still wouldn't be safe. Remaining unsafety includes: • possible dangling pointers • possible incorrect lengths • possible libc bugs with ZST elements • undefined behavior if the sort fn misbehaves - (recently reported as a security issue against glibc because that being UB is dumb even if allowed by the standard: https://news.ycombinator.com/item?id=39264396 https://news.ycombinator.com/item?id=39264396 ) This is why I call it a "half measure". I also fail to see how your proposed abstract declaration would simplify either my wrapper, or other code that would actually bother to use the raw FFI definition in any significant way. This is why I further call it "unnecessary". It also fails to specify which underlying FFI parameter size_of::<T>() would actually be passed into. > You are writing some unsafe code with safe wrapper. My wrapper remains `unsafe` as well, but it ameliorates everything it reasonably can. > These are not the same. No, but my wrapper demonstrates an actual use case of your raw FFI definition... and shows the actual concerns of surrounding code that aren't significantly helped by your declaration.
- Ericson2314 3y agoReplace my pointers with safe references then. Add a static assertion in a where clause about not being a ZST. The second example with the vtables is the point (i.e. complicated data structures). qsort is just a simple example to introduce the concept.
- MaulingMonkey 3y agoVtables are pretty solved as well. I do a lot of Windows COM interop. Using the `windows` crate, vtables for COM interfaces are relegated to an implementation detail - instead you simply implement a (typically safe!) trait: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Media/Audio/XAudio2/trait.IXAudio2EngineCallback_Impl.html https://microsoft.github.io/windows-docs-rs/doc/windows/Win3... Which can then be converted to a refcounted smart pointer: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Media/Audio/XAudio2/struct.IXAudio2EngineCallback.html https://microsoft.github.io/windows-docs-rs/doc/windows/Win3... All driven by win32 sdk parsing and metadata. But suppose we want to roll our own, because we tend to prefer `winapi` but it lacks definition. That's not too terrible either: • https://github.com/MaulingMonkey/thindx-xaudio2/blob/master/crates/thindx-xaudio2-sys/src/sys28.rs#L919-L940 https://github.com/MaulingMonkey/thindx-xaudio2/blob/master/... • https://github.com/MaulingMonkey/thindx-xaudio2/blob/master/crates/thindx-xaudio2-sys/src/macros.rs https://github.com/MaulingMonkey/thindx-xaudio2/blob/master/... • https://github.com/MaulingMonkey/thindx-xaudio2/blob/master/crates/thindx-xaudio2/src/xa28/engine_callback.rs https://github.com/MaulingMonkey/thindx-xaudio2/blob/master/... I could more heavily lean on my macros ala `windows`, but I went the route of manual control for better doc comments, more explicit control of thread safety traits to match the existing C++ codebase, etc. Is there some pointer casting? Yes. Is it annoying or likely to be what breaks? No. What is annoying? • Stacked borrows and narrowing spatial provenance ( https://github.com/retep998/winapi-rs/issues/1025 https://github.com/retep998/winapi-rs/issues/1025 - this can be "solved" by sticking to pointers ala `windows`, or by choosing a different provenance model like rustc might be doing?) • Guarding against panics unwinding over an FFI boundary. This is at least being worked on, but remains unfinished ( https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html ) • Edge case ABI weirdness specific to C++ methods ( https://devblogs.microsoft.com/oldnewthing/20220113-00/?p=106152 https://devblogs.microsoft.com/oldnewthing/20220113-00/?p=10... , https://github.com/retep998/winapi-rs/issues/523 https://github.com/retep998/winapi-rs/issues/523 )