Skip to content

Unsound Offset implementation allows cross-allocation pointer arithmetic in BSlice #5

@DiuDiu777

Description

@DiuDiu777

Hi!

The issue occurs when BSlice values constructed from different underlying allocations are passed to the Offset implementation provided by nom.

Affected Versions

bitvec_nom2 = 0.2.x
bitvec = 1.0.1
nom = 7.1.3
rustc nightly-2025-12-06

Proof of Concept

use bitvec_nom2::BSlice;
use bitvec::prelude::*;
use nom::Offset;

fn main() {
    // Two independent allocations
    let array_a = [0u8; 4];
    let array_b = [0u8; 4];

    // BitSlice views
    let slice_a = array_a.view_bits::<Lsb0>();
    let slice_b = array_b.view_bits::<Lsb0>();

    // Construct BSlice values
    let bslice_a = BSlice(slice_a);
    let bslice_b = BSlice(slice_b);

    println!("Triggering unsound offset computation...");

    // Safe API triggering UB
    let diff = bslice_a.offset(&bslice_b);

    println!("Computed offset: {}", diff);
}

Miri Output
cargo miri run

error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
    --> /Users/lemonj/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wyz-0.5.1/src/comu.rs:305:2
     |
 305 | /     map! {
 306 | |         @unsafe offset_from, origin: Self as |orig| orig.to_const() as *mut T => isize;
 307 | |         @unsafe read => T;
 308 | |         @unsafe read_volatile => T;
...    |
 312 | |         align_offset, align: usize => usize;
 313 | |     }
     | |_____^ Undefined Behavior occurred here
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
     = note: BACKTRACE:
     = note: inside `wyz::comu::Address::<bitvec::ptr::Const, u8>::offset_from` at /Users/lemonj/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wyz-0.5.1/src/comu.rs:285:4: 285:55
     = note: inside `bitvec::ptr::BitPtr::<bitvec::ptr::Const, u8>::offset_from::<u8>` at /Users/lemonj/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bitvec-1.0.1/src/ptr/single.rs:684:3: 686:52
     = note: inside `bitvec_nom2::input::<impl nom::Offset for bitvec_nom2::BSlice<'_, u8, bitvec::order::Lsb0>>::offset` at /Users/lemonj/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bitvec-nom2-0.2.1/src/input.rs:42:18: 42:70
note: inside `main`
    --> src/main.rs:1570:16
     |
1570 |     let diff = bslice_a.offset(&bslice_b);
     |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
     = note: this error originates in the macro `map` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error; 2 warnings emitted

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