Skip to content

Commit b920b00

Browse files
committed
don't panic when allocator symbols called without allocator
1 parent e9adffd commit b920b00

File tree

1 file changed

+66
-78
lines changed

1 file changed

+66
-78
lines changed

src/shims/foreign_items.rs

Lines changed: 66 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
298298
Ok(None)
299299
}
300300

301+
/// Emulates calling the internal __rust_* allocator functions
302+
fn emulate_allocator(
303+
&mut self,
304+
symbol: Symbol,
305+
default: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx>,
306+
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
307+
let this = self.eval_context_mut();
308+
309+
let allocator_kind = if let Some(allocator_kind) = this.tcx.allocator_kind(()) {
310+
allocator_kind
311+
} else {
312+
// in real code, this symbol does not exist without an allocator
313+
return Ok(EmulateByNameResult::NotSupported);
314+
};
315+
316+
match allocator_kind {
317+
AllocatorKind::Global => {
318+
let body = this
319+
.lookup_exported_symbol(symbol)?
320+
.expect("symbol should be present if there is a global allocator");
321+
322+
Ok(EmulateByNameResult::MirBody(body))
323+
}
324+
AllocatorKind::Default => default(this).map(|()| EmulateByNameResult::NeedsJumping),
325+
}
326+
}
327+
301328
/// Emulates calling a foreign item using its name.
302329
fn emulate_foreign_item_by_name(
303330
&mut self,
@@ -372,77 +399,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
372399
let align = this.read_scalar(align)?.to_machine_usize(this)?;
373400
Self::check_alloc_request(size, align)?;
374401

375-
let allocator_kind = this.tcx.allocator_kind(());
376-
377-
match allocator_kind.expect("allocator should be present if used") {
378-
AllocatorKind::Global => {
379-
let body = this.lookup_exported_symbol(Symbol::intern("__rg_alloc"))?
380-
.expect("symbol should be present if there is a global allocator");
381-
382-
return Ok(EmulateByNameResult::MirBody(body))
383-
},
384-
AllocatorKind::Default => {
385-
let ptr = this.memory.allocate(
386-
Size::from_bytes(size),
387-
Align::from_bytes(align).unwrap(),
388-
MiriMemoryKind::Rust.into(),
389-
)?;
390-
this.write_pointer(ptr, dest)?;
391-
}
392-
};
402+
return this.emulate_allocator(Symbol::intern("__rg_alloc"), |this| {
403+
let ptr = this.memory.allocate(
404+
Size::from_bytes(size),
405+
Align::from_bytes(align).unwrap(),
406+
MiriMemoryKind::Rust.into(),
407+
)?;
408+
409+
this.write_pointer(ptr, dest)
410+
});
393411
}
394412
"__rust_alloc_zeroed" => {
395413
let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
396414
let size = this.read_scalar(size)?.to_machine_usize(this)?;
397415
let align = this.read_scalar(align)?.to_machine_usize(this)?;
398416
Self::check_alloc_request(size, align)?;
399417

400-
let allocator_kind = this.tcx.allocator_kind(());
401-
402-
match allocator_kind.expect("allocator should be present if used") {
403-
AllocatorKind::Global => {
404-
let body = this.lookup_exported_symbol(Symbol::intern("__rg_alloc_zeroed"))?
405-
.expect("symbol should be present if there is a global allocator");
406-
407-
return Ok(EmulateByNameResult::MirBody(body))
408-
},
409-
AllocatorKind::Default => {
410-
let ptr = this.memory.allocate(
411-
Size::from_bytes(size),
412-
Align::from_bytes(align).unwrap(),
413-
MiriMemoryKind::Rust.into(),
414-
)?;
415-
416-
// We just allocated this, the access is definitely in-bounds.
417-
this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap();
418-
this.write_pointer(ptr, dest)?;
419-
}
420-
}
418+
return this.emulate_allocator(Symbol::intern("__rg_alloc_zeroed"), |this| {
419+
let ptr = this.memory.allocate(
420+
Size::from_bytes(size),
421+
Align::from_bytes(align).unwrap(),
422+
MiriMemoryKind::Rust.into(),
423+
)?;
424+
425+
// We just allocated this, the access is definitely in-bounds.
426+
this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap();
427+
this.write_pointer(ptr, dest)
428+
});
421429
}
422430
"__rust_dealloc" => {
423431
let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
424432
let ptr = this.read_pointer(ptr)?;
425433
let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?;
426434
let align = this.read_scalar(align)?.to_machine_usize(this)?;
427435

428-
let allocator_kind = this.tcx.allocator_kind(());
429-
430-
match allocator_kind.expect("allocator should be present if used") {
431-
AllocatorKind::Global => {
432-
let body = this.lookup_exported_symbol(Symbol::intern("__rg_dealloc"))?
433-
.expect("symbol should be present if there is a global allocator");
434-
435-
return Ok(EmulateByNameResult::MirBody(body))
436-
},
437-
AllocatorKind::Default => {
438-
// No need to check old_size/align; we anyway check that they match the allocation.
439-
this.memory.deallocate(
440-
ptr,
441-
Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
442-
MiriMemoryKind::Rust.into(),
443-
)?;
444-
}
445-
}
436+
return this.emulate_allocator(Symbol::intern("__rg_dealloc"), |this| {
437+
// No need to check old_size/align; we anyway check that they match the allocation.
438+
this.memory.deallocate(
439+
ptr,
440+
Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
441+
MiriMemoryKind::Rust.into(),
442+
)
443+
});
446444
}
447445
"__rust_realloc" => {
448446
let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?;
@@ -453,27 +451,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
453451
Self::check_alloc_request(new_size, align)?;
454452
// No need to check old_size; we anyway check that they match the allocation.
455453

456-
let allocator_kind = this.tcx.allocator_kind(());
457-
458-
match allocator_kind.expect("allocator should be present if used") {
459-
AllocatorKind::Global => {
460-
let body = this.lookup_exported_symbol(Symbol::intern("__rg_realloc"))?
461-
.expect("symbol should be present if there is a global allocator");
462-
463-
return Ok(EmulateByNameResult::MirBody(body))
464-
},
465-
AllocatorKind::Default => {
466-
let align = Align::from_bytes(align).unwrap();
467-
let new_ptr = this.memory.reallocate(
468-
ptr,
469-
Some((Size::from_bytes(old_size), align)),
470-
Size::from_bytes(new_size),
471-
align,
472-
MiriMemoryKind::Rust.into(),
473-
)?;
474-
this.write_pointer(new_ptr, dest)?;
475-
}
476-
}
454+
return this.emulate_allocator(Symbol::intern("__rg_realloc"), |this| {
455+
let align = Align::from_bytes(align).unwrap();
456+
let new_ptr = this.memory.reallocate(
457+
ptr,
458+
Some((Size::from_bytes(old_size), align)),
459+
Size::from_bytes(new_size),
460+
align,
461+
MiriMemoryKind::Rust.into(),
462+
)?;
463+
this.write_pointer(new_ptr, dest)
464+
});
477465
}
478466

479467
// C memory handling functions

0 commit comments

Comments
 (0)