Skip to content

Calls to BitSlice::set_aliased and BitSlice::set_aliased_unchecked on Cell<u8> is deleted completely by optimizer in release mode #283

Description

@royaltm

Hello @myrrlyn

bitvec: v1.0.1

I think I stumbled upon a strange and nasty bug, where the outcome is different in rustc DEV versus RELEASE compilation profile.

The minimal test example which passes in DEV while fails in RELEASE:

use std::cell::Cell;
use bitvec::prelude::*;

#[test]
fn test_cell_bitvec() {
    let cell: Cell<u8> = Cell::new(0);

    for index in 0..8 {
        assert_eq!(*cell.view_bits::<Lsb0>().get(index).unwrap(), false);
    }

    for index in 0..8 {
        cell.view_bits::<Lsb0>().set_aliased(index, true);
    }

    for index in 0..8 {
        assert_eq!(*cell.view_bits::<Lsb0>().get(index).unwrap(), true);
    }
}

#[test]
fn test_cell_bitvec_unchecked() {
    let cell: Cell<u8> = Cell::new(0);

    for index in 0..8 {
        assert_eq!(*unsafe { cell.view_bits::<Lsb0>().get_unchecked(index) }, false);
    }

    for index in 0..8 {
        unsafe { cell.view_bits::<Lsb0>().set_aliased_unchecked(index, true) }
    }

    for index in 0..8 {
        assert_eq!(*unsafe { cell.view_bits::<Lsb0>().get_unchecked(index) }, true);
    }
}

When tested with --release flag both tests fail as if set_alias and set_alias_unchecked was never called:

running 2 tests
test tests::test_cell_bitvec ... FAILED
test tests::test_cell_bitvec_unchecked ... FAILED

failures:

---- tests::test_cell_bitvec stdout ----
thread 'tests::test_cell_bitvec' panicked at src/main.rs:36:13:
assertion `left == right` failed
  left: false
 right: true
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- tests::test_cell_bitvec_unchecked stdout ----
thread 'tests::test_cell_bitvec_unchecked' panicked at src/main.rs:53:13:
assertion `left == right` failed
  left: false
 right: true


failures:
    tests::test_cell_bitvec
    tests::test_cell_bitvec_unchecked

test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

If I replace Cell<u8> with any other primitive type: Cell<u16|u32|u64|usize> the test does not fail in RELEASE mode. This only happens for Cell<u8>!

The only workaround I found so far is to replace Cell<u8> with AtomicU8 which is not ideal as I'm using it in a single threaded environment.

This happens regardless of the platform, as I first detected the problem on thumbv7em but later I confirmed the same is happening on x86_64.

The bug is quite nasty and can give you headaches when trying to debug this, especially that it works fine in DEV and only manifests when optimizations are turned on.

Moreover it does not matter what kind of opt-level is enabled as long as it's equal to or above opt-level = 1 for profile.release.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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