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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions