Skip to content

Commit 78f3295

Browse files
committed
Check that shims are called with the correct number of arguments
1 parent a49234e commit 78f3295

File tree

12 files changed

+445
-240
lines changed

12 files changed

+445
-240
lines changed

src/helpers.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::convert::TryFrom;
1+
use std::convert::{TryFrom, TryInto};
22
use std::mem;
33
use std::num::NonZeroUsize;
44

@@ -471,6 +471,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
471471
}
472472
}
473473

474+
/// Check that the number of args is what we expect.
475+
pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]>
476+
where &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]> {
477+
if let Ok(ops) = args.try_into() {
478+
return Ok(ops);
479+
}
480+
throw_ub_format!("incorrect number of arguments, got {}, needed {}", args.len(), N)
481+
}
482+
474483
pub fn immty_from_int_checked<'tcx>(
475484
int: impl Into<i128>,
476485
layout: TyAndLayout<'tcx>,

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#![warn(rust_2018_idioms)]
88
#![allow(clippy::cast_lossless)]
99

10+
#![allow(incomplete_features)]
11+
#![feature(const_generics)]
12+
1013
extern crate rustc_apfloat;
1114
extern crate rustc_ast;
1215
#[macro_use] extern crate rustc_middle;

src/shims/dlsym.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_middle::mir;
22

33
use crate::*;
4+
use helpers::check_arg_count;
45

56
#[derive(Debug, Copy, Clone)]
67
pub enum Dlsym {
@@ -35,8 +36,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
3536

3637
match dlsym {
3738
GetEntropy => {
38-
let ptr = this.read_scalar(args[0])?.not_undef()?;
39-
let len = this.read_scalar(args[1])?.to_machine_usize(this)?;
39+
let &[ptr, len] = check_arg_count(args)?;
40+
let ptr = this.read_scalar(ptr)?.not_undef()?;
41+
let len = this.read_scalar(len)?.to_machine_usize(this)?;
4042
this.gen_random(ptr, len)?;
4143
this.write_null(dest)?;
4244
}

src/shims/foreign_items.rs

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_span::symbol::sym;
1111
use rustc_ast::attr;
1212

1313
use crate::*;
14+
use helpers::check_arg_count;
1415

1516
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
1617
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
@@ -139,8 +140,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
139140
| "exit"
140141
| "ExitProcess"
141142
=> {
143+
let &[code] = check_arg_count(args)?;
142144
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
143-
let code = this.read_scalar(args[0])?.to_i32()?;
145+
let code = this.read_scalar(code)?.to_i32()?;
144146
throw_machine_stop!(TerminationInfo::Exit(code.into()));
145147
}
146148
_ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name),
@@ -197,25 +199,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
197199
match link_name {
198200
// Standard C allocation
199201
"malloc" => {
200-
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
202+
let &[size] = check_arg_count(args)?;
203+
let size = this.read_scalar(size)?.to_machine_usize(this)?;
201204
let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C);
202205
this.write_scalar(res, dest)?;
203206
}
204207
"calloc" => {
205-
let items = this.read_scalar(args[0])?.to_machine_usize(this)?;
206-
let len = this.read_scalar(args[1])?.to_machine_usize(this)?;
208+
let &[items, len] = check_arg_count(args)?;
209+
let items = this.read_scalar(items)?.to_machine_usize(this)?;
210+
let len = this.read_scalar(len)?.to_machine_usize(this)?;
207211
let size =
208212
items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
209213
let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C);
210214
this.write_scalar(res, dest)?;
211215
}
212216
"free" => {
213-
let ptr = this.read_scalar(args[0])?.not_undef()?;
217+
let &[ptr] = check_arg_count(args)?;
218+
let ptr = this.read_scalar(ptr)?.not_undef()?;
214219
this.free(ptr, MiriMemoryKind::C)?;
215220
}
216221
"realloc" => {
217-
let old_ptr = this.read_scalar(args[0])?.not_undef()?;
218-
let new_size = this.read_scalar(args[1])?.to_machine_usize(this)?;
222+
let &[old_ptr, new_size] = check_arg_count(args)?;
223+
let old_ptr = this.read_scalar(old_ptr)?.not_undef()?;
224+
let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?;
219225
let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?;
220226
this.write_scalar(res, dest)?;
221227
}
@@ -224,8 +230,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
224230
// (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic
225231
// allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.)
226232
"__rust_alloc" => {
227-
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
228-
let align = this.read_scalar(args[1])?.to_machine_usize(this)?;
233+
let &[size, align] = check_arg_count(args)?;
234+
let size = this.read_scalar(size)?.to_machine_usize(this)?;
235+
let align = this.read_scalar(align)?.to_machine_usize(this)?;
229236
Self::check_alloc_request(size, align)?;
230237
let ptr = this.memory.allocate(
231238
Size::from_bytes(size),
@@ -235,8 +242,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
235242
this.write_scalar(ptr, dest)?;
236243
}
237244
"__rust_alloc_zeroed" => {
238-
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
239-
let align = this.read_scalar(args[1])?.to_machine_usize(this)?;
245+
let &[size, align] = check_arg_count(args)?;
246+
let size = this.read_scalar(size)?.to_machine_usize(this)?;
247+
let align = this.read_scalar(align)?.to_machine_usize(this)?;
240248
Self::check_alloc_request(size, align)?;
241249
let ptr = this.memory.allocate(
242250
Size::from_bytes(size),
@@ -248,9 +256,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
248256
this.write_scalar(ptr, dest)?;
249257
}
250258
"__rust_dealloc" => {
251-
let ptr = this.read_scalar(args[0])?.not_undef()?;
252-
let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?;
253-
let align = this.read_scalar(args[2])?.to_machine_usize(this)?;
259+
let &[ptr, old_size, align] = check_arg_count(args)?;
260+
let ptr = this.read_scalar(ptr)?.not_undef()?;
261+
let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?;
262+
let align = this.read_scalar(align)?.to_machine_usize(this)?;
254263
// No need to check old_size/align; we anyway check that they match the allocation.
255264
let ptr = this.force_ptr(ptr)?;
256265
this.memory.deallocate(
@@ -260,12 +269,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
260269
)?;
261270
}
262271
"__rust_realloc" => {
263-
let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?;
264-
let align = this.read_scalar(args[2])?.to_machine_usize(this)?;
265-
let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?;
272+
let &[ptr, old_size, align, new_size] = check_arg_count(args)?;
273+
let ptr = this.force_ptr(this.read_scalar(ptr)?.not_undef()?)?;
274+
let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?;
275+
let align = this.read_scalar(align)?.to_machine_usize(this)?;
276+
let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?;
266277
Self::check_alloc_request(new_size, align)?;
267278
// No need to check old_size; we anyway check that they match the allocation.
268-
let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?;
269279
let align = Align::from_bytes(align).unwrap();
270280
let new_ptr = this.memory.reallocate(
271281
ptr,
@@ -279,9 +289,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
279289

280290
// C memory handling functions
281291
"memcmp" => {
282-
let left = this.read_scalar(args[0])?.not_undef()?;
283-
let right = this.read_scalar(args[1])?.not_undef()?;
284-
let n = Size::from_bytes(this.read_scalar(args[2])?.to_machine_usize(this)?);
292+
let &[left, right, n] = check_arg_count(args)?;
293+
let left = this.read_scalar(left)?.not_undef()?;
294+
let right = this.read_scalar(right)?.not_undef()?;
295+
let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?);
285296

286297
let result = {
287298
let left_bytes = this.memory.read_bytes(left, n)?;
@@ -298,9 +309,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
298309
this.write_scalar(Scalar::from_i32(result), dest)?;
299310
}
300311
"memrchr" => {
301-
let ptr = this.read_scalar(args[0])?.not_undef()?;
302-
let val = this.read_scalar(args[1])?.to_i32()? as u8;
303-
let num = this.read_scalar(args[2])?.to_machine_usize(this)?;
312+
let &[ptr, val, num] = check_arg_count(args)?;
313+
let ptr = this.read_scalar(ptr)?.not_undef()?;
314+
let val = this.read_scalar(val)?.to_i32()? as u8;
315+
let num = this.read_scalar(num)?.to_machine_usize(this)?;
304316
if let Some(idx) = this
305317
.memory
306318
.read_bytes(ptr, Size::from_bytes(num))?
@@ -315,9 +327,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
315327
}
316328
}
317329
"memchr" => {
318-
let ptr = this.read_scalar(args[0])?.not_undef()?;
319-
let val = this.read_scalar(args[1])?.to_i32()? as u8;
320-
let num = this.read_scalar(args[2])?.to_machine_usize(this)?;
330+
let &[ptr, val, num] = check_arg_count(args)?;
331+
let ptr = this.read_scalar(ptr)?.not_undef()?;
332+
let val = this.read_scalar(val)?.to_i32()? as u8;
333+
let num = this.read_scalar(num)?.to_machine_usize(this)?;
321334
let idx = this
322335
.memory
323336
.read_bytes(ptr, Size::from_bytes(num))?
@@ -331,7 +344,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
331344
}
332345
}
333346
"strlen" => {
334-
let ptr = this.read_scalar(args[0])?.not_undef()?;
347+
let &[ptr] = check_arg_count(args)?;
348+
let ptr = this.read_scalar(ptr)?.not_undef()?;
335349
let n = this.memory.read_c_str(ptr)?.len();
336350
this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?;
337351
}
@@ -345,8 +359,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
345359
| "asinf"
346360
| "atanf"
347361
=> {
362+
let &[f] = check_arg_count(args)?;
348363
// FIXME: Using host floats.
349-
let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
364+
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?);
350365
let f = match link_name {
351366
"cbrtf" => f.cbrt(),
352367
"coshf" => f.cosh(),
@@ -363,11 +378,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
363378
| "hypotf"
364379
| "atan2f"
365380
=> {
381+
let &[f1, f2] = check_arg_count(args)?;
366382
// underscore case for windows, here and below
367383
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
368384
// FIXME: Using host floats.
369-
let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
370-
let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?);
385+
let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?);
386+
let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?);
371387
let n = match link_name {
372388
"_hypotf" | "hypotf" => f1.hypot(f2),
373389
"atan2f" => f1.atan2(f2),
@@ -383,8 +399,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
383399
| "asin"
384400
| "atan"
385401
=> {
402+
let &[f] = check_arg_count(args)?;
386403
// FIXME: Using host floats.
387-
let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
404+
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?);
388405
let f = match link_name {
389406
"cbrt" => f.cbrt(),
390407
"cosh" => f.cosh(),
@@ -401,9 +418,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
401418
| "hypot"
402419
| "atan2"
403420
=> {
421+
let &[f1, f2] = check_arg_count(args)?;
404422
// FIXME: Using host floats.
405-
let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
406-
let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?);
423+
let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?);
424+
let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?);
407425
let n = match link_name {
408426
"_hypot" | "hypot" => f1.hypot(f2),
409427
"atan2" => f1.atan2(f2),
@@ -415,9 +433,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
415433
| "ldexp"
416434
| "scalbn"
417435
=> {
436+
let &[x, exp] = check_arg_count(args)?;
418437
// For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
419-
let x = this.read_scalar(args[0])?.to_f64()?;
420-
let exp = this.read_scalar(args[1])?.to_i32()?;
438+
let x = this.read_scalar(x)?.to_f64()?;
439+
let exp = this.read_scalar(exp)?.to_i32()?;
421440

422441
// Saturating cast to i16. Even those are outside the valid exponent range to
423442
// `scalbn` below will do its over/underflow handling.

0 commit comments

Comments
 (0)