Skip to content

Incorrectly generated code for struct alignments #23431

Closed
@AerialX

Description

@AerialX

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,
}

Metadata

Metadata

Assignees

Labels

A-codegenArea: Code generation

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions