Skip to content

Accesses to alloca buffers in translated code can cause UB #1954

Description

@AlexTMjugador

Currently, c2rust translates functions that call alloca to set up and read from a [c2rust_]alloca_allocations: Vec<Vec<u8>> variable:

// If `alloca` was used in the function body, include a variable to hold the
// allocations.
if let Some(alloca_allocations_name) = self
.function_context
.borrow_mut()
.alloca_allocations_name
.take()
{
// let mut c2rust_alloca_allocations: Vec<Vec<u8>> = Vec::new();
let inner_vec = mk().path_ty(vec![mk().path_segment_with_args(
"Vec",
mk().angle_bracketed_args(vec![mk().ident_ty("u8")]),
)]);
let outer_vec = mk().path_ty(vec![mk().path_segment_with_args(
"Vec",
mk().angle_bracketed_args(vec![inner_vec]),
)]);
let alloca_allocations_stmt = mk().local_stmt(Box::new(mk().local(
mk().mutbl().ident_pat(alloca_allocations_name),
Some(outer_vec),
Some(mk().call_expr(mk().path_expr(vec!["Vec", "new"]), vec![])),
)));
body_stmts.push(alloca_allocations_stmt);
}

However, when the Vec<u8> backing buffer of an allocation is used to access types with stricter alignment requirements than u8, such as f32, undefined behavior can occur.

I ran into this while experimenting with transpiling libvorbis to Rust for use by my vorbis_rs library, where Miri correctly reported the following in the place where an alloca buffer was used:

    error: Undefined Behavior: accessing memory based on pointer with alignment 1, but alignment 4 is required
     --> packages/vorbis_c2rust_sys/src/lib/psy.rs:573:4
      |
      = note: 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: this is on thread `issue_17`
      = note: stack backtrace:
              0: vorbis_c2rust_sys::lib::psy::setup_tone_curves
                  at packages/vorbis_c2rust_sys/src/lib/psy.rs:573:5: 573:48
              1: vorbis_c2rust_sys::lib::psy::_vp_psy_init
                  at packages/vorbis_c2rust_sys/src/lib/psy.rs:902:20: 909:3
              2: vorbis_c2rust_sys::lib::block::_vds_shared_init
                  at packages/vorbis_c2rust_sys/src/lib/block.rs:728:4: 735:5
              3: vorbis_c2rust_sys::lib::block::vorbis_analysis_init
                  at packages/vorbis_c2rust_sys/src/lib/block.rs:836:5: 836:53
              4: vorbis_rs::encoder::encoder_util::VorbisEncodingState::new
                  at packages/vorbis_rs/src/common/error.rs:258:22: 258:38
              5: vorbis_rs::VorbisEncoderBuilder::<&mut std::vec::Vec<u8>>::build
                  at packages/vorbis_rs/src/encoder/encoder_impl.rs:241:35: 241:72
              6: issue_17
                  at packages/vorbis_rs/tests/regression_tests.rs:11:20: 17:10
              7: issue_17::{closure#0}
                  at packages/vorbis_rs/tests/regression_tests.rs:9:14: 9:14

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

I have a hunch that the most appropriate fix would be to use unaligned read methods when reading from an alloca buffer.

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