@@ -11,6 +11,7 @@ use rand::rngs::StdRng;
11
11
use rand:: Rng ;
12
12
use rand:: SeedableRng ;
13
13
14
+ use rustc_attr:: InlineAttr ;
14
15
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
15
16
#[ allow( unused) ]
16
17
use rustc_data_structures:: static_assert_size;
@@ -47,10 +48,10 @@ pub const SIGRTMIN: i32 = 34;
47
48
/// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`)
48
49
pub const SIGRTMAX : i32 = 42 ;
49
50
50
- /// Each const has multiple addresses, but only this many. Since const allocations are never
51
- /// deallocated, choosing a new [`AllocId`] and thus base address for each evaluation would
52
- /// produce unbounded memory usage.
53
- const ADDRS_PER_CONST : usize = 16 ;
51
+ /// Each anonymous global (constant, vtable, function pointer, ...) has multiple addresses, but only
52
+ /// this many. Since const allocations are never deallocated, choosing a new [`AllocId`] and thus
53
+ /// base address for each evaluation would produce unbounded memory usage.
54
+ const ADDRS_PER_ANON_GLOBAL : usize = 32 ;
54
55
55
56
/// Extra data stored with each stack frame
56
57
pub struct FrameExtra < ' tcx > {
@@ -1372,7 +1373,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
1372
1373
catch_unwind : None ,
1373
1374
timing,
1374
1375
is_user_relevant : ecx. machine . is_user_relevant ( & frame) ,
1375
- salt : ecx. machine . rng . borrow_mut ( ) . gen :: < usize > ( ) % ADDRS_PER_CONST ,
1376
+ salt : ecx. machine . rng . borrow_mut ( ) . gen :: < usize > ( ) % ADDRS_PER_ANON_GLOBAL ,
1376
1377
} ;
1377
1378
1378
1379
Ok ( frame. with_extra ( extra) )
@@ -1518,4 +1519,40 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
1518
1519
Entry :: Occupied ( oe) => Ok ( oe. get ( ) . clone ( ) ) ,
1519
1520
}
1520
1521
}
1522
+
1523
+ fn get_global_alloc_salt (
1524
+ ecx : & InterpCx < ' tcx , Self > ,
1525
+ instance : Option < ty:: Instance < ' tcx > > ,
1526
+ ) -> usize {
1527
+ let unique = if let Some ( instance) = instance {
1528
+ // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
1529
+ // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
1530
+ // duplicated across crates. We thus generate a new `AllocId` for every mention of a
1531
+ // function. This means that `main as fn() == main as fn()` is false, while `let x = main as
1532
+ // fn(); x == x` is true. However, as a quality-of-life feature it can be useful to identify
1533
+ // certain functions uniquely, e.g. for backtraces. So we identify whether codegen will
1534
+ // actually emit duplicate functions. It does that when they have non-lifetime generics, or
1535
+ // when they can be inlined. All other functions are given a unique address.
1536
+ // This is not a stable guarantee! The `inline` attribute is a hint and cannot be relied
1537
+ // upon for anything. But if we don't do this, backtraces look terrible.
1538
+ let is_generic = instance
1539
+ . args
1540
+ . into_iter ( )
1541
+ . any ( |kind| !matches ! ( kind. unpack( ) , ty:: GenericArgKind :: Lifetime ( _) ) ) ;
1542
+ let can_be_inlined = match ecx. tcx . codegen_fn_attrs ( instance. def_id ( ) ) . inline {
1543
+ InlineAttr :: Never => false ,
1544
+ _ => true ,
1545
+ } ;
1546
+ !is_generic && !can_be_inlined
1547
+ } else {
1548
+ // Non-functions are never unique.
1549
+ false
1550
+ } ;
1551
+ // Always use the same salt if the allocation is unique.
1552
+ if unique {
1553
+ CTFE_ALLOC_SALT
1554
+ } else {
1555
+ ecx. machine . rng . borrow_mut ( ) . gen :: < usize > ( ) % ADDRS_PER_ANON_GLOBAL
1556
+ }
1557
+ }
1521
1558
}
0 commit comments