@@ -11,6 +11,7 @@ use rand::rngs::StdRng;
1111use rand:: Rng ;
1212use rand:: SeedableRng ;
1313
14+ use rustc_attr:: InlineAttr ;
1415use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
1516#[ allow( unused) ]
1617use rustc_data_structures:: static_assert_size;
@@ -47,10 +48,10 @@ pub const SIGRTMIN: i32 = 34;
4748/// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`)
4849pub const SIGRTMAX : i32 = 42 ;
4950
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 ;
5455
5556/// Extra data stored with each stack frame
5657pub struct FrameExtra < ' tcx > {
@@ -1372,7 +1373,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
13721373 catch_unwind : None ,
13731374 timing,
13741375 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 ,
13761377 } ;
13771378
13781379 Ok ( frame. with_extra ( extra) )
@@ -1518,4 +1519,40 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
15181519 Entry :: Occupied ( oe) => Ok ( oe. get ( ) . clone ( ) ) ,
15191520 }
15201521 }
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+ }
15211558}
0 commit comments