X86_64-pc-windows-gnu and x86_64-pc-windows-msvc abi compatibility

Hi, are x86_64-pc-windows-gnu and x86_64-pc-windows-msvc abi compatible for the same version of the rustc compiler ?

I don't have a definitive answer. Maybe that's a task for ABI cafe to test thoroughly.

In my experience from C, it depends how you mix them. If they live in separate binaries (exe loading a DLL), then extern "C" ABI seems to be compatible enough .

However, for static linking into the same executable, they're not quite compatible. They rely on different built-ins in GNU libc and libgcc vs MS CRT, so you need to link both runtimes, and that's probably a recipe for trouble.

1 Like

I' m testing this using libloading and haven't seen any incompatibility yet (either loading gnu from msvc or msvc from gnu) with complex structures and even crossbeam channel (sending messages from the loaded dll to the loader and vice versa) : I suppose the compiler code shows the memory layouts are the same for both targets, but didn't check this myself (yet)

It may be the same by accident, but is definitively not guaranteed. Also if you unwind across the abi boundary between the two because of a panic, it will either abort your entire process (if you used extern "C) or be considered a foreign exception (if you used extern "C-unwind" or extern "Rust") and catching rust panics in foreign code will cause the next panic on the same thread to abort as double panic due to the panic count not properly getting restored when catching the exception.

I "fully" understand and consider identical memory layouts are not guaranteed for msvc and gnu and that's my main concern: I use a module management system and don't differentiate gnu and msvc right now (only in an internal manner , msvc and gnu versions share the same axis);
as far as panics are concerned, I tend to consider they shouldn't happen in prod(in contrary to dev when they may happen)
So I need to check rustc source code to ensure this is subject to change or not, but I really don't know where to look

It is subject to change. Mixing code compiled for different target triples is explicitly not a supported use case. It may happen to work, and it may even be unlikely to, but this is entirely coincidental and may change without warning for any reason.

Mangled symbols certainly won't be compatible, and the compatibility of global allocator seems a decent candidate for causing “fun” issues.

1 Like

well this is a bit weird despite the above , one can envision a plugin system on windows where the plugin need to be compiled using msvc (the community edition is free but the license may be limiting (5 concurrent users ,< 250 pc or 1million$) and being able to use mingw to develop a plugin when the main application is using msvc is handy (he other way too) : this happens to work as of 1.81.0 it should be ok for future versions : a sound studio with dsp plugins comes in mind , but video processing with nodes as binary plugins pops up along amo

The Rust ABIs x86_64-pc-windows-gnu and x86_64-pc-windows-msvc are not guaranteed to be compatible, ever, for a variety of good reasons. But it's entirely permissible for the two ABIs to define an "FFI" subset that's compatible, even though the full ABI is not; I believe that this is the case already (but would have to check - it is the case if you use the two ABIs for C or C++ DLLs).

If my memory is correct (and I'm old enough that it's not guaranteed to be), these two ABIs have the same #[repr(C)] layouts for data, and compatible extern "C" fn ABIs for #[repr(C)] data. You just have the "normal" Windows DLL fun of making sure that you don't allocate in one module and free in another to handle.

I just finished allocation test from one loaded msvc module and deallocation from the loader(gnu).
The data is a "pretty big" 3Mo image from bevy render to texture (headless bevy)
and is passed to the loader which displays it in Freya-Dioxus ( image2 based on image).
The image is deallocated every frame (once again by the loader) and I don't get memory leaks or it would rapidly exhaust system memory if the image couldn't be deallocated: I get a smooth 144Hz rendering of bevy in a freya-dioxus canvas
I'm right now testing msvc-gnu , msvc-msvc ... combinations and don't get leaks :
Lol, having msvc and gnu not being compatible suddenly after a compiler upgrade would
be a real shame

As long as deallocation is handled by the same ABI as did the allocation, you shouldn't get problems. What's likely to happen is not leaks, but random crashes and other weirdness that you can't explain, because the deallocation in one ABI has damaged the heap tracking structures the other ABI used.

2 Likes

I think both pc-windows targets use the same impl that calls HeapAlloc for System. Assuming that is and remains true, you're at the mercy of Windows for such memory management cross-DLL. Based on my vague recollection, I think it's conditionally okay until you do something like enable the +crt-static target feature.

Either way you're relying on a lot of things from multiple vendors happening to be compatible with each other. It certainly isn't sound by Rust's concept of sound API design.

2 Likes

well , this isn't very far in some ways from a situation where one uses dlltool from mingw (mingw loading msvc case)

The upcoming gnullvm target at least switches the C lib from msvcrt to ucrt, which should reduce the delta against msvc.

2 Likes