Skip to content

Commit 4008bbd

Browse files
committed
Auto merge of #157977 - folkertdev:miri-zero-valist, r=RalfJung
c-variadic: initialize the copied `VaList` in const-eval Properly initialize the result of `VaList::clone` in `rustc_const_eval`. r? RalfJung cc @theemathas
2 parents 8c75e93 + 7c497ef commit 4008bbd

3 files changed

Lines changed: 71 additions & 1 deletion

File tree

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,13 +725,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
725725

726726
sym::va_copy => {
727727
let va_list = self.deref_pointer(&args[0])?;
728+
728729
let key_mplace = self.va_list_key_field(&va_list)?;
729730
let key = self.read_pointer(&key_mplace)?;
730731

731732
let varargs = self.get_ptr_va_list(key)?;
732733
let copy_key = self.va_list_ptr(varargs.clone());
733734

734-
let copy_key_mplace = self.va_list_key_field(dest)?;
735+
// Zero the destination VaList, so it is fully initialized.
736+
let dest = self.force_allocation(dest)?;
737+
let zeros = std::iter::repeat_n(0u8, dest.layout.size.bytes_usize());
738+
self.write_bytes_ptr(dest.ptr(), zeros)?;
739+
740+
let copy_key_mplace = self.va_list_key_field(&dest)?;
735741
self.write_pointer(copy_key, &copy_key_mplace)?;
736742
}
737743

library/core/src/intrinsics/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3641,6 +3641,10 @@ pub const unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaList<'_>) -> T;
36413641
#[rustc_intrinsic]
36423642
#[rustc_nounwind]
36433643
pub const fn va_copy<'f>(src: &VaList<'f>) -> VaList<'f> {
3644+
// This fallback body exploits the fact that our codegen backends all just use
3645+
// a plain memcpy to duplicate VaList. This assumption is wrong for Miri.
3646+
assert!(!cfg!(miri), "fallback body is incorrect under Miri");
3647+
36443648
src.duplicate()
36453649
}
36463650

src/tools/miri/tests/pass/c-variadic.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//@run-native
12
#![feature(c_variadic)]
23

34
use std::ffi::{CStr, VaList, c_char, c_double, c_int, c_long};
@@ -105,11 +106,70 @@ fn various_types() {
105106
}
106107
}
107108

109+
fn clone() {
110+
if cfg!(force_intrinsic_fallback) {
111+
// Skip this test when we use the fallback bodies. The fallback body does
112+
// not hook into the Miri allocation bookkeeping for variable argument lists
113+
// and would would falsely report UB.
114+
return;
115+
}
116+
117+
unsafe extern "C" fn clone_the_va_list(args: ...) {
118+
// The implicit `drop` will catch a `VaList` that isn't properly initialized.
119+
let _ = args.clone();
120+
}
121+
122+
unsafe { clone_the_va_list(1i32, 2i32) }
123+
}
124+
125+
fn clone_and_advance() {
126+
if cfg!(force_intrinsic_fallback) {
127+
// Skip this test when we use the fallback bodies. The fallback body does
128+
// not hook into the Miri allocation bookkeeping for variable argument lists
129+
// and would would falsely report UB.
130+
return;
131+
}
132+
133+
unsafe extern "C" fn variadic(mut a: ...) {
134+
unsafe {
135+
let mut b = a.clone();
136+
assert_eq!(a.next_arg::<i32>(), 1i32);
137+
assert_eq!(b.next_arg::<i32>(), 1i32);
138+
139+
assert_eq!(a.next_arg::<i32>(), 2i32);
140+
141+
let mut c = a.clone();
142+
let mut d = b.clone();
143+
144+
assert_eq!(a.next_arg::<i32>(), 3i32);
145+
assert_eq!(b.next_arg::<i32>(), 2i32);
146+
assert_eq!(c.next_arg::<i32>(), 3i32);
147+
assert_eq!(d.next_arg::<i32>(), 2i32);
148+
149+
assert_eq!(c.next_arg::<i32>(), 4i32);
150+
assert_eq!(a.next_arg::<i32>(), 4i32);
151+
152+
drop(c);
153+
drop(a);
154+
155+
assert_eq!(d.next_arg::<i32>(), 3i32);
156+
assert_eq!(d.next_arg::<i32>(), 4i32);
157+
158+
assert_eq!(b.next_arg::<i32>(), 3i32);
159+
assert_eq!(b.next_arg::<i32>(), 4i32);
160+
}
161+
}
162+
163+
unsafe { variadic(1i32, 2i32, 3i32, 4i32) }
164+
}
165+
108166
fn main() {
109167
ignores_arguments();
110168
echo();
111169
forward_by_val();
112170
forward_by_ref();
113171
nested();
114172
various_types();
173+
clone();
174+
clone_and_advance();
115175
}

0 commit comments

Comments
 (0)