Pointer becomes misaligned in test with `no_mangle`

I have a piece of code that looks like this:

// lib.rs

#[unsafe(no_mangle)]
pub unsafe extern "C" fn read(args: *const *const u8) -> u64 {
    assert!(args.is_aligned());
    0
}

When no_mangle is present, cargo test fails like this (though there isn't even a test anywhere):

thread 'main' panicked at src/lib.rs:5:5:
assertion failed: args.is_aligned()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

thread 'main' panicked at library/core/src/panicking.rs:218:5:
panic in a function that cannot unwind
stack backtrace:
panicked at src/lib.rs:5:5:
assertion failed: args.is_aligned()
thread panicked while processing panic. aborting.

Removing no_mangle fixes it.

I'm very confused, what is going on here?

the symbol read is conflicting with libc, but apparently they have different type signature, so it is called with nonsense arguments.

remember, C symbols all exists in a global namespace and because they are not mangled with the type signature, it is common for C libraries to add prefixes to symbols (poor man's "namespace"), just to avoid conflicts like these.

5 Likes

Wow, that makes a lot of sense, I should have thought about that!

In fact, the ability to override existing symbols like that is why the no_mangle annotation is unsafe.

3 Likes

I guess the error could have been better in that case, it wasn't immediately clear what is going on there. I'd expect some kind of linking error or something, but got runtime panic instead.

Unfortunately Rust has no control over that. You can complain to your linker.

1 Like