Repository navigation
Accesses to alloca buffers in translated code can cause UB #1954
Copy link
Copy link
Open
Description
Currently, c2rust translates functions that call alloca to set up and read from a [c2rust_]alloca_allocations: Vec<Vec<u8>> variable:
c2rust/c2rust-transpile/src/translator/functions.rs
Lines 217 to 241 in 90b216e
| // 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.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
Rua commentedon Jul 27, 2026
How does C deal with this? It doesn't have any information about the required alignment, so does it just assume a relatively high alignment by default?
AlexTMjugador commentedon Jul 27, 2026
I think C deals with this by simply not providing a consistent contractual guarantee, since
allocais not a standard function.That said, Microsoft's C runtime documents that
_allocareturns memory that is "suitably aligned for storage of any type of object". By contrast, the Linuxalloca(3)man page makes no guarantees about alignment, but notes that it is implemented "by necessity" in terms of the__builtin_allocacompiler intrinsic, which I verified is howmuslimplements it. FreeBSD's man page doesn't mention either alignment nor any compiler intrinsics.In turn, Clang's documentation for
__builtin_allocalikewise says nothing about alignment. However, Clang also provides a__builtin_alloca_with_alignintrinsic with well-defined alignment semantics, and I found code suggesting that the unqualified intrinsic assumes the biggest required alignment.Naturally, GCC also has an equivalent pair of intrinsics, although their documentation is even sparser than Clang's. I also found code suggesting that the unqualified intrinsic assumes the biggest required alignment.
So, in practice, I think C code that uses
allocaand targets common C library implementations and compilers is safe with respect to alignment because these implementations have converged on treatingallocaas providing a suitable alignment for any object, even though this behavior is largely an informal convention rather than a well-documented contractual guarantee, except in Microsoft's C runtime.