Unexpected return value in 32bit DLL

When building a cdylib crate with stable-i686-pc-windows-msvc toolchain (rustc 1.44.1) the return value of an extern function is a random number and not i8 as expected.

This is the function:

#[no_mangle]
pub extern "system" fn balloon(p1: u16) -> i8 {
    println!("p1: {}", p1);
    8
}

Because I refused to write C/C++/C# I used Python (32bit) to consume the library on a Windows 10 (10.0.18363 / 64bit).
This is my python script:

import ctypes

dll = ctypes.WinDLL("z:\\balloon-x86.dll")

result = int(dll.balloon(ctypes.c_uint(18)))

print("Result: " + str(result))

Obviously I expected 8 as return value, but this is the output:

PS Z:\> python test.py
p1: 18
Result: 16646152 

The number after Result: is always changing.

You will find the source code as well as a DLL in the following repo: https://github.com/ChriFo/balloon

I am very thankful for an explanation why this happens!

1 Like

i8 is 1 byte (signed).
c_uint is 4 bytes (unsigned).
16646152 = 0xFE0008: the 8 is there (+garbage from the stack).

The result is correct, it's just the types don't match.
You can make Rust match Python by returning a u32 instead. The same thing would happen if the parameter you pass is over 0xffff for the same reason.

You don't need to cast the integer argument.

None , integers, bytes objects and (unicode) strings are the only native Python objects that can directly be used as parameters in these function calls .. Python integers are passed as the platforms default C int type, their value is masked to fit into the C type.

So you can call the function as:

dll.balloon(18)

You can also set the return type explicitly:

balloon = dll.balloon
balloon.restype = ctypes.c_byte

result = balloon(18)

print("Result: " + str(result))

Although, your original example printed 8 for me, so I couldn't test if setting the integer return type in Python would help. According to this table, c_byte still corresponds to Python's int.

Edit: I tested your original example with a debug build of the .DLL. When I tested with a release build, I was able to reproduce the random value. Setting balloon.restype = ctypes.c_byte printed 8 on the release build, so try that out.

1 Like

Thank you @naim and @Safe

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.