Skip to content

slice-deque: SliceDeque::as_slices and as_mut_slices can violate slice alignment preconditions for T with alignment > 1 #14

Description

@kaixinlalala

Summary

I have used afl.rs to fuzz the public APIs of this crate. When calling SliceDeque::as_slices and SliceDeque::as_mut_slices on an empty SliceDeque<i32>, the function triggers a runtime abort due to a violated unsafe precondition inside slice::from_raw_parts and slice::from_raw_parts_mut.

The panic happens inSliceDeque::as_slices and SliceDeque::as_mut_slices , where the empty second slice is constructed from usize::max_value() as *const _. Even for a zero-length slice, slice::from_raw_parts and slice::from_raw_parts_mut requires the pointer to be non-null and properly aligned for T. For T = i32, usize::MAX as *const i32 is not properly aligned.

Reproduction code

extern crate slice_deque;
fn main() {
    let mut d = slice_deque::SliceDeque::<i32>::new();
    d.push_back(1);
    d.push_back(2);
    let (left, right) = d.as_slices();
    assert_eq!(left, &[1, 2]);
    assert_eq!(right, &[]);
}
extern crate slice_deque;
fn main() {
    let mut d = slice_deque:: SliceDeque::<i32>::with_capacity(0);
    let _ = d.as_mut_slices();
    assert_eq!(left, &[]);
    assert_eq!(right, &[]);
}

I also placed the replay files at replay_files).

Expected behavior:

should return two valid slices without panicking, aborting, or violating unsafe preconditions.

For the example above, the expected result is:

left == &[1, 2]
right == &[]
left == &[]
right == &[]

Actual behavior for as_slices:

thread 'main' panicked at /Rust-Lib-Testing/test/tests/crates/slice-deque-0.3.0/src/lib.rs:492:17:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`

This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
stack backtrace:
   0:     0x558db501ddf8 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h0f9d2e8e73f1bc7d
   1:     0x558db5059183 - core::fmt::write::h2b15537d64ec9505
   2:     0x558db504664f - std::io::Write::write_fmt::h7f766131a16fe05a
   3:     0x558db501dc43 - std::sys::backtrace::BacktraceLock::print::h5e38585c963961db
   4:     0x558db5018a6c - std::panicking::default_hook::{{closure}}::h7a475a2b7b7e4121
   5:     0x558db501890d - std::panicking::default_hook::hac0f4b95d0cecbc2
   6:     0x558db5018f41 - std::panicking::rust_panic_with_hook::hb51ba0f67890aa28
   7:     0x558db501e1a6 - std::panicking::begin_panic_handler::{{closure}}::h73d0277a9a02463b
   8:     0x558db501e019 - std::sys::backtrace::__rust_end_short_backtrace::hf93dae6c307b4fe8
   9:     0x558db5018b5d - __rustc[b6f6af4e11d2f413]::rust_begin_unwind
  10:     0x558db505812d - core::panicking::panic_nounwind_fmt::h102b43c20952100b
  11:     0x558db50149e9 - core::slice::raw::from_raw_parts::precondition_check::h73250b4aea4062ac
                               at /Rust-Lib-Testing/test/src/rust/library/core/src/ub_checks.rs:72:21
  12:     0x558db5016137 - core::slice::raw::from_raw_parts::h8e67de28ac319893
                               at /Rust-Lib-Testing/test/src/rust/library/core/src/ub_checks.rs:77:17
  13:     0x558db5015fc0 - slice_deque::SliceDeque<T>::as_slices::hed85916b50ed7650
                               at /Rust-Lib-Testing/test/tests/crates/slice-deque-0.3.0/src/lib.rs:492:17
  14:     0x558db501434c - replay_slice_deque1::main::h2abf81457f189292
                               at /Rust-Lib-Testing/test/tests/crates/slice-deque-0.3.0/fuzz_target/slice_deque_importance_fuzz/multipleTargets/replay_slice_deque1/src/main.rs:6:27
  15:     0x558db5013fab - core::ops::function::FnOnce::call_once::h127d8f7ae5af77f8
                               at /Rust-Lib-Testing/test/src/rust/library/core/src/ops/function.rs:253:5
  16:     0x558db501621e - std::sys::backtrace::__rust_begin_short_backtrace::h09b6bd66fc288ce6
                               at /Rust-Lib-Testing/test/src/rust/library/std/src/sys/backtrace.rs:158:18
  17:     0x558db50161f1 - std::rt::lang_start::{{closure}}::h82f416d938689675
                               at /Rust-Lib-Testing/test/src/rust/library/std/src/rt.rs:206:18
  18:     0x558db5045645 - std::rt::lang_start_internal::h9de2b5630c7cec4d
  19:     0x558db50161d7 - std::rt::lang_start::h01ad6e2ad60a32fa
                               at /Rust-Lib-Testing/test/src/rust/library/std/src/rt.rs:205:5
  20:     0x558db501448e - main
  21:     0x7fa7814aa083 - __libc_start_main
                               at /build/glibc-B3wQXB/glibc-2.31/csu/../csu/libc-start.c:308:16
  22:     0x558db50136de - _start
  23:                0x0 - <unknown>
thread caused non-unwinding panic. aborting.
Aborted

Actual behavior for as_mut_slices:

This also aborts with a similar unsafe precondition violation.

Additional observation:

This behavior depends on the alignment requirement of T.

For example, with T=i8, the same code does not trigger precondition failure, because i8 has alignment 1, and usize::MAX happens to satisfy that alignment requirement.

However, with T=i32, usize::MAX as *const T is not properly aligned, so slice::from_raw_parts and slice::from_raw_parts_mut aborts under Rust's UB checks.

Environment:

slice-deque version: 0.3.0

rustc version: 1.94.1

OS: Ubuntu 20.04.6 LTS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions