I have created this simple reproducer program, which allocates a libusb transfer and then calls libusb_set_iso_packet_lengths on it:
use std::ptr::null_mut;
use rusb::ffi::{
libusb_alloc_transfer, libusb_fill_iso_transfer, libusb_set_iso_packet_lengths, libusb_transfer,
};
fn main() {
let transfer = unsafe { libusb_alloc_transfer(32) };
if transfer.is_null() {
panic!("Failed to allocate transfer");
}
extern "system" fn callback(transfer: *mut libusb_transfer) {}
unsafe {
libusb_fill_iso_transfer(
transfer,
null_mut(),
0,
null_mut(),
0,
32, // num_iso_packets, set to the same value as allocated
callback,
std::ptr::null_mut(),
5000,
);
}
unsafe { libusb_set_iso_packet_lengths(transfer, 2137) };
}
To my surprise this code works without panicking on current stable rust (1.77.1), but panics inside of libusb_set_iso_packet_lengths on nightly (2024-03-27). These are the logs:
thread 'main' panicked at library/core/src/panicking.rs:152:5:
unsafe precondition(s) violated: slice::get_unchecked_mut requires that the index is within the slice
stack backtrace:
0: rust_begin_unwind
at /rustc/c9f8f3438a8134a413aa5d4903e0196e44e37bbc/library/std/src/panicking.rs:646:5
1: core::panicking::panic_nounwind_fmt::runtime
at /rustc/c9f8f3438a8134a413aa5d4903e0196e44e37bbc/library/core/src/panicking.rs:110:18
2: core::panicking::panic_nounwind_fmt
at /rustc/c9f8f3438a8134a413aa5d4903e0196e44e37bbc/library/core/src/panicking.rs:120:5
3: core::panicking::panic_nounwind
at /rustc/c9f8f3438a8134a413aa5d4903e0196e44e37bbc/library/core/src/panicking.rs:152:5
4: <usize as core::slice::index::SliceIndex<[T]>>::get_unchecked_mut::precondition_check
at /rustc/c9f8f3438a8134a413aa5d4903e0196e44e37bbc/library/core/src/ub_checks.rs:66:21
5: <usize as core::slice::index::SliceIndex<[T]>>::get_unchecked_mut
at /rustc/c9f8f3438a8134a413aa5d4903e0196e44e37bbc/library/core/src/slice/index.rs:236:9
6: core::slice::<impl [T]>::get_unchecked_mut
at /rustc/c9f8f3438a8134a413aa5d4903e0196e44e37bbc/library/core/src/slice/mod.rs:728:24
7: libusb1_sys::libusb_set_iso_packet_lengths
at /home/alufers/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libusb1-sys-0.6.4/src/lib.rs:661:9
8: repro_libusb_panic::main
at ./examples/repro_libusb_panic.rs:28:14
9: core::ops::function::FnOnce::call_once
at /rustc/c9f8f3438a8134a413aa5d4903e0196e44e37bbc/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
thread caused non-unwinding panic. aborting.
[1] 137247 IOT instruction (core dumped) RUST_BACKTRACE=1 cargo run --example repro_libusb_panic
It appears that rust started adding runtime checks to unchecked unsafe functions (https://github.com/rust-lang/rust/issues/120848), and it breaks libusb_set_iso_packet_lengths which calls get_unchecked_mut on a zero length slice.
Hi!
I have created this simple reproducer program, which allocates a libusb transfer and then calls
libusb_set_iso_packet_lengths
on it:To my surprise this code works without panicking on current stable rust (1.77.1), but panics inside of
libusb_set_iso_packet_lengths
on nightly (2024-03-27). These are the logs:I have bisected it with cargo-bisect-rustc, and this is the rust commit that breaks this function https://github.com/rust-lang/rust/commit/2b43e75c98cc5ae32328c8b49657bcd882eb5e75
It appears that rust started adding runtime checks to unchecked unsafe functions (https://github.com/rust-lang/rust/issues/120848), and it breaks
libusb_set_iso_packet_lengths
which callsget_unchecked_mut
on a zero length slice.