C
C#15mo ago
λshμηarie

C#/C Interop M1 Padding/Alignment Issues

I have a small application I've written to help showcase this issue that I have uploaded to GitHub (https://github.com/Flash619/InteropTest). When calling C methods from C# with a series of complex parameters (size_t, uint32_t, and void *) it seems memory alignment / marshalling is somehow thrown off. When both the DLL and C# are built and executed on intel x64 linux, the interop works flawlessly. However when built and executed on an M1 MacBook, the variables do not match those expected. C# Side [DllImport("clib", EntryPoint = "test_interop", CallingConvention = CallingConvention.Cdecl)] private static extern int test_interop(int number1, int number2, int number3, byte[] data1, int number4, byte[] data2, int number5, int number6, int number7, int number8); C Side int test_interop( const uint32_t number1, const uint32_t number2, const uint32_t number3, const void *data1, const size_t number4, const void *data3, const size_t number5, const size_t number6, const size_t number7, const uint32_t number8 ) Output
SENT: number1: 24 number2: 48 number3: 1223 number4: 86 number5: 108 number6: 132 number7: 1935 number8: 213 RECEIVED: number1: 24 number2: 48 number3: 1223 number4: 86 number5: 108 number6: 132 number7: 914828035983 number8: 1843242248
As you can see above, number7 and number8 are both incorrect, and if I remove arguments it will still be inaccurate in various unpredictable ways... The same code built/executed on linux works flawlessly so I'm sorta confused... Possibly an M1 specific issue due to the varying sizes of size_t and uint32_t?
18 Replies
cap5lut
cap5lut15mo ago
uint32_t would be uint and size_t would be nint on the C# side, besides that i dunno tho
λshμηarie
λshμηarieOP15mo ago
I've tried to play around with nuint and uint but they had the same issue iirc.
reflectronic
reflectronic15mo ago
i mean, int for size_t is definitely wrong it is a long
λshμηarie
λshμηarieOP15mo ago
size_t afaik doesn't directly map to long as size_t depends on the architecture, correct?
reflectronic
reflectronic15mo ago
yes, but it would be a long on x64 or arm64 and, on arm64, multiple parameters can be packed into one register. actually, this is not true, never mind
λshμηarie
λshμηarieOP15mo ago
I've tried using different variable types, long, uint, nuint, etc... the result is the same. Additionally if the variable types were the cause I would expect the same incorrect values to be present on x64 intel linux correct? It works fine on x64 linux...
reflectronic
reflectronic15mo ago
i mean, the problem is pretty clear to me. number7 must be nint, because the function is expecting to read 64 bytes of stack space but the caller only pushes 32 and this also affects number8 since it is expected to be allocated 32 bits later than it is
λshμηarie
λshμηarieOP15mo ago
Why does number 1 through 6 work in that case?
reflectronic
reflectronic15mo ago
on arm64, the first 8 integer arguments are passed in registers, so the size being smaller here does not cause an immediate problem. the later ones are pushed onto the stack and that absolutely will screw up if the size is not correct i would have to look at why it works fine on SysV ABI and i kind of do not want to
λshμηarie
λshμηarieOP15mo ago
So what C# types should I use for uint32_t and size_t then?
reflectronic
reflectronic15mo ago
uint32_t should be uint. though, it doesn't matter for this case if it's int
λshμηarie
λshμηarieOP15mo ago
Why not?
reflectronic
reflectronic15mo ago
size_t sould be nuint, though again the sign does not matter the sign does not change the way it is handled by the ABI and, like, (uint)myInt does not lose or change any data. the value in the processor is identical after the cast. it is just treated differently by code using that value
λshμηarie
λshμηarieOP15mo ago
But didn't you say it needed to be nint for alignment?
reflectronic
reflectronic15mo ago
nint and nuint are identical other than the signedness. which doesn't affect this i mean. it's nice to use the correct type. but i am just saying that nint vs nuint is sort of a red herring, swapping them would not fix or cause a problem here
λshμηarie
λshμηarieOP15mo ago
I'll try to set these to the correct types on the C# side and report back.
reflectronic
reflectronic15mo ago
sorry, i see why you got confused. yes, i should have said nuint to be precise
λshμηarie
λshμηarieOP15mo ago
All numbers checked and passed! Thank you so much!
Want results from more Discord servers?
Add your server