1
1
use std::{collections::hash_map::Entry, io::Write, iter, path::Path};
2
2
3
3
use rustc_apfloat::Float;
4
- use rustc_ast::expand::allocator::{ alloc_error_handler_name, AllocatorKind} ;
4
+ use rustc_ast::expand::allocator::alloc_error_handler_name;
5
5
use rustc_hir::{def::DefKind, def_id::CrateNum};
6
6
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
7
7
use rustc_middle::mir;
@@ -12,6 +12,7 @@ use rustc_target::{
12
12
spec::abi::Abi,
13
13
};
14
14
15
+ use super::alloc::{check_alloc_request, EvalContextExt as _};
15
16
use super::backtrace::EvalContextExt as _;
16
17
use crate::*;
17
18
use helpers::{ToHost, ToSoft};
@@ -232,138 +233,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
232
233
Some(instance) => Ok(Some((this.load_mir(instance.def, None)?, instance))),
233
234
}
234
235
}
235
-
236
- fn malloc(
237
- &mut self,
238
- size: u64,
239
- zero_init: bool,
240
- kind: MiriMemoryKind,
241
- ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
242
- let this = self.eval_context_mut();
243
- if size == 0 {
244
- Ok(Pointer::null())
245
- } else {
246
- let align = this.min_align(size, kind);
247
- let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?;
248
- if zero_init {
249
- // We just allocated this, the access is definitely in-bounds and fits into our address space.
250
- this.write_bytes_ptr(
251
- ptr.into(),
252
- iter::repeat(0u8).take(usize::try_from(size).unwrap()),
253
- )
254
- .unwrap();
255
- }
256
- Ok(ptr.into())
257
- }
258
- }
259
-
260
- fn free(
261
- &mut self,
262
- ptr: Pointer<Option<Provenance>>,
263
- kind: MiriMemoryKind,
264
- ) -> InterpResult<'tcx> {
265
- let this = self.eval_context_mut();
266
- if !this.ptr_is_null(ptr)? {
267
- this.deallocate_ptr(ptr, None, kind.into())?;
268
- }
269
- Ok(())
270
- }
271
-
272
- fn realloc(
273
- &mut self,
274
- old_ptr: Pointer<Option<Provenance>>,
275
- new_size: u64,
276
- kind: MiriMemoryKind,
277
- ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
278
- let this = self.eval_context_mut();
279
- let new_align = this.min_align(new_size, kind);
280
- if this.ptr_is_null(old_ptr)? {
281
- if new_size == 0 {
282
- Ok(Pointer::null())
283
- } else {
284
- let new_ptr =
285
- this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?;
286
- Ok(new_ptr.into())
287
- }
288
- } else {
289
- if new_size == 0 {
290
- this.deallocate_ptr(old_ptr, None, kind.into())?;
291
- Ok(Pointer::null())
292
- } else {
293
- let new_ptr = this.reallocate_ptr(
294
- old_ptr,
295
- None,
296
- Size::from_bytes(new_size),
297
- new_align,
298
- kind.into(),
299
- )?;
300
- Ok(new_ptr.into())
301
- }
302
- }
303
- }
304
236
}
305
237
306
238
impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
307
239
trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
308
- /// Returns the minimum alignment for the target architecture for allocations of the given size.
309
- fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {
310
- let this = self.eval_context_ref();
311
- // List taken from `library/std/src/sys/pal/common/alloc.rs`.
312
- // This list should be kept in sync with the one from libstd.
313
- let min_align = match this.tcx.sess.target.arch.as_ref() {
314
- "x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "wasm32" => 8,
315
- "x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" =>
316
- 16,
317
- arch => bug!("unsupported target architecture for malloc: `{}`", arch),
318
- };
319
- // Windows always aligns, even small allocations.
320
- // Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
321
- // But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big.
322
- if kind == MiriMemoryKind::WinHeap || size >= min_align {
323
- return Align::from_bytes(min_align).unwrap();
324
- }
325
- // We have `size < min_align`. Round `size` *down* to the next power of two and use that.
326
- fn prev_power_of_two(x: u64) -> u64 {
327
- let next_pow2 = x.next_power_of_two();
328
- if next_pow2 == x {
329
- // x *is* a power of two, just use that.
330
- x
331
- } else {
332
- // x is between two powers, so next = 2*prev.
333
- next_pow2 / 2
334
- }
335
- }
336
- Align::from_bytes(prev_power_of_two(size)).unwrap()
337
- }
338
-
339
- /// Emulates calling the internal __rust_* allocator functions
340
- fn emulate_allocator(
341
- &mut self,
342
- default: impl FnOnce(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx>,
343
- ) -> InterpResult<'tcx, EmulateForeignItemResult> {
344
- let this = self.eval_context_mut();
345
-
346
- let Some(allocator_kind) = this.tcx.allocator_kind(()) else {
347
- // in real code, this symbol does not exist without an allocator
348
- return Ok(EmulateForeignItemResult::NotSupported);
349
- };
350
-
351
- match allocator_kind {
352
- AllocatorKind::Global => {
353
- // When `#[global_allocator]` is used, `__rust_*` is defined by the macro expansion
354
- // of this attribute. As such we have to call an exported Rust function,
355
- // and not execute any Miri shim. Somewhat unintuitively doing so is done
356
- // by returning `NotSupported`, which triggers the `lookup_exported_symbol`
357
- // fallback case in `emulate_foreign_item`.
358
- return Ok(EmulateForeignItemResult::NotSupported);
359
- }
360
- AllocatorKind::Default => {
361
- default(this)?;
362
- Ok(EmulateForeignItemResult::NeedsJumping)
363
- }
364
- }
365
- }
366
-
367
240
fn emulate_foreign_item_inner(
368
241
&mut self,
369
242
link_name: Symbol,
@@ -610,7 +483,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
610
483
let size = this.read_target_usize(size)?;
611
484
let align = this.read_target_usize(align)?;
612
485
613
- Self:: check_alloc_request(size, align)?;
486
+ check_alloc_request(size, align)?;
614
487
615
488
let memory_kind = match link_name.as_str() {
616
489
"__rust_alloc" => MiriMemoryKind::Rust,
@@ -644,7 +517,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
644
517
let size = this.read_target_usize(size)?;
645
518
let align = this.read_target_usize(align)?;
646
519
647
- Self:: check_alloc_request(size, align)?;
520
+ check_alloc_request(size, align)?;
648
521
649
522
let ptr = this.allocate_ptr(
650
523
Size::from_bytes(size),
@@ -708,7 +581,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
708
581
let new_size = this.read_target_usize(new_size)?;
709
582
// No need to check old_size; we anyway check that they match the allocation.
710
583
711
- Self:: check_alloc_request(new_size, align)?;
584
+ check_alloc_request(new_size, align)?;
712
585
713
586
let align = Align::from_bytes(align).unwrap();
714
587
let new_ptr = this.reallocate_ptr(
@@ -1100,16 +973,4 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
1100
973
// i.e., if we actually emulated the function with one of the shims.
1101
974
Ok(EmulateForeignItemResult::NeedsJumping)
1102
975
}
1103
-
1104
- /// Check some basic requirements for this allocation request:
1105
- /// non-zero size, power-of-two alignment.
1106
- fn check_alloc_request(size: u64, align: u64) -> InterpResult<'tcx> {
1107
- if size == 0 {
1108
- throw_ub_format!("creating allocation with size 0");
1109
- }
1110
- if !align.is_power_of_two() {
1111
- throw_ub_format!("creating allocation with non-power-of-two alignment {}", align);
1112
- }
1113
- Ok(())
1114
- }
1115
976
}
0 commit comments