Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/eval.rs')
-rw-r--r--crates/hir-ty/src/mir/eval.rs38
1 files changed, 27 insertions, 11 deletions
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 010ebcbd06..a1bab09795 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -137,6 +137,7 @@ pub struct Evaluator<'a> {
/// time of use.
vtable_map: VTableMap,
thread_local_storage: TlsData,
+ random_state: oorandom::Rand64,
stdout: Vec<u8>,
stderr: Vec<u8>,
layout_cache: RefCell<FxHashMap<Ty, Arc<Layout>>>,
@@ -147,6 +148,8 @@ pub struct Evaluator<'a> {
execution_limit: usize,
/// An additional limit on stack depth, to prevent stack overflow
stack_depth_limit: usize,
+ /// Maximum count of bytes that heap and stack can grow
+ memory_limit: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -520,6 +523,7 @@ impl Evaluator<'_> {
thread_local_storage: TlsData::default(),
static_locations: HashMap::default(),
db,
+ random_state: oorandom::Rand64::new(0),
trait_env,
crate_id,
stdout: vec![],
@@ -527,6 +531,7 @@ impl Evaluator<'_> {
assert_placeholder_ty_is_unused,
stack_depth_limit: 100,
execution_limit: 1000_000,
+ memory_limit: 1000_000_000, // 2GB, 1GB for stack and 1GB for heap
layout_cache: RefCell::new(HashMap::default()),
}
}
@@ -938,6 +943,11 @@ impl Evaluator<'_> {
};
locals.ptr = locals_ptr;
let prev_stack_pointer = self.stack.len();
+ if stack_size > self.memory_limit {
+ return Err(MirEvalError::Panic(format!(
+ "Stack overflow. Tried to grow stack to {stack_size} bytes"
+ )));
+ }
self.stack.extend(iter::repeat(0).take(stack_size));
Ok((locals, prev_stack_pointer))
}
@@ -1180,7 +1190,7 @@ impl Evaluator<'_> {
let Some((size, align)) = self.size_align_of(ty, locals)? else {
not_supported!("unsized box initialization");
};
- let addr = self.heap_allocate(size, align);
+ let addr = self.heap_allocate(size, align)?;
Owned(addr.to_bytes())
}
Rvalue::CopyForDeref(_) => not_supported!("copy for deref"),
@@ -1565,7 +1575,7 @@ impl Evaluator<'_> {
ConstScalar::Bytes(v, memory_map) => {
let mut v: Cow<'_, [u8]> = Cow::Borrowed(v);
let patch_map = memory_map.transform_addresses(|b, align| {
- let addr = self.heap_allocate(b.len(), align);
+ let addr = self.heap_allocate(b.len(), align)?;
self.write_memory(addr, b)?;
Ok(addr.to_usize())
})?;
@@ -1580,7 +1590,7 @@ impl Evaluator<'_> {
return Err(MirEvalError::InvalidConst(konst.clone()));
}
}
- let addr = self.heap_allocate(size, align);
+ let addr = self.heap_allocate(size, align)?;
self.write_memory(addr, &v)?;
self.patch_addresses(&patch_map, &memory_map.vtable, addr, ty, locals)?;
Interval::new(addr, size)
@@ -1683,13 +1693,19 @@ impl Evaluator<'_> {
}
}
- fn heap_allocate(&mut self, size: usize, align: usize) -> Address {
+ fn heap_allocate(&mut self, size: usize, align: usize) -> Result<Address> {
+ if !align.is_power_of_two() || align > 10000 {
+ return Err(MirEvalError::UndefinedBehavior(format!("Alignment {align} is invalid")));
+ }
while self.heap.len() % align != 0 {
self.heap.push(0);
}
+ if size.checked_add(self.heap.len()).map_or(true, |x| x > self.memory_limit) {
+ return Err(MirEvalError::Panic(format!("Memory allocation of {size} bytes failed")));
+ }
let pos = self.heap.len();
self.heap.extend(iter::repeat(0).take(size));
- Address::Heap(pos)
+ Ok(Address::Heap(pos))
}
fn detect_fn_trait(&self, def: FunctionId) -> Option<FnTrait> {
@@ -2200,7 +2216,7 @@ impl Evaluator<'_> {
)?;
// FIXME: there is some leak here
let size = layout.size.bytes_usize();
- let addr = self.heap_allocate(size, layout.align.abi.bytes() as usize);
+ let addr = self.heap_allocate(size, layout.align.abi.bytes() as usize)?;
self.write_memory(addr, &result)?;
IntervalAndTy { interval: Interval { addr, size }, ty }
};
@@ -2235,10 +2251,10 @@ impl Evaluator<'_> {
let Some((size, align)) = self.size_align_of(&ty, locals)? else {
not_supported!("unsized extern static");
};
- let addr = self.heap_allocate(size, align);
+ let addr = self.heap_allocate(size, align)?;
Interval::new(addr, size)
};
- let addr = self.heap_allocate(self.ptr_size(), self.ptr_size());
+ let addr = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
self.write_memory(addr, &result.addr.to_bytes())?;
self.static_locations.insert(st, addr);
Ok(addr)
@@ -2398,11 +2414,11 @@ pub fn render_const_using_debug_impl(
not_supported!("core::fmt::Debug::fmt not found");
};
// a1 = &[""]
- let a1 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size());
+ let a1 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size())?;
// a2 = &[::core::fmt::ArgumentV1::new(&(THE_CONST), ::core::fmt::Debug::fmt)]
// FIXME: we should call the said function, but since its name is going to break in the next rustc version
// and its ABI doesn't break yet, we put it in memory manually.
- let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size());
+ let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size())?;
evaluator.write_memory(a2, &data.addr.to_bytes())?;
let debug_fmt_fn_ptr = evaluator.vtable_map.id(TyKind::FnDef(
db.intern_callable_def(debug_fmt_fn.into()).into(),
@@ -2412,7 +2428,7 @@ pub fn render_const_using_debug_impl(
evaluator.write_memory(a2.offset(evaluator.ptr_size()), &debug_fmt_fn_ptr.to_le_bytes())?;
// a3 = ::core::fmt::Arguments::new_v1(a1, a2)
// FIXME: similarly, we should call function here, not directly working with memory.
- let a3 = evaluator.heap_allocate(evaluator.ptr_size() * 6, evaluator.ptr_size());
+ let a3 = evaluator.heap_allocate(evaluator.ptr_size() * 6, evaluator.ptr_size())?;
evaluator.write_memory(a3.offset(2 * evaluator.ptr_size()), &a1.to_bytes())?;
evaluator.write_memory(a3.offset(3 * evaluator.ptr_size()), &[1])?;
evaluator.write_memory(a3.offset(4 * evaluator.ptr_size()), &a2.to_bytes())?;