Skip to content

Miscompilation of code in or around Iterator::position #161

@benhansen-io

Description

@benhansen-io

I tried this code (also available at https://github.com/benhansen-io/esp-miscompile-test)

use esp_idf_sys as _; // If using the `libstart` feature of `esp-idf-sys`, always keep this module imported

#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct RGB {
    r: u8,
    g: u8,
    b: u8,
}

impl RGB {
    fn new(r: u8, g: u8, b: u8) -> RGB {
        RGB { r, g, b }
    }
}

fn next_color(curr: RGB, order: &[RGB]) -> RGB {
    let curr_idx = order
        .iter()
        .position(|c| {
            // println!("UNCOMMENT TO STOP PANIC");
            *c == curr
        })
        .unwrap();
    let next_idx = if curr_idx == order.len() - 1 {
        0
    } else {
        curr_idx + 1
    };
    order[next_idx]
}

#[no_mangle]
extern "C" fn rust_main() -> i32 {
    // Temporary. Will disappear once ESP-IDF 4.4 is released, but for now it is necessary to call this function once,
    // or else some patches to the runtime implemented by esp-idf-sys might not link properly.
    esp_idf_sys::link_patches();

    let green: RGB = RGB::new(0, 255, 0);
    let blue: RGB = RGB::new(0, 0, 255);
    let yellow: RGB = RGB::new(255, 255, 0);

    let color_order = [yellow, blue, green];
    let mut curr = yellow;
    println!("Starting");
    loop {
        println!("curr: {:?}", curr);
        curr = next_color(curr, &color_order);
        println!("next: {:?}", curr);
        std::thread::sleep(std::time::Duration::from_millis(500));
    }
}

I expected to see this happen:

2023-02-15 20:44:15 Hello world from C!
2023-02-15 20:44:15 Starting
2023-02-15 20:44:15 curr: RGB { r: 255, g: 255, b: 0 }
2023-02-15 20:44:15 next: RGB { r: 0, g: 0, b: 255 }
2023-02-15 20:44:15 curr: RGB { r: 0, g: 0, b: 255 }
2023-02-15 20:44:16 next: RGB { r: 0, g: 255, b: 0 }
2023-02-15 20:44:16 curr: RGB { r: 0, g: 255, b: 0 }
2023-02-15 20:44:16 next: RGB { r: 255, g: 255, b: 0 }
2023-02-15 20:44:16 curr: RGB { r: 255, g: 255, b: 0 }
...

Instead, this happened:

2023-02-15 20:43:28 Hello world from C!                                                                                                                         
2023-02-15 20:43:28 Starting                                                                                                                                    
2023-02-15 20:43:28 curr: RGB { r: 255, g: 255, b: 0 }                                                                                                          
2023-02-15 20:43:28 next: RGB { r: 0, g: 0, b: 255 }                                                                                                            
2023-02-15 20:43:28 curr: RGB { r: 0, g: 0, b: 255 }                                                                                                            
2023-02-15 20:43:28 ESP-ROM:esp32s3-20210327
2023-02-15 20:43:29 curr: RGB { r: 0, g: 0, b: 255 }
2023-02-15 20:43:29 ESP-ROM:esp32s3-20210327
2023-02-15 20:43:30 curr: RGB { r: 0, g: 0, b: 255 }
2023-02-15 20:43:30 ESP-ROM:esp32s3-20210327
...

Without panic abort immediate I also see:

2023-02-15 20:49:27 thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:23:10

Adding the commented out println! or removing the opt-level = "s" both cause the correct output to be displayed.

Meta

rustc --version --verbose:

rustc 1.65.0 (897e37553 2022-11-02)
binary: rustc
commit-hash: 897e37553bba8b42751c67658967889d11ecd120
commit-date: 2022-11-02
host: x86_64-unknown-linux-gnu
release: 1.65.0
LLVM version: 15.0.0

(tested on 1.67.0 too)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions