Description
The attached source produces code that misbehaves on some platforms that are picky about memory access alignment. The code should exit with code 2, but on both Emscripten-generated JavaScript and ARMv5, it finishes with exit code 1 to indicate that the en
field is incorrectly tested as equal to Enum::A
. Changing the val
field to a u32
type results in proper execution on these platforms. All optimization levels seem to cause it.
Libraries that make use of structs with u8
fields followed by enums seem particularly prone to this problem. It all works fine on platforms that allow unaligned memory access like x86, ARMv6, etc.
Expected output: (x86, ARMv6)
test: Test { val: 1, en: B }
testvalue: B
Actual output: (ARMv5, Emscripten)
test: Test { val: 0, en: A }
testvalue: A
Note that the same ARM binary runs on both ARMv5 and ARMv6 platforms, producing the different results.
See also: emscripten-core/emscripten#3261
Generated LLVM IR (println!()
and derive(Debug)
removed)
#![feature(start)]
#[inline(never)]
fn testvalue(e: Enum) -> isize {
println!("testvalue: {:?}", e);
let mut ch = 0;
match &e {
&Enum::A => ch = 1,
&Enum::B => ch = 2,
&Enum::C(_) => (),
};
ch
}
#[inline(never)]
fn clonetest(k: Test) -> Test {
k.clone()
}
#[inline(never)]
#[start]
fn main(_: isize, _: *const *const u8) -> isize {
let test = Test {
val: 1,
en: Enum::B,
};
let test = clonetest(test.clone());
println!("test: {:?}", test);
testvalue(test.en)
}
#[derive(Debug, Copy, Clone)]
pub enum Enum {
A,
B,
C(u16)
}
#[derive(Debug, Copy, Clone)]
pub struct Test {
pub val: u8,
pub en: Enum,
}