Skip to content

Wrong code generated for Android ARM with optimisations #22776

Description

@romanb

There appears to be a case that looks like optimisations resulting in bad code to be generated for Android ARM. This issue demonstrates the problem in the context where I ran into it, using the byteorder library.

Test environment

  • Host OS: OSX 10.9.5
  • Android SDK
  • Android NDK (Revision 10d) with standalone toolchain according to the wiki.
  • Android Emulator: ARM (armeabi-v7a), Android 5.0.1 (API level 21)
  • rustc 1.0.0-dev (built 2015-02-23), configured for cross-compilation to the arm-linux-androideabi target.

Steps to reproduce

  1. Clone byteorder. Checkout commit d9259c15a4b18de37d765aebbe5034f282772b84.

  2. Create main.rs:

    use byteorder::{BigEndian, WriteBytesExt};
    
    extern crate byteorder;
    
    fn main() {
        let mut v_16: Vec<u8> = Vec::new();
        v_16.write_u16::<BigEndian>(64_u16).unwrap();
        println!("u16_be: {:?}", v_16);
    
        let mut v_32: Vec<u8> = Vec::new();
        v_32.write_u32::<BigEndian>(64_u32).unwrap();
        println!("u32_be: {:?}", v_32);
    
        let mut v_64: Vec<u8> = Vec::new();
        v_64.write_u64::<BigEndian>(64_u64).unwrap();
        println!("u64_be: {:?}", v_64);
    }
    
  3. Build

    mkdir target
    # Build byteorder
    rustc -C opt-level=3 --target=arm-linux-androideabi -C linker=arm-linux-androideabi-gcc -C ar=arm-linux-androideabi-ar --crate-type lib --out-dir target/ --emit=dep-info,link /path/to/byteorder/src/lib.rs
    # Build main.rs
    rustc -C opt-level=3 --target=arm-linux-androideabi -C linker=arm-linux-androideabi-gcc -C link-args=-pie --crate-type bin -Ltarget --out-dir target/ ./main.rs
    
  4. Run on emulator

    adb push target/main /some/writeable/dir/main
    adb shell /some/writeable/dir/main
    
  5. Output

    Expected:

    u16_be: [0, 64]
    u32_be: [0, 0, 0, 64]
    u64_be: [0, 0, 0, 0, 0, 0, 0, 64]
    

    Actual (sample):

    u16_be: [253, 182]
    u32_be: [57, 0, 0, 0]
    u64_be: [244, 102, 251, 255, 57, 0, 0, 0]
    

Workarounds

There seem to be two ways to work around the problem:

  1. Apply the following patch to byteorder

    diff --git a/src/lib.rs b/src/lib.rs
    index 009a780..8e6f37d 100644
    --- a/src/lib.rs
    +++ b/src/lib.rs
    @@ -265,8 +265,8 @@ macro_rules! write_num_bytes {
    
             assert!($dst.len() >= $size); // critical for memory safety!
             unsafe {
    -            let bytes = (&transmute::<_, [u8; $size]>($n.$which())).as_ptr();
    -            copy_nonoverlapping_memory($dst.as_mut_ptr(), bytes, $size);
    +            let bytes = transmute::<_, [u8; $size]>($n.$which());
    +            copy_nonoverlapping_memory($dst.as_mut_ptr(), (&bytes).as_ptr(), $size);
             }
         });
     }
    
  2. Turn off optimizations (opt-level).

Further Details

The following is the output for the relevant functions (write_u16, write_u32 and write_u64) of compiling byteorder using --emit=llvm-ir with and without the above patch.

Without the patch: https://gist.github.com/romanb/2ff2ebb474c87103e631
With the patch: https://gist.github.com/romanb/d419ba4882d9c489c494

Metadata

Metadata

Assignees

No one assigned

    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