Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 0193a5a

Browse files
authored
Merge pull request rust-lang#4181 from tiif/check_shim_variadic
Throw ub error when invoking non-vararg shim with vararg import
2 parents fd11306 + af04c0d commit 0193a5a

15 files changed

+129
-101
lines changed

src/tools/miri/src/helpers.rs

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
999999
&'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
10001000
{
10011001
self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
1002-
check_arg_count(args)
1002+
1003+
if abi.c_variadic {
1004+
throw_ub_format!(
1005+
"calling a non-variadic function with a variadic caller-side signature"
1006+
);
1007+
}
1008+
if let Ok(ops) = args.try_into() {
1009+
return interp_ok(ops);
1010+
}
1011+
throw_ub_format!(
1012+
"incorrect number of arguments for `{link_name}`: got {}, expected {}",
1013+
args.len(),
1014+
N
1015+
)
10031016
}
10041017

10051018
/// Check shim for variadic function.
@@ -1015,7 +1028,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10151028
&'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
10161029
{
10171030
self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
1018-
check_vargarg_fixed_arg_count(link_name, abi, args)
1031+
1032+
if !abi.c_variadic {
1033+
throw_ub_format!(
1034+
"calling a variadic function with a non-variadic caller-side signature"
1035+
);
1036+
}
1037+
if abi.fixed_count != u32::try_from(N).unwrap() {
1038+
throw_ub_format!(
1039+
"incorrect number of fixed arguments for variadic function `{}`: got {}, expected {N}",
1040+
link_name.as_str(),
1041+
abi.fixed_count
1042+
)
1043+
}
1044+
if let Some(args) = args.split_first_chunk() {
1045+
return interp_ok(args);
1046+
}
1047+
panic!("mismatch between signature and `args` slice");
10191048
}
10201049

10211050
/// Mark a machine allocation that was just created as immutable.
@@ -1199,7 +1228,7 @@ impl<'tcx> MiriMachine<'tcx> {
11991228
}
12001229

12011230
/// Check that the number of args is what we expect.
1202-
pub fn check_arg_count<'a, 'tcx, const N: usize>(
1231+
pub fn check_intrinsic_arg_count<'a, 'tcx, const N: usize>(
12031232
args: &'a [OpTy<'tcx>],
12041233
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]>
12051234
where
@@ -1208,7 +1237,11 @@ where
12081237
if let Ok(ops) = args.try_into() {
12091238
return interp_ok(ops);
12101239
}
1211-
throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
1240+
throw_ub_format!(
1241+
"incorrect number of arguments for intrinsic: got {}, expected {}",
1242+
args.len(),
1243+
N
1244+
)
12121245
}
12131246

12141247
/// Check that the number of varargs is at least the minimum what we expect.
@@ -1228,34 +1261,6 @@ pub fn check_min_vararg_count<'a, 'tcx, const N: usize>(
12281261
)
12291262
}
12301263

1231-
/// Check the number of fixed args of a vararg function.
1232-
/// Returns a tuple that consisting of an array of fixed args, and a slice of varargs.
1233-
fn check_vargarg_fixed_arg_count<'a, 'tcx, const N: usize>(
1234-
link_name: Symbol,
1235-
abi: &FnAbi<'tcx, Ty<'tcx>>,
1236-
args: &'a [OpTy<'tcx>],
1237-
) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])> {
1238-
if !abi.c_variadic {
1239-
throw_ub_format!("calling a variadic function with a non-variadic caller-side signature");
1240-
}
1241-
if abi.fixed_count != u32::try_from(N).unwrap() {
1242-
throw_ub_format!(
1243-
"incorrect number of fixed arguments for variadic function `{}`: got {}, expected {N}",
1244-
link_name.as_str(),
1245-
abi.fixed_count
1246-
)
1247-
}
1248-
if let Some(args) = args.split_first_chunk() {
1249-
return interp_ok(args);
1250-
}
1251-
throw_ub_format!(
1252-
"incorrect number of arguments for `{}`: got {}, expected at least {}",
1253-
link_name.as_str(),
1254-
args.len(),
1255-
N
1256-
)
1257-
}
1258-
12591264
pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> {
12601265
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
12611266
"{name} not available when isolation is enabled",

src/tools/miri/src/intrinsics/atomic.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_middle::mir::BinOp;
22
use rustc_middle::{mir, ty};
33

4-
use self::helpers::check_arg_count;
4+
use self::helpers::check_intrinsic_arg_count;
55
use crate::*;
66

77
pub enum AtomicOp {
@@ -131,7 +131,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
131131
) -> InterpResult<'tcx> {
132132
let this = self.eval_context_mut();
133133

134-
let [place] = check_arg_count(args)?;
134+
let [place] = check_intrinsic_arg_count(args)?;
135135
let place = this.deref_pointer(place)?;
136136

137137
// Perform atomic load.
@@ -144,7 +144,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
144144
fn atomic_store(&mut self, args: &[OpTy<'tcx>], atomic: AtomicWriteOrd) -> InterpResult<'tcx> {
145145
let this = self.eval_context_mut();
146146

147-
let [place, val] = check_arg_count(args)?;
147+
let [place, val] = check_intrinsic_arg_count(args)?;
148148
let place = this.deref_pointer(place)?;
149149

150150
// Perform regular load.
@@ -159,7 +159,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
159159
args: &[OpTy<'tcx>],
160160
atomic: AtomicFenceOrd,
161161
) -> InterpResult<'tcx> {
162-
let [] = check_arg_count(args)?;
162+
let [] = check_intrinsic_arg_count(args)?;
163163
let _ = atomic;
164164
//FIXME: compiler fences are currently ignored
165165
interp_ok(())
@@ -171,7 +171,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
171171
atomic: AtomicFenceOrd,
172172
) -> InterpResult<'tcx> {
173173
let this = self.eval_context_mut();
174-
let [] = check_arg_count(args)?;
174+
let [] = check_intrinsic_arg_count(args)?;
175175
this.atomic_fence(atomic)?;
176176
interp_ok(())
177177
}
@@ -185,7 +185,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
185185
) -> InterpResult<'tcx> {
186186
let this = self.eval_context_mut();
187187

188-
let [place, rhs] = check_arg_count(args)?;
188+
let [place, rhs] = check_intrinsic_arg_count(args)?;
189189
let place = this.deref_pointer(place)?;
190190
let rhs = this.read_immediate(rhs)?;
191191

@@ -226,7 +226,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
226226
) -> InterpResult<'tcx> {
227227
let this = self.eval_context_mut();
228228

229-
let [place, new] = check_arg_count(args)?;
229+
let [place, new] = check_intrinsic_arg_count(args)?;
230230
let place = this.deref_pointer(place)?;
231231
let new = this.read_scalar(new)?;
232232

@@ -245,7 +245,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
245245
) -> InterpResult<'tcx> {
246246
let this = self.eval_context_mut();
247247

248-
let [place, expect_old, new] = check_arg_count(args)?;
248+
let [place, expect_old, new] = check_intrinsic_arg_count(args)?;
249249
let place = this.deref_pointer(place)?;
250250
let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()`
251251
let new = this.read_scalar(new)?;

src/tools/miri/src/intrinsics/mod.rs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_middle::ty::{self, FloatTy};
1111
use rustc_span::{Symbol, sym};
1212

1313
use self::atomic::EvalContextExt as _;
14-
use self::helpers::{ToHost, ToSoft, check_arg_count};
14+
use self::helpers::{ToHost, ToSoft, check_intrinsic_arg_count};
1515
use self::simd::EvalContextExt as _;
1616
use crate::*;
1717

@@ -104,24 +104,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
104104

105105
// Raw memory accesses
106106
"volatile_load" => {
107-
let [place] = check_arg_count(args)?;
107+
let [place] = check_intrinsic_arg_count(args)?;
108108
let place = this.deref_pointer(place)?;
109109
this.copy_op(&place, dest)?;
110110
}
111111
"volatile_store" => {
112-
let [place, dest] = check_arg_count(args)?;
112+
let [place, dest] = check_intrinsic_arg_count(args)?;
113113
let place = this.deref_pointer(place)?;
114114
this.copy_op(dest, &place)?;
115115
}
116116

117117
"volatile_set_memory" => {
118-
let [ptr, val_byte, count] = check_arg_count(args)?;
118+
let [ptr, val_byte, count] = check_intrinsic_arg_count(args)?;
119119
this.write_bytes_intrinsic(ptr, val_byte, count, "volatile_set_memory")?;
120120
}
121121

122122
// Memory model / provenance manipulation
123123
"ptr_mask" => {
124-
let [ptr, mask] = check_arg_count(args)?;
124+
let [ptr, mask] = check_intrinsic_arg_count(args)?;
125125

126126
let ptr = this.read_pointer(ptr)?;
127127
let mask = this.read_target_usize(mask)?;
@@ -137,7 +137,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
137137
// ```
138138
// Would not be considered UB, or the other way around (`is_val_statically_known(0)`).
139139
"is_val_statically_known" => {
140-
let [_arg] = check_arg_count(args)?;
140+
let [_arg] = check_intrinsic_arg_count(args)?;
141141
// FIXME: should we check for validity here? It's tricky because we do not have a
142142
// place. Codegen does not seem to set any attributes like `noundef` for intrinsic
143143
// calls, so we don't *have* to do anything.
@@ -146,7 +146,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
146146
}
147147

148148
"floorf16" | "ceilf16" | "truncf16" | "roundf16" | "rintf16" => {
149-
let [f] = check_arg_count(args)?;
149+
let [f] = check_intrinsic_arg_count(args)?;
150150
let f = this.read_scalar(f)?.to_f16()?;
151151
let mode = match intrinsic_name {
152152
"floorf16" => Round::TowardNegative,
@@ -161,7 +161,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
161161
this.write_scalar(res, dest)?;
162162
}
163163
"floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
164-
let [f] = check_arg_count(args)?;
164+
let [f] = check_intrinsic_arg_count(args)?;
165165
let f = this.read_scalar(f)?.to_f32()?;
166166
let mode = match intrinsic_name {
167167
"floorf32" => Round::TowardNegative,
@@ -176,7 +176,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
176176
this.write_scalar(res, dest)?;
177177
}
178178
"floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => {
179-
let [f] = check_arg_count(args)?;
179+
let [f] = check_intrinsic_arg_count(args)?;
180180
let f = this.read_scalar(f)?.to_f64()?;
181181
let mode = match intrinsic_name {
182182
"floorf64" => Round::TowardNegative,
@@ -191,7 +191,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
191191
this.write_scalar(res, dest)?;
192192
}
193193
"floorf128" | "ceilf128" | "truncf128" | "roundf128" | "rintf128" => {
194-
let [f] = check_arg_count(args)?;
194+
let [f] = check_intrinsic_arg_count(args)?;
195195
let f = this.read_scalar(f)?.to_f128()?;
196196
let mode = match intrinsic_name {
197197
"floorf128" => Round::TowardNegative,
@@ -216,7 +216,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
216216
| "log10f32"
217217
| "log2f32"
218218
=> {
219-
let [f] = check_arg_count(args)?;
219+
let [f] = check_intrinsic_arg_count(args)?;
220220
let f = this.read_scalar(f)?.to_f32()?;
221221
// Using host floats except for sqrt (but it's fine, these operations do not have
222222
// guaranteed precision).
@@ -244,7 +244,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
244244
| "log10f64"
245245
| "log2f64"
246246
=> {
247-
let [f] = check_arg_count(args)?;
247+
let [f] = check_intrinsic_arg_count(args)?;
248248
let f = this.read_scalar(f)?.to_f64()?;
249249
// Using host floats except for sqrt (but it's fine, these operations do not have
250250
// guaranteed precision).
@@ -264,7 +264,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
264264
}
265265

266266
"fmaf32" => {
267-
let [a, b, c] = check_arg_count(args)?;
267+
let [a, b, c] = check_intrinsic_arg_count(args)?;
268268
let a = this.read_scalar(a)?.to_f32()?;
269269
let b = this.read_scalar(b)?.to_f32()?;
270270
let c = this.read_scalar(c)?.to_f32()?;
@@ -274,7 +274,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
274274
this.write_scalar(res, dest)?;
275275
}
276276
"fmaf64" => {
277-
let [a, b, c] = check_arg_count(args)?;
277+
let [a, b, c] = check_intrinsic_arg_count(args)?;
278278
let a = this.read_scalar(a)?.to_f64()?;
279279
let b = this.read_scalar(b)?.to_f64()?;
280280
let c = this.read_scalar(c)?.to_f64()?;
@@ -285,7 +285,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
285285
}
286286

287287
"fmuladdf32" => {
288-
let [a, b, c] = check_arg_count(args)?;
288+
let [a, b, c] = check_intrinsic_arg_count(args)?;
289289
let a = this.read_scalar(a)?.to_f32()?;
290290
let b = this.read_scalar(b)?.to_f32()?;
291291
let c = this.read_scalar(c)?.to_f32()?;
@@ -300,7 +300,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
300300
this.write_scalar(res, dest)?;
301301
}
302302
"fmuladdf64" => {
303-
let [a, b, c] = check_arg_count(args)?;
303+
let [a, b, c] = check_intrinsic_arg_count(args)?;
304304
let a = this.read_scalar(a)?.to_f64()?;
305305
let b = this.read_scalar(b)?.to_f64()?;
306306
let c = this.read_scalar(c)?.to_f64()?;
@@ -316,7 +316,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
316316
}
317317

318318
"powf32" => {
319-
let [f1, f2] = check_arg_count(args)?;
319+
let [f1, f2] = check_intrinsic_arg_count(args)?;
320320
let f1 = this.read_scalar(f1)?.to_f32()?;
321321
let f2 = this.read_scalar(f2)?.to_f32()?;
322322
// Using host floats (but it's fine, this operation does not have guaranteed precision).
@@ -325,7 +325,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
325325
this.write_scalar(res, dest)?;
326326
}
327327
"powf64" => {
328-
let [f1, f2] = check_arg_count(args)?;
328+
let [f1, f2] = check_intrinsic_arg_count(args)?;
329329
let f1 = this.read_scalar(f1)?.to_f64()?;
330330
let f2 = this.read_scalar(f2)?.to_f64()?;
331331
// Using host floats (but it's fine, this operation does not have guaranteed precision).
@@ -335,7 +335,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
335335
}
336336

337337
"powif32" => {
338-
let [f, i] = check_arg_count(args)?;
338+
let [f, i] = check_intrinsic_arg_count(args)?;
339339
let f = this.read_scalar(f)?.to_f32()?;
340340
let i = this.read_scalar(i)?.to_i32()?;
341341
// Using host floats (but it's fine, this operation does not have guaranteed precision).
@@ -344,7 +344,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
344344
this.write_scalar(res, dest)?;
345345
}
346346
"powif64" => {
347-
let [f, i] = check_arg_count(args)?;
347+
let [f, i] = check_intrinsic_arg_count(args)?;
348348
let f = this.read_scalar(f)?.to_f64()?;
349349
let i = this.read_scalar(i)?.to_i32()?;
350350
// Using host floats (but it's fine, this operation does not have guaranteed precision).
@@ -360,7 +360,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
360360
| "fdiv_algebraic"
361361
| "frem_algebraic"
362362
=> {
363-
let [a, b] = check_arg_count(args)?;
363+
let [a, b] = check_intrinsic_arg_count(args)?;
364364
let a = this.read_immediate(a)?;
365365
let b = this.read_immediate(b)?;
366366
let op = match intrinsic_name {
@@ -383,7 +383,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
383383
| "fdiv_fast"
384384
| "frem_fast"
385385
=> {
386-
let [a, b] = check_arg_count(args)?;
386+
let [a, b] = check_intrinsic_arg_count(args)?;
387387
let a = this.read_immediate(a)?;
388388
let b = this.read_immediate(b)?;
389389
let op = match intrinsic_name {
@@ -427,7 +427,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
427427
}
428428

429429
"float_to_int_unchecked" => {
430-
let [val] = check_arg_count(args)?;
430+
let [val] = check_intrinsic_arg_count(args)?;
431431
let val = this.read_immediate(val)?;
432432

433433
let res = this
@@ -444,7 +444,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
444444

445445
// Other
446446
"breakpoint" => {
447-
let [] = check_arg_count(args)?;
447+
let [] = check_intrinsic_arg_count(args)?;
448448
// normally this would raise a SIGTRAP, which aborts if no debugger is connected
449449
throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap")))
450450
}

0 commit comments

Comments
 (0)