author | Margareta Eliza Balazs <ebalazs@mozilla.com> |
Tue, 14 Aug 2018 12:30:50 +0300 | |
changeset 431377 | 914b3b370ad059a04ad751642b74e013f8e3ad08 |
parent 431376 | 3e66cf1dad95c1594448d82bcac82711f8ba155e (current diff) |
parent 431327 | 397dbf4d571f60282bed90ce11918adfae99b0d1 (diff) |
child 431378 | a12c995d61221cbeea9a53d48e5443f87d2d28ce |
child 431451 | a62c083163d60a523e2d3cae38c6b1a8adac0817 |
child 431461 | 0360d2d3a79a0fc685b65717ee7b4a9310013985 |
push id | 106435 |
push user | ebalazs@mozilla.com |
push date | Tue, 14 Aug 2018 09:36:55 +0000 |
treeherder | mozilla-inbound@a12c995d6122 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 63.0a1 |
first release with | nightly linux32
914b3b370ad0
/
63.0a1
/
20180814100100
/
files
nightly linux64
914b3b370ad0
/
63.0a1
/
20180814100100
/
files
nightly mac
914b3b370ad0
/
63.0a1
/
20180814100100
/
files
nightly win32
914b3b370ad0
/
63.0a1
/
20180814100100
/
files
nightly win64
914b3b370ad0
/
63.0a1
/
20180814100100
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
63.0a1
/
20180814100100
/
pushlog to previous
nightly linux64
63.0a1
/
20180814100100
/
pushlog to previous
nightly mac
63.0a1
/
20180814100100
/
pushlog to previous
nightly win32
63.0a1
/
20180814100100
/
pushlog to previous
nightly win64
63.0a1
/
20180814100100
/
pushlog to previous
|
--- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -707,17 +707,17 @@ nsIntRect Accessible::Bounds() const { return BoundsInAppUnits().ToNearestPixels(mDoc->PresContext()->AppUnitsPerDevPixel()); } nsIntRect Accessible::BoundsInCSSPixels() const { - return BoundsInAppUnits().ToNearestPixels(mDoc->PresContext()->AppUnitsPerCSSPixel()); + return BoundsInAppUnits().ToNearestPixels(AppUnitsPerCSSPixel()); } void Accessible::SetSelected(bool aSelect) { if (!HasOwnContent()) return;
--- a/build/debian-packages/valgrind-wheezy.diff +++ b/build/debian-packages/valgrind-wheezy.diff @@ -1,4821 +1,75 @@ -diff -Nru valgrind-3.13.0/debian/changelog valgrind-3.13.0/debian/changelog ---- valgrind-3.13.0/debian/changelog 2017-07-24 08:41:05.000000000 +0900 -+++ valgrind-3.13.0/debian/changelog 2018-01-11 17:08:25.000000000 +0900 -@@ -1,3 +1,13 @@ -+valgrind (1:3.13.0-1.deb7moz1) wheezy; urgency=medium -+ -+ * Mozilla backport for wheezy. -+ * debian/patches/valgrind-epochs.patch: Apply patch from Julian Seward that -+ allows us to write a suppression for a leak in a library that gets -+ unloaded before shutdown. -+ Ref: https://bugs.kde.org/show_bug.cgi?id=79362 -+ -+ -- Mike Hommey <glandium@debian.org> Thu, 11 Jan 2018 17:08:25 +0900 -+ - valgrind (1:3.13.0-1) unstable; urgency=medium +diff -Nru valgrind-3.13.0/debian/patches/05_fix-callgrind_control.patch valgrind-3.14.0.git20180806/debian/patches/05_fix-callgrind_control.patch +--- valgrind-3.13.0/debian/patches/05_fix-callgrind_control.patch 2017-07-24 08:41:05.000000000 +0900 ++++ valgrind-3.14.0.git20180806/debian/patches/05_fix-callgrind_control.patch 2018-08-10 16:00:19.142494503 +0900 +@@ -7,9 +7,9 @@ - * New upstream release -diff -Nru valgrind-3.13.0/debian/patches/series valgrind-3.13.0/debian/patches/series + --- a/callgrind/callgrind_control.in + +++ b/callgrind/callgrind_control.in +-@@ -29,7 +29,7 @@ ++@@ -33,7 +33,7 @@ + @pids = (); +- open LIST, "vgdb $vgdbPrefixOption -l|"; ++ open LIST, $vgdb_exe . " $vgdbPrefixOption -l|"; + while(<LIST>) { + - if (/^use --pid=(\d+) for \S*?valgrind\s+(.*?)\s*$/) { + + if (/^use --pid=(\d+) for \S*?valgrind\.bin\s+(.*?)\s*$/) { +diff -Nru valgrind-3.13.0/debian/patches/07_fix-spelling-in-binary.patch valgrind-3.14.0.git20180806/debian/patches/07_fix-spelling-in-binary.patch +--- valgrind-3.13.0/debian/patches/07_fix-spelling-in-binary.patch 2017-07-24 08:41:05.000000000 +0900 ++++ valgrind-3.14.0.git20180806/debian/patches/07_fix-spelling-in-binary.patch 2018-08-10 16:01:46.110793537 +0900 +@@ -16,7 +16,7 @@ + && VKI_S_ISREG(stat_buf.mode) + --- a/coregrind/m_gdbserver/server.c + +++ b/coregrind/m_gdbserver/server.c +-@@ -254,7 +254,7 @@ ++@@ -256,7 +256,7 @@ + " Valgrind internal host status/memory\n" + " v.translate <addr> [<traceflags>] : debug translation of <addr> with <traceflags>\n" + " (default traceflags 0b00100000 : show after instrumentation)\n" +@@ -27,7 +27,7 @@ + case 1: /* v.set */ + --- a/VEX/priv/ir_defs.c + +++ b/VEX/priv/ir_defs.c +-@@ -4643,7 +4643,7 @@ ++@@ -4698,7 +4698,7 @@ + if (bb->stmts_used < 0 || bb->stmts_size < 8 + || bb->stmts_used > bb->stmts_size) + /* this BB is so strange we can't even print it */ +@@ -60,7 +60,7 @@ + " N-plicated elts\n"); + --- a/coregrind/m_scheduler/scheduler.c + +++ b/coregrind/m_scheduler/scheduler.c +-@@ -2147,7 +2147,7 @@ ++@@ -2208,7 +2208,7 @@ + "to recompile such code, using the header files from this version of\n" + "Valgrind, and not any previous version.\n" + "\n" +@@ -71,7 +71,7 @@ + " http://www.valgrind.org/support/bug_reports.html\n" + --- a/coregrind/m_xtree.c + +++ b/coregrind/m_xtree.c +-@@ -946,7 +946,7 @@ ++@@ -961,7 +961,7 @@ + FP("n%u: %llu %s\n", n_groups, top_total, header->top_node_desc); + + /* Output depth 0 groups. */ +diff -Nru valgrind-3.13.0/debian/patches/09_fix-armhf-detect.patch valgrind-3.14.0.git20180806/debian/patches/09_fix-armhf-detect.patch +--- valgrind-3.13.0/debian/patches/09_fix-armhf-detect.patch 2017-07-24 08:41:05.000000000 +0900 ++++ valgrind-3.14.0.git20180806/debian/patches/09_fix-armhf-detect.patch 2018-08-10 16:02:01.462846319 +0900 +@@ -6,7 +6,7 @@ + + --- a/configure.ac + +++ b/configure.ac +-@@ -234,7 +234,7 @@ ++@@ -252,7 +252,7 @@ + ARCH_MAX="s390x" + ;; + +diff -Nru valgrind-3.13.0/debian/patches/series valgrind-3.14.0.git20180806/debian/patches/series --- valgrind-3.13.0/debian/patches/series 2017-07-24 08:41:05.000000000 +0900 -+++ valgrind-3.13.0/debian/patches/series 2018-01-11 17:08:25.000000000 +0900 -@@ -4,3 +4,4 @@ ++++ valgrind-3.14.0.git20180806/debian/patches/series 2018-08-10 15:59:43.434371705 +0900 +@@ -2,5 +2,4 @@ + 04_workaround-SIGSEGV-on-PPC.patch + 05_fix-callgrind_control.patch 07_fix-spelling-in-binary.patch - 08_fix-spelling-in-manpage.patch +-08_fix-spelling-in-manpage.patch 09_fix-armhf-detect.patch -+valgrind-epochs.patch -diff -Nru valgrind-3.13.0/debian/patches/valgrind-epochs.patch valgrind-3.13.0/debian/patches/valgrind-epochs.patch ---- valgrind-3.13.0/debian/patches/valgrind-epochs.patch 1970-01-01 09:00:00.000000000 +0900 -+++ valgrind-3.13.0/debian/patches/valgrind-epochs.patch 2018-01-11 17:08:25.000000000 +0900 -@@ -0,0 +1,4792 @@ -+Index: valgrind-3.13.0/Makefile.am -+=================================================================== -+--- valgrind-3.13.0.orig/Makefile.am -++++ valgrind-3.13.0/Makefile.am -+@@ -16,6 +16,10 @@ EXP_TOOLS = exp-sgcheck \ -+ exp-bbv \ -+ exp-dhat -+ -++#TOOLS = none memcheck -++#EXP_TOOLS = -++ -++ -+ # Put docs last because building the HTML is slow and we want to get -+ # everything else working before we try it. -+ SUBDIRS = \ -+Index: valgrind-3.13.0/cachegrind/cg_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/cachegrind/cg_main.c -++++ valgrind-3.13.0/cachegrind/cg_main.c -+@@ -210,12 +210,14 @@ static HChar* get_perm_string(const HCha -+ static void get_debug_info(Addr instr_addr, const HChar **dir, -+ const HChar **file, const HChar **fn, UInt* line) -+ { -++ DiEpoch ep = VG_(current_DiEpoch)(); -+ Bool found_file_line = VG_(get_filename_linenum)( -++ ep, -+ instr_addr, -+ file, dir, -+ line -+ ); -+- Bool found_fn = VG_(get_fnname)(instr_addr, fn); -++ Bool found_fn = VG_(get_fnname)(ep, instr_addr, fn); -+ -+ if (!found_file_line) { -+ *file = "???"; -+Index: valgrind-3.13.0/callgrind/bb.c -+=================================================================== -+--- valgrind-3.13.0.orig/callgrind/bb.c -++++ valgrind-3.13.0/callgrind/bb.c -+@@ -199,7 +199,8 @@ obj_node* obj_of_address(Addr addr) -+ DebugInfo* di; -+ PtrdiffT offset; -+ -+- di = VG_(find_DebugInfo)(addr); -++ DiEpoch ep = VG_(current_DiEpoch)(); -++ di = VG_(find_DebugInfo)(ep, addr); -+ obj = CLG_(get_obj_node)( di ); -+ -+ /* Update symbol offset in object if remapped */ -+Index: valgrind-3.13.0/callgrind/dump.c -+=================================================================== -+--- valgrind-3.13.0.orig/callgrind/dump.c -++++ valgrind-3.13.0/callgrind/dump.c -+@@ -373,7 +373,8 @@ Bool get_debug_pos(BBCC* bbcc, Addr addr -+ found_file_line = debug_cache_info[cachepos]; -+ } -+ else { -+- found_file_line = VG_(get_filename_linenum)(addr, -++ DiEpoch ep = VG_(current_DiEpoch)(); -++ found_file_line = VG_(get_filename_linenum)(ep, addr, -+ &file, -+ &dir, -+ &(p->line)); -+Index: valgrind-3.13.0/callgrind/fn.c -+=================================================================== -+--- valgrind-3.13.0.orig/callgrind/fn.c -++++ valgrind-3.13.0/callgrind/fn.c -+@@ -434,17 +434,18 @@ Bool CLG_(get_debug_info)(Addr instr_add -+ -+ CLG_DEBUG(6, " + get_debug_info(%#lx)\n", instr_addr); -+ -++ DiEpoch ep = VG_(current_DiEpoch)(); -+ if (pDebugInfo) { -+- *pDebugInfo = VG_(find_DebugInfo)(instr_addr); -++ *pDebugInfo = VG_(find_DebugInfo)(ep, instr_addr); -+ -+ // for generated code in anonymous space, pSegInfo is 0 -+ } -+ -+- found_file_line = VG_(get_filename_linenum)(instr_addr, -++ found_file_line = VG_(get_filename_linenum)(ep, instr_addr, -+ file, -+ dir, -+ &line); -+- found_fn = VG_(get_fnname)(instr_addr, fn_name); -++ found_fn = VG_(get_fnname)(ep, instr_addr, fn_name); -+ -+ if (!found_file_line && !found_fn) { -+ CLG_(stat).no_debug_BBs++; -+@@ -503,6 +504,7 @@ fn_node* CLG_(get_fn_node)(BB* bb) -+ CLG_(get_debug_info)(bb_addr(bb), -+ &dirname, &filename, &fnname, &line_num, &di); -+ -++ DiEpoch ep = VG_(current_DiEpoch)(); -+ if (0 == VG_(strcmp)(fnname, "???")) { -+ int p; -+ static HChar buf[32]; // for sure large enough -+@@ -521,7 +523,7 @@ fn_node* CLG_(get_fn_node)(BB* bb) -+ fnname = buf; -+ } -+ else { -+- if (VG_(get_fnname_if_entry)(bb_addr(bb), &fnname)) -++ if (VG_(get_fnname_if_entry)(ep, bb_addr(bb), &fnname)) -+ bb->is_entry = 1; -+ } -+ -+Index: valgrind-3.13.0/coregrind/m_addrinfo.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_addrinfo.c -++++ valgrind-3.13.0/coregrind/m_addrinfo.c -+@@ -86,7 +86,7 @@ static ThreadId find_tid_with_stack_cont -+ return VG_INVALID_THREADID; -+ } -+ -+-void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai ) -++void VG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai ) -+ { -+ VgSectKind sect; -+ -+@@ -99,7 +99,7 @@ void VG_(describe_addr) ( Addr a, /*OUT* -+ VG_(free), sizeof(HChar) ); -+ -+ (void) VG_(get_data_description)( ai->Addr.Variable.descr1, -+- ai->Addr.Variable.descr2, a ); -++ ai->Addr.Variable.descr2, ep, a ); -+ /* If there's nothing in descr1/2, free them. Why is it safe to -+ VG_(indexXA) at zero here? Because VG_(get_data_description) -+ guarantees to zero terminate descr1/2 regardless of the outcome -+@@ -127,7 +127,7 @@ void VG_(describe_addr) ( Addr a, /*OUT* -+ there. -- */ -+ const HChar *name; -+ if (VG_(get_datasym_and_offset)( -+- a, &name, -++ ep, a, &name, -+ &ai->Addr.DataSym.offset )) { -+ ai->Addr.DataSym.name = VG_(strdup)("mc.da.dsname", name); -+ ai->tag = Addr_DataSym; -+@@ -148,6 +148,7 @@ void VG_(describe_addr) ( Addr a, /*OUT* -+ ai->tag = Addr_Stack; -+ VG_(initThreadInfo)(&ai->Addr.Stack.tinfo); -+ ai->Addr.Stack.tinfo.tid = tid; -++ ai->Addr.Stack.epoch = ep; -+ ai->Addr.Stack.IP = 0; -+ ai->Addr.Stack.frameNo = -1; -+ ai->Addr.Stack.stackPos = StackPos_stacked; -+@@ -196,9 +197,9 @@ void VG_(describe_addr) ( Addr a, /*OUT* -+ ai->Addr.Block.block_desc = aai.name; -+ ai->Addr.Block.block_szB = aai.block_szB; -+ ai->Addr.Block.rwoffset = aai.rwoffset; -+- ai->Addr.Block.allocated_at = VG_(null_ExeContext)(); -++ ai->Addr.Block.allocated_at = VG_(null_ExeContextAndEpoch)(); -+ VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo); -+- ai->Addr.Block.freed_at = VG_(null_ExeContext)(); -++ ai->Addr.Block.freed_at = VG_(null_ExeContextAndEpoch)(); -+ return; -+ } -+ } -+@@ -248,6 +249,7 @@ void VG_(describe_addr) ( Addr a, /*OUT* -+ ai->tag = Addr_Stack; -+ VG_(initThreadInfo)(&ai->Addr.Stack.tinfo); -+ ai->Addr.Stack.tinfo.tid = tid; -++ ai->Addr.Stack.epoch = ep; -+ ai->Addr.Stack.IP = 0; -+ ai->Addr.Stack.frameNo = -1; -+ vg_assert (stackPos != StackPos_stacked); -+@@ -447,20 +449,24 @@ static void pp_addrinfo_WRK ( Addr a, co -+ Bool haslinenum; -+ PtrdiffT offset; -+ -+- if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.IP, -++ if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.epoch, -++ ai->Addr.Stack.IP, -+ &offset)) -+- haslinenum = VG_(get_linenum) (ai->Addr.Stack.IP - offset, -++ haslinenum = VG_(get_linenum) (ai->Addr.Stack.epoch, -++ ai->Addr.Stack.IP - offset, -+ &linenum); -+ else -+ haslinenum = False; -+ -+- hasfile = VG_(get_filename)(ai->Addr.Stack.IP, &file); -++ hasfile = VG_(get_filename)(ai->Addr.Stack.epoch, -++ ai->Addr.Stack.IP, &file); -+ -+ HChar strlinenum[16] = ""; // large enough -+ if (hasfile && haslinenum) -+ VG_(sprintf)(strlinenum, "%u", linenum); -+ -+- hasfn = VG_(get_fnname)(ai->Addr.Stack.IP, &fn); -++ hasfn = VG_(get_fnname)(ai->Addr.Stack.epoch, -++ ai->Addr.Stack.IP, &fn); -+ -+ if (hasfn || hasfile) -+ VG_(emit)( "%sin frame #%d, created by %ps (%ps:%s)%s\n", -+@@ -533,32 +539,35 @@ static void pp_addrinfo_WRK ( Addr a, co -+ xpost -+ ); -+ if (ai->Addr.Block.block_kind==Block_Mallocd) { -+- VG_(pp_ExeContext)(ai->Addr.Block.allocated_at); -+- vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)()); -++ VG_(pp_ExeContextAndEpoch)(ai->Addr.Block.allocated_at); -++ vg_assert( -++ VG_(is_null_ExeContextAndEpoch)(ai->Addr.Block.freed_at)); -+ } -+ else if (ai->Addr.Block.block_kind==Block_Freed) { -+- VG_(pp_ExeContext)(ai->Addr.Block.freed_at); -+- if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) { -++ VG_(pp_ExeContextAndEpoch)(ai->Addr.Block.freed_at); -++ if (!VG_(is_null_ExeContextAndEpoch)(ai->Addr.Block.allocated_at)) { -+ VG_(emit)( -+ "%sBlock was alloc'd at%s\n", -+ xpre, -+ xpost -+ ); -+- VG_(pp_ExeContext)(ai->Addr.Block.allocated_at); -++ VG_(pp_ExeContextAndEpoch)(ai->Addr.Block.allocated_at); -+ } -+ } -+ else if (ai->Addr.Block.block_kind==Block_MempoolChunk -+ || ai->Addr.Block.block_kind==Block_UserG) { -+ // client-defined -+- VG_(pp_ExeContext)(ai->Addr.Block.allocated_at); -+- vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)()); -++ VG_(pp_ExeContextAndEpoch)(ai->Addr.Block.allocated_at); -++ vg_assert(VG_(is_null_ExeContextAndEpoch)(ai->Addr.Block.freed_at)); -+ /* Nb: cannot have a freed_at, as a freed client-defined block -+ has a Block_Freed block_kind. */ -+ } else { -+ // Client or Valgrind arena. At least currently, we never -+ // have stacktraces for these. -+- vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)()); -+- vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)()); -++ vg_assert(VG_(is_null_ExeContextAndEpoch) -++ (ai->Addr.Block.allocated_at)); -++ vg_assert(VG_(is_null_ExeContextAndEpoch) -++ (ai->Addr.Block.freed_at)); -+ } -+ if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid) -+ VG_(emit)( -+@@ -603,7 +612,7 @@ static void pp_addrinfo_WRK ( Addr a, co -+ if (ai->Addr.SectKind.kind == Vg_SectText) { -+ /* To better describe the address in a text segment, -+ pp a dummy stacktrace made of this single address. */ -+- VG_(pp_StackTrace)( &a, 1 ); -++ VG_(pp_StackTrace)( VG_(current_DiEpoch)(), &a, 1 ); -+ } -+ break; -+ -+Index: valgrind-3.13.0/coregrind/m_debuginfo/debuginfo.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_debuginfo/debuginfo.c -++++ valgrind-3.13.0/coregrind/m_debuginfo/debuginfo.c -+@@ -70,6 +70,10 @@ -+ should-we-load-debuginfo-now? finite state machine. */ -+ #define DEBUG_FSM 0 -+ -++/* Set this to 1 to enable somewhat minimal debug printing for the -++ debuginfo-epoch machinery. */ -++#define DEBUG_EPOCHS 0 -++ -+ -+ /*------------------------------------------------------------*/ -+ /*--- The _svma / _avma / _image / _bias naming scheme ---*/ -+@@ -109,6 +113,116 @@ static void caches__invalidate (void); -+ -+ -+ /*------------------------------------------------------------*/ -++/*--- Epochs ---*/ -++/*------------------------------------------------------------*/ -++ -++/* The DebugInfo epoch is incremented every time we either load debuginfo in -++ response to an object mapping, or an existing DebugInfo becomes -++ non-current (or will be discarded) due to an object unmap. By storing, -++ in each DebugInfo, the first and last epoch for which it is valid, we can -++ unambiguously identify the set of DebugInfos which should be used to -++ provide metadata for a code or data address, provided we know the epoch -++ to which that address pertains. -++ -++ Note, this isn't the same as the "handle_counter" below. That only -++ advances when new DebugInfos are created. "current_epoch" advances both -++ at DebugInfo created and destruction-or-making-non-current. -++*/ -++ -++// The value zero is reserved for indicating an invalid epoch number. -++static UInt current_epoch = 1; -++ -++inline DiEpoch VG_(current_DiEpoch) ( void ) { -++ DiEpoch dep; dep.n = current_epoch; return dep; -++} -++ -++static void advance_current_DiEpoch ( const HChar* msg ) { -++ current_epoch++; -++ if (DEBUG_EPOCHS) -++ VG_(printf)("Advancing current epoch to %u due to %s\n", -++ current_epoch, msg); -++} -++ -++static inline Bool eq_DiEpoch ( DiEpoch dep1, DiEpoch dep2 ) { -++ return dep1.n == dep2.n && /*neither is invalid*/dep1.n != 0; -++} -++ -++// Is this DebugInfo currently "allocated" (pre-use state, only FSM active) ? -++static inline Bool is_DebugInfo_allocated ( const DebugInfo* di ) -++{ -++ if (is_DiEpoch_INVALID(di->first_epoch) -++ && is_DiEpoch_INVALID(di->last_epoch)) { -++ return True; -++ } else { -++ return False; -++ } -++} -++ -++// Is this DebugInfo currently "active" (valid for the current epoch) ? -++static inline Bool is_DebugInfo_active ( const DebugInfo* di ) -++{ -++ if (!is_DiEpoch_INVALID(di->first_epoch) -++ && is_DiEpoch_INVALID(di->last_epoch)) { -++ // Yes it is active. Sanity check .. -++ tl_assert(di->first_epoch.n <= current_epoch); -++ return True; -++ } else { -++ return False; -++ } -++} -++ -++// Is this DebugInfo currently "archived" ? -++static inline Bool is_DebugInfo_archived ( const DebugInfo* di ) -++{ -++ if (!is_DiEpoch_INVALID(di->first_epoch) -++ && !is_DiEpoch_INVALID(di->last_epoch)) { -++ // Yes it is archived. Sanity checks .. -++ tl_assert(di->first_epoch.n <= di->last_epoch.n); -++ tl_assert(di->last_epoch.n <= current_epoch); -++ return True; -++ } else { -++ return False; -++ } -++} -++ -++// Is this DebugInfo valid for the specified epoch? -++static inline Bool is_DI_valid_for_epoch ( const DebugInfo* di, DiEpoch ep ) -++{ -++ // Stay sane -++ vg_assert(ep.n > 0 && ep.n <= current_epoch); -++ -++ Bool first_valid = !is_DiEpoch_INVALID(di->first_epoch); -++ Bool last_valid = !is_DiEpoch_INVALID(di->last_epoch); -++ -++ if (first_valid) { -++ if (last_valid) { -++ // Both valid. di is in Archived state. -++ return di->first_epoch.n <= ep.n && ep.n <= di->last_epoch.n; -++ } else { -++ // First is valid, last is invalid. di is in Active state. -++ return di->first_epoch.n <= ep.n; -++ } -++ } else { -++ if (last_valid) { -++ // First is invalid, last is valid. This is an impossible state. -++ vg_assert(0); -++ /*NOTREACHED*/ -++ return False; -++ } else { -++ // Neither is valid. di is in Allocated state. -++ return False; -++ } -++ } -++ -++} -++ -++static inline UInt ROL32 ( UInt x, UInt n ) -++{ -++ return (x << n) | (x >> (32-n)); -++} -++ -++ -++/*------------------------------------------------------------*/ -+ /*--- Root structure ---*/ -+ /*------------------------------------------------------------*/ -+ -+@@ -162,6 +276,23 @@ static void move_DebugInfo_one_step_forw -+ } -+ -+ -++// Debugging helper for epochs -++static void show_epochs ( const HChar* msg ) -++{ -++ if (DEBUG_EPOCHS) { -++ DebugInfo* di; -++ VG_(printf)("\nDebugInfo epoch display, requested by \"%s\"\n", msg); -++ VG_(printf)(" Current epoch (note: 0 means \"invalid epoch\") = %u\n", -++ current_epoch); -++ for (di = debugInfo_list; di; di = di->next) { -++ VG_(printf)(" [di=%p] first %u last %u %s\n", -++ di, di->first_epoch.n, di->last_epoch.n, di->fsm.filename); -++ } -++ VG_(printf)("\n"); -++ } -++} -++ -++ -+ /*------------------------------------------------------------*/ -+ /*--- Notification (acquire/discard) helpers ---*/ -+ /*------------------------------------------------------------*/ -+@@ -182,6 +313,8 @@ DebugInfo* alloc_DebugInfo( const HChar* -+ -+ di = ML_(dinfo_zalloc)("di.debuginfo.aDI.1", sizeof(DebugInfo)); -+ di->handle = handle_counter++; -++ di->first_epoch = DiEpoch_INVALID(); -++ di->last_epoch = DiEpoch_INVALID(); -+ di->fsm.filename = ML_(dinfo_strdup)("di.debuginfo.aDI.2", filename); -+ di->fsm.maps = VG_(newXA)( -+ ML_(dinfo_zalloc), "di.debuginfo.aDI.3", -+@@ -302,34 +435,52 @@ static void free_DebugInfo ( DebugInfo* -+ } -+ -+ -+-/* 'si' is a member of debugInfo_list. Find it, remove it from the -+- list, notify m_redir that this has happened, and free all storage -+- reachable from it. -++/* 'di' is a member of debugInfo_list. Find it, and either (remove it from -++ the list and free all storage reachable from it) or archive it, notify -++ m_redir that this has happened, and free all storage reachable from it. -++ -++ Note that 'di' can't be archived. Is a DebugInfo is archived then we -++ want to hold on to it forever. This is asserted for. -++ -++ Note also, we don't advance the current epoch here. That's the -++ responsibility of some (non-immediate) caller. -+ */ -+-static void discard_DebugInfo ( DebugInfo* di ) -++static void discard_or_archive_DebugInfo ( DebugInfo* di ) -+ { -+- const HChar* reason = "munmap"; -++ const HChar* reason = "munmap"; -++ const Bool archive = VG_(clo_keep_debuginfo); -+ -+ DebugInfo** prev_next_ptr = &debugInfo_list; -+ DebugInfo* curr = debugInfo_list; -+ -+ while (curr) { -+ if (curr == di) { -+- /* Found it; remove from list and free it. */ -++ /* It must be active! */ -++ vg_assert( is_DebugInfo_active(di)); -++ /* Found it; (remove from list and free it), or archive it. */ -+ if (curr->have_dinfo -+ && (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir))) -+ VG_(message)(Vg_DebugMsg, -+- "Discarding syms at %#lx-%#lx in %s due to %s()\n", -++ "%s syms at %#lx-%#lx in %s due to %s()\n", -++ archive ? "Archiving" : "Discarding", -+ di->text_avma, -+ di->text_avma + di->text_size, -+ curr->fsm.filename ? curr->fsm.filename -+ : "???", -+ reason); -+ vg_assert(*prev_next_ptr == curr); -+- *prev_next_ptr = curr->next; -+- if (curr->have_dinfo) -++ if (!archive) { -++ *prev_next_ptr = curr->next; -++ } -++ if (curr->have_dinfo) { -+ VG_(redir_notify_delete_DebugInfo)( curr ); -+- free_DebugInfo(curr); -++ } -++ if (archive) { -++ /* Adjust the epoch markers appropriately. */ -++ di->last_epoch = VG_(current_DiEpoch)(); -++ } else { -++ free_DebugInfo(curr); -++ } -+ return; -+ } -+ prev_next_ptr = &curr->next; -+@@ -358,10 +509,11 @@ static Bool discard_syms_in_range ( Addr -+ while (True) { -+ if (curr == NULL) -+ break; -+- if (curr->text_present -+- && curr->text_size > 0 -+- && (start+length - 1 < curr->text_avma -+- || curr->text_avma + curr->text_size - 1 < start)) { -++ if (is_DebugInfo_archived(curr) -++ || (curr->text_present -++ && curr->text_size > 0 -++ && (start+length - 1 < curr->text_avma -++ || curr->text_avma + curr->text_size - 1 < start))) { -+ /* no overlap */ -+ } else { -+ found = True; -+@@ -372,7 +524,7 @@ static Bool discard_syms_in_range ( Addr -+ -+ if (!found) break; -+ anyFound = True; -+- discard_DebugInfo( curr ); -++ discard_or_archive_DebugInfo( curr ); -+ } -+ -+ return anyFound; -+@@ -418,9 +570,9 @@ static Bool do_DebugInfos_overlap ( cons -+ } -+ -+ -+-/* Discard all elements of debugInfo_list whose .mark bit is set. -++/* Discard or archive all elements of debugInfo_list whose .mark bit is set. -+ */ -+-static void discard_marked_DebugInfos ( void ) -++static void discard_or_archive_marked_DebugInfos ( void ) -+ { -+ DebugInfo* curr; -+ -+@@ -436,7 +588,7 @@ static void discard_marked_DebugInfos ( -+ } -+ -+ if (!curr) break; -+- discard_DebugInfo( curr ); -++ discard_or_archive_DebugInfo( curr ); -+ -+ } -+ } -+@@ -446,19 +598,22 @@ static void discard_marked_DebugInfos ( -+ Clearly diRef must have its mapping information set to something sane. */ -+ static void discard_DebugInfos_which_overlap_with ( DebugInfo* diRef ) -+ { -++ vg_assert(is_DebugInfo_allocated(diRef)); -+ DebugInfo* di; -+ /* Mark all the DebugInfos in debugInfo_list that need to be -+ deleted. First, clear all the mark bits; then set them if they -+ overlap with siRef. Since siRef itself is in this list we at -+ least expect its own mark bit to be set. */ -+ for (di = debugInfo_list; di; di = di->next) { -++ if (is_DebugInfo_archived(di)) -++ continue; -+ di->mark = do_DebugInfos_overlap( di, diRef ); -+ if (di == diRef) { -+ vg_assert(di->mark); -+ di->mark = False; -+ } -+ } -+- discard_marked_DebugInfos(); -++ discard_or_archive_marked_DebugInfos(); -+ } -+ -+ -+@@ -470,6 +625,8 @@ static DebugInfo* find_or_create_DebugIn -+ DebugInfo* di; -+ vg_assert(filename); -+ for (di = debugInfo_list; di; di = di->next) { -++ if (is_DebugInfo_archived(di)) -++ continue; -+ vg_assert(di->fsm.filename); -+ if (0==VG_(strcmp)(di->fsm.filename, filename)) -+ break; -+@@ -480,6 +637,7 @@ static DebugInfo* find_or_create_DebugIn -+ di->next = debugInfo_list; -+ debugInfo_list = di; -+ } -++ vg_assert(!is_DebugInfo_archived(di)); -+ return di; -+ } -+ -+@@ -723,6 +881,8 @@ static ULong di_notify_ACHIEVE_ACCEPT_ST -+ ULong di_handle; -+ Bool ok; -+ -++ advance_current_DiEpoch("di_notify_ACHIEVE_ACCEPT_STATE"); -++ -+ vg_assert(di->fsm.filename); -+ TRACE_SYMTAB("\n"); -+ TRACE_SYMTAB("------ start ELF OBJECT " -+@@ -734,7 +894,8 @@ static ULong di_notify_ACHIEVE_ACCEPT_ST -+ /* We're going to read symbols and debug info for the avma -+ ranges specified in the _DebugInfoFsm mapping array. First -+ get rid of any other DebugInfos which overlap any of those -+- ranges (to avoid total confusion). */ -++ ranges (to avoid total confusion). But only those valid in -++ the current epoch. We don't want to discard archived DebugInfos. */ -+ discard_DebugInfos_which_overlap_with( di ); -+ -+ /* The DebugInfoMappings that now exist in the FSM may involve -+@@ -765,6 +926,15 @@ static ULong di_notify_ACHIEVE_ACCEPT_ST -+ priv_storage.h. */ -+ check_CFSI_related_invariants(di); -+ ML_(finish_CFSI_arrays)(di); -++ -++ // Mark di's first epoch point as a valid epoch. Because its -++ // last_epoch value is still invalid, this changes di's state from -++ // "allocated" to "active". -++ vg_assert(is_DebugInfo_allocated(di)); -++ di->first_epoch = VG_(current_DiEpoch)(); -++ vg_assert(is_DebugInfo_active(di)); -++ show_epochs("di_notify_ACHIEVE_ACCEPT_STATE success"); -++ -+ /* notify m_redir about it */ -+ TRACE_SYMTAB("\n------ Notifying m_redir ------\n"); -+ VG_(redir_notify_new_DebugInfo)( di ); -+@@ -1077,8 +1247,11 @@ void VG_(di_notify_munmap)( Addr a, Size -+ Bool anyFound; -+ if (0) VG_(printf)("DISCARD %#lx %#lx\n", a, a+len); -+ anyFound = discard_syms_in_range(a, len); -+- if (anyFound) -++ if (anyFound) { -+ caches__invalidate(); -++ advance_current_DiEpoch("VG_(di_notify_munmap)"); -++ show_epochs("VG_(di_notify_munmap)"); -++ } -+ } -+ -+ -+@@ -1094,8 +1267,10 @@ void VG_(di_notify_mprotect)( Addr a, Si -+ # endif -+ if (0 && !exe_ok) { -+ Bool anyFound = discard_syms_in_range(a, len); -+- if (anyFound) -++ if (anyFound) { -+ caches__invalidate(); -++ advance_current_DiEpoch("VG_(di_notify_mprotect)"); -++ } -+ } -+ } -+ -+@@ -1395,6 +1570,7 @@ void VG_(di_notify_pdb_debuginfo)( Int f -+ caches__invalidate(); -+ /* dump old info for this range, if any */ -+ discard_syms_in_range( avma_obj, total_size ); -++ advance_current_DiEpoch("VG_(di_notify_pdb_debuginfo)"); -+ -+ { DebugInfo* di = find_or_create_DebugInfo_for(exename); -+ -+@@ -1471,6 +1647,7 @@ DebugInfoMapping* ML_(find_rx_mapping) ( -+ /*------------------------------------------------------------*/ -+ /*--- Types and functions for inlined IP cursor ---*/ -+ /*------------------------------------------------------------*/ -++ -+ struct _InlIPCursor { -+ Addr eip; // Cursor used to describe calls at eip. -+ DebugInfo* di; // DebugInfo describing inlined calls at eip -+@@ -1534,8 +1711,8 @@ Bool VG_(next_IIPC)(InlIPCursor *iipc) -+ } -+ -+ /* Forward */ -+-static void search_all_loctabs ( Addr ptr, /*OUT*/DebugInfo** pdi, -+- /*OUT*/Word* locno ); -++static void search_all_loctabs ( DiEpoch ep, Addr ptr, -++ /*OUT*/DebugInfo** pdi, /*OUT*/Word* locno ); -+ -+ /* Returns the position after which eip would be inserted in inltab. -+ (-1 if eip should be inserted before position 0). -+@@ -1565,7 +1742,7 @@ static Word inltab_insert_pos (DebugInfo -+ return lo - 1; -+ } -+ -+-InlIPCursor* VG_(new_IIPC)(Addr eip) -++InlIPCursor* VG_(new_IIPC)(DiEpoch ep, Addr eip) -+ { -+ DebugInfo* di; -+ Word locno; -+@@ -1576,8 +1753,8 @@ InlIPCursor* VG_(new_IIPC)(Addr eip) -+ if (!VG_(clo_read_inline_info)) -+ return NULL; // No way we can find inlined calls. -+ -+- /* Search the DebugInfo for eip */ -+- search_all_loctabs ( eip, &di, &locno ); -++ /* Search the DebugInfo for (ep, eip) */ -++ search_all_loctabs ( ep, eip, &di, &locno ); -+ if (di == NULL || di->inltab_used == 0) -+ return NULL; // No di (with inltab) containing eip. -+ -+@@ -1641,8 +1818,8 @@ void VG_(delete_IIPC)(InlIPCursor *iipc) -+ If findText==True, only text symbols are searched for. -+ If findText==False, only data symbols are searched for. -+ */ -+-static void search_all_symtabs ( Addr ptr, /*OUT*/DebugInfo** pdi, -+- /*OUT*/Word* symno, -++static void search_all_symtabs ( DiEpoch ep, Addr ptr, -++ /*OUT*/DebugInfo** pdi, /*OUT*/Word* symno, -+ Bool findText ) -+ { -+ Word sno; -+@@ -1651,6 +1828,9 @@ static void search_all_symtabs ( Addr pt -+ -+ for (di = debugInfo_list; di != NULL; di = di->next) { -+ -++ if (!is_DI_valid_for_epoch(di, ep)) -++ continue; -++ -+ if (findText) { -+ /* Consider any symbol in the r-x mapped area to be text. -+ See Comment_Regarding_Text_Range_Checks in storage.c for -+@@ -1698,15 +1878,17 @@ static void search_all_symtabs ( Addr pt -+ } -+ -+ -+-/* Search all loctabs that we know about to locate ptr. If found, set -+- *pdi to the relevant DebugInfo, and *locno to the loctab entry -++/* Search all loctabs that we know about to locate ptr at epoch ep. If -++ *found, set pdi to the relevant DebugInfo, and *locno to the loctab entry -+ *number within that. If not found, *pdi is set to NULL. */ -+-static void search_all_loctabs ( Addr ptr, /*OUT*/DebugInfo** pdi, -+- /*OUT*/Word* locno ) -++static void search_all_loctabs ( DiEpoch ep, Addr ptr, -++ /*OUT*/DebugInfo** pdi, /*OUT*/Word* locno ) -+ { -+ Word lno; -+ DebugInfo* di; -+ for (di = debugInfo_list; di != NULL; di = di->next) { -++ if (!is_DI_valid_for_epoch(di, ep)) -++ continue; -+ if (di->text_present -+ && di->text_size > 0 -+ && di->text_avma <= ptr -+@@ -1729,19 +1911,22 @@ static void search_all_loctabs ( Addr pt -+ -+ typedef -+ struct { -+- Addr sym_avma; -++ // (sym_epoch, sym_avma) are the hash table key. -++ DiEpoch sym_epoch; -++ Addr sym_avma; -++ // Fields below here are not part of the key. -+ const HChar* sym_name; -+ PtrdiffT offset : (sizeof(PtrdiffT)*8)-1; -+ Bool isText : 1; -+ } -+ Sym_Name_CacheEnt; -+-/* Sym_Name_CacheEnt associates a queried address to the sym name found. -+- By nature, if a sym name was found, it means the searched address -+- stored in the cache is an avma (see e.g. search_all_symtabs). -+- Note however that the caller is responsibe to work with 'avma' -+- addresses e.g. when calling VG_(get_fnname) : m_debuginfo.c has -+- no way to differentiate an 'svma a' from an 'avma a'. It is however -+- unlikely that svma would percolate outside of this module. */ -++/* Sym_Name_CacheEnt associates a queried (epoch, address) pair to the sym -++ name found. By nature, if a sym name was found, it means the searched -++ address stored in the cache is an avma (see e.g. search_all_symtabs). -++ Note however that the caller is responsibe to work with 'avma' addresses -++ e.g. when calling VG_(get_fnname) : m_debuginfo.c has no way to -++ differentiate an 'svma a' from an 'avma a'. It is however unlikely that -++ svma would percolate outside of this module. */ -+ -+ static Sym_Name_CacheEnt sym_name_cache[N_SYM_NAME_CACHE]; -+ -+@@ -1757,13 +1942,15 @@ static void sym_name_cache__invalidate ( -+ sym_name_cache[0].sym_name = no_sym_name; -+ } -+ -+-/* The whole point of this whole big deal: map a code address to a -+- plausible symbol name. Returns False if no idea; otherwise True. -++/* The whole point of this whole big deal: map an (epoch, code address) pair -++ to a plausible symbol name. Returns False if no idea; otherwise True. -++ -+ Caller supplies buf. If do_cxx_demangling is False, don't do -+ C++ demangling, regardless of VG_(clo_demangle) -- probably because the -+ call has come from VG_(get_fnname_raw)(). findText -+ indicates whether we're looking for a text symbol or a data symbol -+ -- caller must choose one kind or the other. -++ -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership -+ in pub_tool_debuginfo.h -+ get_sym_name and the fact it calls the demangler is the main reason -+@@ -1772,22 +1959,32 @@ static void sym_name_cache__invalidate ( -+ (1) the DebugInfo it belongs to is not discarded -+ (2) the demangler is not invoked again -+ Also, the returned string is owned by "somebody else". Callers must -+- not free it or modify it.*/ -++ not free it or modify it. */ -+ static -+ Bool get_sym_name ( Bool do_cxx_demangling, Bool do_z_demangling, -+ Bool do_below_main_renaming, -+- Addr a, const HChar** buf, -++ DiEpoch ep, Addr a, const HChar** buf, -+ Bool match_anywhere_in_sym, Bool show_offset, -+ Bool findText, /*OUT*/PtrdiffT* offsetP ) -+ { -+- UWord hash = a % N_SYM_NAME_CACHE; -+- Sym_Name_CacheEnt* se = &sym_name_cache[hash]; -++ // Compute the hash from 'ep' and 'a'. The latter contains lots of -++ // significant bits, but 'ep' is expected to be a small number, typically -++ // less than 500. So rotate it around a bit in the hope of spreading the -++ // bits out somewhat. -++ vg_assert(!is_DiEpoch_INVALID(ep)); -++ UWord hash = a ^ (UWord)(ep.n ^ ROL32(ep.n, 5) -++ ^ ROL32(ep.n, 13) ^ ROL32(ep.n, 19)); -++ hash %= N_SYM_NAME_CACHE; -++ -++ Sym_Name_CacheEnt* se = &sym_name_cache[hash]; -+ -+- if (UNLIKELY(se->sym_avma != a || se->isText != findText)) { -++ if (UNLIKELY(se->sym_epoch.n != ep.n || se->sym_avma != a -++ || se->isText != findText)) { -+ DebugInfo* di; -+ Word sno; -+ -+- search_all_symtabs ( a, &di, &sno, findText ); -++ search_all_symtabs ( ep, a, &di, &sno, findText ); -++ se->sym_epoch = ep; -+ se->sym_avma = a; -+ se->isText = findText; -+ if (di == NULL || a == 0) -+@@ -1846,12 +2043,12 @@ Bool get_sym_name ( Bool do_cxx_demangli -+ /* ppc64be-linux only: find the TOC pointer (R2 value) that should be in -+ force at the entry point address of the function containing -+ guest_code_addr. Returns 0 if not known. */ -+-Addr VG_(get_tocptr) ( Addr guest_code_addr ) -++Addr VG_(get_tocptr) ( DiEpoch ep, Addr guest_code_addr ) -+ { -+ #if defined(VGA_ppc64be) || defined(VGA_ppc64le) -+ DebugInfo* si; -+ Word sno; -+- search_all_symtabs ( guest_code_addr, -++ search_all_symtabs ( ep, guest_code_addr, -+ &si, &sno, -+ True/*consider text symbols only*/ ); -+ if (si == NULL) -+@@ -1867,11 +2064,11 @@ Addr VG_(get_tocptr) ( Addr guest_code_a -+ match anywhere in function, but don't show offsets. -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership -+ in pub_tool_debuginfo.h */ -+-Bool VG_(get_fnname) ( Addr a, const HChar** buf ) -++Bool VG_(get_fnname) ( DiEpoch ep, Addr a, const HChar** buf ) -+ { -+ return get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True, -+ /*below-main-renaming*/True, -+- a, buf, -++ ep, a, buf, -+ /*match_anywhere_in_fun*/True, -+ /*show offset?*/False, -+ /*text sym*/True, -+@@ -1882,11 +2079,11 @@ Bool VG_(get_fnname) ( Addr a, const HCh -+ match anywhere in function, and show offset if nonzero. -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership -+ in pub_tool_debuginfo.h */ -+-Bool VG_(get_fnname_w_offset) ( Addr a, const HChar** buf ) -++Bool VG_(get_fnname_w_offset) ( DiEpoch ep, Addr a, const HChar** buf ) -+ { -+ return get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True, -+ /*below-main-renaming*/True, -+- a, buf, -++ ep, a, buf, -+ /*match_anywhere_in_fun*/True, -+ /*show offset?*/True, -+ /*text sym*/True, -+@@ -1898,14 +2095,14 @@ Bool VG_(get_fnname_w_offset) ( Addr a, -+ and don't show offsets. -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership -+ in pub_tool_debuginfo.h */ -+-Bool VG_(get_fnname_if_entry) ( Addr a, const HChar** buf ) -++Bool VG_(get_fnname_if_entry) ( DiEpoch ep, Addr a, const HChar** buf ) -+ { -+ const HChar *tmp; -+ Bool res; -+ -+ res = get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True, -+ /*below-main-renaming*/True, -+- a, &tmp, -++ ep, a, &tmp, -+ /*match_anywhere_in_fun*/False, -+ /*show offset?*/False, -+ /*text sym*/True, -+@@ -1920,11 +2117,11 @@ Bool VG_(get_fnname_if_entry) ( Addr a, -+ offsets. -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership -+ in pub_tool_debuginfo.h */ -+-Bool VG_(get_fnname_raw) ( Addr a, const HChar** buf ) -++Bool VG_(get_fnname_raw) ( DiEpoch ep, Addr a, const HChar** buf ) -+ { -+ return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False, -+ /*below-main-renaming*/False, -+- a, buf, -++ ep, a, buf, -+ /*match_anywhere_in_fun*/True, -+ /*show offset?*/False, -+ /*text sym*/True, -+@@ -1936,14 +2133,22 @@ Bool VG_(get_fnname_raw) ( Addr a, const -+ don't show offsets. -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership -+ in pub_tool_debuginfo.h */ -+-Bool VG_(get_fnname_no_cxx_demangle) ( Addr a, const HChar** buf, -++Bool VG_(get_fnname_no_cxx_demangle) ( DiEpoch ep, Addr a, const HChar** buf, -+ const InlIPCursor* iipc ) -+ { -++ // FIXME JRS 28 June 2017: should we use 'iipc->di->first_epoch' -++ // instead of 'ep' in the call to get_sym_name? At least let's -++ // assert that the DebugInfo that 'iipc' mentions is valid for the -++ // specified epoch. -++ if (iipc) { -++ vg_assert(is_DI_valid_for_epoch(iipc->di, ep)); -++ } -++ -+ if (is_bottom(iipc)) { -+ // At the bottom (towards main), we describe the fn at eip. -+ return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/True, -+ /*below-main-renaming*/True, -+- a, buf, -++ ep, a, buf, -+ /*match_anywhere_in_fun*/True, -+ /*show offset?*/False, -+ /*text sym*/True, -+@@ -1962,13 +2167,13 @@ Bool VG_(get_fnname_no_cxx_demangle) ( A -+ /* mips-linux only: find the offset of current address. This is needed for -+ stack unwinding for MIPS. -+ */ -+-Bool VG_(get_inst_offset_in_function)( Addr a, -++Bool VG_(get_inst_offset_in_function)( DiEpoch ep, Addr a, -+ /*OUT*/PtrdiffT* offset ) -+ { -+ const HChar *fnname; -+ return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False, -+ /*below-main-renaming*/False, -+- a, &fnname, -++ ep, a, &fnname, -+ /*match_anywhere_in_sym*/True, -+ /*show offset?*/False, -+ /*text sym*/True, -+@@ -2000,13 +2205,13 @@ Vg_FnNameKind VG_(get_fnname_kind) ( con -+ } -+ } -+ -+-Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( Addr ip ) -++Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( DiEpoch ep, Addr ip ) -+ { -+ const HChar *buf; -+ -+ // We don't demangle, because it's faster not to, and the special names -+ // we're looking for won't be mangled. -+- if (VG_(get_fnname_raw) ( ip, &buf )) { -++ if (VG_(get_fnname_raw) ( ep, ip, &buf )) { -+ -+ return VG_(get_fnname_kind)(buf); -+ } else { -+@@ -2019,13 +2224,13 @@ Vg_FnNameKind VG_(get_fnname_kind_from_I -+ Also data_addr's offset from the symbol start is put into *offset. -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership -+ in pub_tool_debuginfo.h */ -+-Bool VG_(get_datasym_and_offset)( Addr data_addr, -++Bool VG_(get_datasym_and_offset)( DiEpoch ep, Addr data_addr, -+ /*OUT*/const HChar** dname, -+ /*OUT*/PtrdiffT* offset ) -+ { -+ return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False, -+ /*below-main-renaming*/False, -+- data_addr, dname, -++ ep, data_addr, dname, -+ /*match_anywhere_in_sym*/True, -+ /*show offset?*/False, -+ /*text sym*/False, -+@@ -2038,7 +2243,7 @@ Bool VG_(get_datasym_and_offset)( Addr d -+ (1) the DebugInfo it belongs to is not discarded -+ (2) the segment containing the address is not merged with another segment -+ */ -+-Bool VG_(get_objname) ( Addr a, const HChar** objname ) -++Bool VG_(get_objname) ( DiEpoch ep, Addr a, const HChar** objname ) -+ { -+ DebugInfo* di; -+ const NSegment *seg; -+@@ -2047,6 +2252,8 @@ Bool VG_(get_objname) ( Addr a, const HC -+ /* Look in the debugInfo_list to find the name. In most cases we -+ expect this to produce a result. */ -+ for (di = debugInfo_list; di != NULL; di = di->next) { -++ if (!is_DI_valid_for_epoch(di, ep)) -++ continue; -+ if (di->text_present -+ && di->text_size > 0 -+ && di->text_avma <= a -+@@ -2059,8 +2266,13 @@ Bool VG_(get_objname) ( Addr a, const HC -+ the debugInfo_list, ask the address space manager whether it -+ knows the name of the file associated with this mapping. This -+ allows us to print the names of exe/dll files in the stack trace -+- when running programs under wine. */ -+- if ( (seg = VG_(am_find_nsegment)(a)) != NULL -++ when running programs under wine. -++ -++ Restrict this to the case where 'ep' is the current epoch, though, so -++ that we don't return information about this epoch when the caller was -++ enquiring about a different one. */ -++ if ( eq_DiEpoch(ep, VG_(current_DiEpoch)()) -++ && (seg = VG_(am_find_nsegment)(a)) != NULL -+ && (filename = VG_(am_get_filename)(seg)) != NULL ) { -+ *objname = filename; -+ return True; -+@@ -2070,12 +2282,14 @@ Bool VG_(get_objname) ( Addr a, const HC -+ -+ /* Map a code address to its DebugInfo. Returns NULL if not found. Doesn't -+ require debug info. */ -+-DebugInfo* VG_(find_DebugInfo) ( Addr a ) -++DebugInfo* VG_(find_DebugInfo) ( DiEpoch ep, Addr a ) -+ { -+ static UWord n_search = 0; -+ DebugInfo* di; -+ n_search++; -+ for (di = debugInfo_list; di != NULL; di = di->next) { -++ if (!is_DI_valid_for_epoch(di, ep)) -++ continue; -+ if (di->text_present -+ && di->text_size > 0 -+ && di->text_avma <= a -+@@ -2091,13 +2305,13 @@ DebugInfo* VG_(find_DebugInfo) ( Addr a -+ /* Map a code address to a filename. Returns True if successful. The -+ returned string is persistent as long as the DebugInfo to which it -+ belongs is not discarded. */ -+-Bool VG_(get_filename)( Addr a, const HChar** filename ) -++Bool VG_(get_filename)( DiEpoch ep, Addr a, const HChar** filename ) -+ { -+ DebugInfo* si; -+ Word locno; -+ UInt fndn_ix; -+ -+- search_all_loctabs ( a, &si, &locno ); -++ search_all_loctabs ( ep, a, &si, &locno ); -+ if (si == NULL) -+ return False; -+ fndn_ix = ML_(fndn_ix) (si, locno); -+@@ -2106,11 +2320,11 @@ Bool VG_(get_filename)( Addr a, const HC -+ } -+ -+ /* Map a code address to a line number. Returns True if successful. */ -+-Bool VG_(get_linenum)( Addr a, UInt* lineno ) -++Bool VG_(get_linenum)( DiEpoch ep, Addr a, UInt* lineno ) -+ { -+ DebugInfo* si; -+ Word locno; -+- search_all_loctabs ( a, &si, &locno ); -++ search_all_loctabs ( ep, a, &si, &locno ); -+ if (si == NULL) -+ return False; -+ *lineno = si->loctab[locno].lineno; -+@@ -2121,7 +2335,7 @@ Bool VG_(get_linenum)( Addr a, UInt* lin -+ /* Map a code address to a filename/line number/dir name info. -+ See prototype for detailed description of behaviour. -+ */ -+-Bool VG_(get_filename_linenum) ( Addr a, -++Bool VG_(get_filename_linenum) ( DiEpoch ep, Addr a, -+ /*OUT*/const HChar** filename, -+ /*OUT*/const HChar** dirname, -+ /*OUT*/UInt* lineno ) -+@@ -2130,7 +2344,7 @@ Bool VG_(get_filename_linenum) ( Addr a, -+ Word locno; -+ UInt fndn_ix; -+ -+- search_all_loctabs ( a, &si, &locno ); -++ search_all_loctabs ( ep, a, &si, &locno ); -+ if (si == NULL) { -+ if (dirname) { -+ *dirname = ""; -+@@ -2159,7 +2373,8 @@ Bool VG_(get_filename_linenum) ( Addr a, -+ Therefore specify "*" to search all the objects. On TOC-afflicted -+ platforms, a symbol is deemed to be found only if it has a nonzero -+ TOC pointer. */ -+-Bool VG_(lookup_symbol_SLOW)(const HChar* sopatt, const HChar* name, -++Bool VG_(lookup_symbol_SLOW)(DiEpoch ep, -++ const HChar* sopatt, const HChar* name, -+ SymAVMAs* avmas) -+ { -+ Bool require_pToc = False; -+@@ -2172,6 +2387,8 @@ Bool VG_(lookup_symbol_SLOW)(const HChar -+ for (si = debugInfo_list; si; si = si->next) { -+ if (debug) -+ VG_(printf)("lookup_symbol_SLOW: considering %s\n", si->soname); -++ if (!is_DI_valid_for_epoch(si, ep)) -++ continue; -+ if (!VG_(string_match)(sopatt, si->soname)) { -+ if (debug) -+ VG_(printf)(" ... skip\n"); -+@@ -2254,7 +2471,7 @@ putStrEsc( SizeT n, HChar** buf, SizeT * -+ return n; -+ } -+ -+-const HChar* VG_(describe_IP)(Addr eip, const InlIPCursor *iipc) -++const HChar* VG_(describe_IP)(DiEpoch ep, Addr eip, const InlIPCursor *iipc) -+ { -+ static HChar *buf = NULL; -+ static SizeT bufsiz = 0; -+@@ -2267,7 +2484,10 @@ const HChar* VG_(describe_IP)(Addr eip, -+ HChar ibuf[50]; // large enough -+ SizeT n = 0; -+ -+- vg_assert (!iipc || iipc->eip == eip); -++ // An InlIPCursor is associated with one specific DebugInfo. So if -++ // it exists, make sure that it is valid for the specified DiEpoch. -++ vg_assert (!iipc -++ || (is_DI_valid_for_epoch(iipc->di, ep) && iipc->eip == eip)); -+ -+ const HChar *buf_fn; -+ const HChar *buf_obj; -+@@ -2282,8 +2502,8 @@ const HChar* VG_(describe_IP)(Addr eip, -+ if (is_bottom(iipc)) { -+ // At the bottom (towards main), we describe the fn at eip. -+ know_fnname = VG_(clo_sym_offsets) -+- ? VG_(get_fnname_w_offset) (eip, &buf_fn) -+- : VG_(get_fnname) (eip, &buf_fn); -++ ? VG_(get_fnname_w_offset) (ep, eip, &buf_fn) -++ : VG_(get_fnname) (ep, eip, &buf_fn); -+ } else { -+ const DiInlLoc *next_inl = iipc && iipc->next_inltab >= 0 -+ ? & iipc->di->inltab[iipc->next_inltab] -+@@ -2301,12 +2521,12 @@ const HChar* VG_(describe_IP)(Addr eip, -+ // ??? Currently never showing an offset. -+ } -+ -+- know_objname = VG_(get_objname)(eip, &buf_obj); -++ know_objname = VG_(get_objname)(ep, eip, &buf_obj); -+ -+ if (is_top(iipc)) { -+ // The source for the highest level is in the loctab entry. -+ know_srcloc = VG_(get_filename_linenum)( -+- eip, -++ ep, eip, -+ &buf_srcloc, -+ &buf_dirname, -+ &lineno -+@@ -2459,6 +2679,20 @@ const HChar* VG_(describe_IP)(Addr eip, -+ /*--- ---*/ -+ /*--------------------------------------------------------------*/ -+ -++/* Note that the CFI machinery pertains to unwinding the stack "right now". -++ There is no support for unwinding stack images obtained from some time in -++ the past. That means that: -++ -++ (1) We only deal with CFI from DebugInfos that are valid for the current -++ debuginfo epoch. Unlike in the rest of the file, there is no -++ epoch-awareness. -++ -++ (2) We assume that the CFI cache will be invalidated every time the the -++ epoch changes. This is done by ensuring (in the file above) that -++ every call to advance_current_DiEpoch has a call to -++ caches__invalidate alongside it. -++*/ -++ -+ /* Gather up all the constant pieces of info needed to evaluate -+ a CfiExpr into one convenient struct. */ -+ typedef -+@@ -2579,6 +2813,9 @@ UWord evalCfiExpr ( const XArray* exprs, -+ *cfsi_mP to the cfsi_m pointer in that DebugInfo's cfsi_m_pool. -+ -+ If not found, set *diP to (DebugInfo*)1 and *cfsi_mP to zero. -++ -++ Per comments at the top of this section, we only look for CFI in -++ DebugInfos that are valid for the current epoch. -+ */ -+ __attribute__((noinline)) -+ static void find_DiCfSI ( /*OUT*/DebugInfo** diP, -+@@ -2594,10 +2831,15 @@ static void find_DiCfSI ( /*OUT*/DebugIn -+ -+ if (0) VG_(printf)("search for %#lx\n", ip); -+ -++ DiEpoch curr_epoch = VG_(current_DiEpoch)(); -++ -+ for (di = debugInfo_list; di != NULL; di = di->next) { -+ Word j; -+ n_steps++; -+ -++ if (!is_DI_valid_for_epoch(di, curr_epoch)) -++ continue; -++ -+ /* Use the per-DebugInfo summary address ranges to skip -+ inapplicable DebugInfos quickly. */ -+ if (di->cfsi_used == 0) -+@@ -2605,6 +2847,11 @@ static void find_DiCfSI ( /*OUT*/DebugIn -+ if (ip < di->cfsi_minavma || ip > di->cfsi_maxavma) -+ continue; -+ -++ // This di must be active (because we have explicitly chosen not to -++ // allow unwinding stacks that pertain to some past epoch). It can't -++ // be archived or not-yet-active. -++ vg_assert(is_DebugInfo_active(di)); -++ -+ /* It might be in this DebugInfo. Search it. */ -+ j = ML_(search_one_cfitab)( di, ip ); -+ vg_assert(j >= -1 && j < (Word)di->cfsi_used); -+@@ -3032,6 +3279,7 @@ Bool VG_(use_CF_info) ( /*MOD*/D3UnwindR -+ Bool VG_(use_FPO_info) ( /*MOD*/Addr* ipP, -+ /*MOD*/Addr* spP, -+ /*MOD*/Addr* fpP, -++ DiEpoch ep, -+ Addr min_accessible, -+ Addr max_accessible ) -+ { -+@@ -3049,6 +3297,9 @@ Bool VG_(use_FPO_info) ( /*MOD*/Addr* ip -+ for (di = debugInfo_list; di != NULL; di = di->next) { -+ n_steps++; -+ -++ if (!is_DI_valid_for_epoch(di, ep)) -++ continue; -++ -+ /* Use the per-DebugInfo summary address ranges to skip -+ inapplicable DebugInfos quickly. */ -+ if (di->fpo == NULL) -+@@ -3552,6 +3803,7 @@ static void format_message ( /*MOD*/XArr -+ static -+ Bool consider_vars_in_frame ( /*MOD*/XArray* /* of HChar */ dname1, -+ /*MOD*/XArray* /* of HChar */ dname2, -++ DiEpoch ep, -+ Addr data_addr, -+ Addr ip, Addr sp, Addr fp, -+ /* shown to user: */ -+@@ -3570,6 +3822,8 @@ Bool consider_vars_in_frame ( /*MOD*/XAr -+ /* first, find the DebugInfo that pertains to 'ip'. */ -+ for (di = debugInfo_list; di; di = di->next) { -+ n_steps++; -++ if (!is_DI_valid_for_epoch(di, ep)) -++ continue; -+ /* text segment missing? unlikely, but handle it .. */ -+ if (!di->text_present || di->text_size == 0) -+ continue; -+@@ -3687,7 +3941,7 @@ Bool consider_vars_in_frame ( /*MOD*/XAr -+ Bool VG_(get_data_description)( -+ /*MOD*/ XArray* /* of HChar */ dname1, -+ /*MOD*/ XArray* /* of HChar */ dname2, -+- Addr data_addr -++ DiEpoch ep, Addr data_addr -+ ) -+ { -+ # define N_FRAMES 8 -+@@ -3807,7 +4061,7 @@ Bool VG_(get_data_description)( -+ vg_assert(n_frames >= 0 && n_frames <= N_FRAMES); -+ for (j = 0; j < n_frames; j++) { -+ if (consider_vars_in_frame( dname1, dname2, -+- data_addr, -++ ep, data_addr, -+ ips[j], -+ sps[j], fps[j], tid, j )) { -+ zterm_XA( dname1 ); -+@@ -3834,7 +4088,7 @@ Bool VG_(get_data_description)( -+ equivalent kludge. */ -+ if (j > 0 /* this is a non-innermost frame */ -+ && consider_vars_in_frame( dname1, dname2, -+- data_addr, -++ ep, data_addr, -+ ips[j] + 1, -+ sps[j], fps[j], tid, j )) { -+ zterm_XA( dname1 ); -+Index: valgrind-3.13.0/coregrind/m_debuginfo/priv_storage.h -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_debuginfo/priv_storage.h -++++ valgrind-3.13.0/coregrind/m_debuginfo/priv_storage.h -+@@ -588,6 +588,36 @@ struct _DebugInfo { -+ structure is allocated. */ -+ ULong handle; -+ -++ /* The range of epochs for which this DebugInfo is valid. These also -++ divide the DebugInfo's lifetime into three parts: -++ -++ (1) Allocated: but with only .fsm holding useful info -- in -++ particular, not yet holding any debug info. -++ .first_epoch == DebugInfoEpoch_INVALID -++ .last_epoch == DebugInfoEpoch_INVALID -++ -++ (2) Active: containing debug info, and current. -++ .first_epoch != DebugInfoEpoch_INVALID -++ .last_epoch == DebugInfoEpoch_INVALID -++ -++ (3) Archived: containing debug info, but no longer current. -++ .first_epoch != DebugInfoEpoch_INVALID -++ .last_epoch != DebugInfoEpoch_INVALID -++ -++ State (2) corresponds to an object which is currently mapped. When -++ the object is unmapped, what happens depends on the setting of -++ --keep-debuginfo: -++ -++ * when =no, the DebugInfo is removed from debugInfo_list and -++ deleted. -++ -++ * when =yes, the DebugInfo is retained in debugInfo_list, but its -++ .last_epoch field is filled in, and current_epoch is advanced. This -++ effectively moves the DebugInfo into state (3). -++ */ -++ DiEpoch first_epoch; -++ DiEpoch last_epoch; -++ -+ /* Used for debugging only - indicate what stuff to dump whilst -+ reading stuff into the seginfo. Are computed as early in the -+ lifetime of the DebugInfo as possible -- at the point when it is -+Index: valgrind-3.13.0/coregrind/m_errormgr.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_errormgr.c -++++ valgrind-3.13.0/coregrind/m_errormgr.c -+@@ -136,16 +136,16 @@ struct _Error { -+ Int count; -+ -+ // The tool-specific part -+- ThreadId tid; // Initialised by core -+- ExeContext* where; // Initialised by core -+- ErrorKind ekind; // Used by ALL. Must be in the range (0..) -+- Addr addr; // Used frequently -+- const HChar* string; // Used frequently -+- void* extra; // For any tool-specific extras -++ ThreadId tid; // Initialised by core -++ ExeContextAndEpoch where; // Initialised by core -++ ErrorKind ekind; // Used by ALL. Must be in the range (0..) -++ Addr addr; // Used frequently -++ const HChar* string; // Used frequently -++ void* extra; // For any tool-specific extras -+ }; -+ -+ -+-ExeContext* VG_(get_error_where) ( const Error* err ) -++ExeContextAndEpoch VG_(get_error_where) ( const Error* err ) -+ { -+ return err->where; -+ } -+@@ -293,7 +293,10 @@ static Bool eq_Error ( VgRes res, const -+ { -+ if (e1->ekind != e2->ekind) -+ return False; -+- if (!VG_(eq_ExeContext)(res, e1->where, e2->where)) -++ // This comparison ignores the debuginfo epoch. Result is that we -++ // could conclude this error is the same as one from some other epoch. -++ // I don't think that's a big deal in practice. -++ if (!VG_(eq_ExeContext)(res, e1->where.ec, e2->where.ec)) -+ return False; -+ -+ switch (e1->ekind) { -+@@ -321,15 +324,15 @@ static Bool eq_Error ( VgRes res, const -+ */ -+ #define ERRTXT_LEN 4096 -+ -+-static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque) -++static void printSuppForIp_XML(UInt n, DiEpoch ep, Addr ip, void* uu_opaque) -+ { -+ const HChar *buf; -+- InlIPCursor* iipc = VG_(new_IIPC)(ip); -++ InlIPCursor* iipc = VG_(new_IIPC)(ep, ip); -+ do { -+- if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) { -++ if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) { -+ VG_(printf_xml)(" <sframe> <fun>%pS</fun> </sframe>\n", buf); -+ } else -+- if ( VG_(get_objname)(ip, &buf) ) { -++ if ( VG_(get_objname)(ep, ip, &buf) ) { -+ VG_(printf_xml)(" <sframe> <obj>%pS</obj> </sframe>\n", buf); -+ } else { -+ VG_(printf_xml)(" <sframe> <obj>*</obj> </sframe>\n"); -+@@ -338,16 +341,16 @@ static void printSuppForIp_XML(UInt n, A -+ VG_(delete_IIPC)(iipc); -+ } -+ -+-static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV) -++static void printSuppForIp_nonXML(UInt n, DiEpoch ep, Addr ip, void* textV) -+ { -+ const HChar *buf; -+ XArray* /* of HChar */ text = (XArray*)textV; -+- InlIPCursor* iipc = VG_(new_IIPC)(ip); -++ InlIPCursor* iipc = VG_(new_IIPC)(ep, ip); -+ do { -+- if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) { -++ if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) { -+ VG_(xaprintf)(text, " fun:%s\n", buf); -+ } else -+- if ( VG_(get_objname)(ip, &buf) ) { -++ if ( VG_(get_objname)(ep, ip, &buf) ) { -+ VG_(xaprintf)(text, " obj:%s\n", buf); -+ } else { -+ VG_(xaprintf)(text, " obj:*\n"); -+@@ -361,15 +364,15 @@ static void printSuppForIp_nonXML(UInt n -+ static void gen_suppression(const Error* err) -+ { -+ const HChar* name; -+- ExeContext* ec; -++ ExeContextAndEpoch ece; -+ XArray* /* HChar */ text; -+ -+ const HChar* dummy_name = "insert_a_suppression_name_here"; -+ -+ vg_assert(err); -+ -+- ec = VG_(get_error_where)(err); -+- vg_assert(ec); -++ ece = VG_(get_error_where)(err); -++ vg_assert(ece.ec); -+ -+ name = VG_TDICT_CALL(tool_get_error_name, err); -+ if (NULL == name) { -+@@ -408,12 +411,12 @@ static void gen_suppression(const Error* -+ VG_(xaprintf)(text, " %s\n", xtra); -+ -+ // Print stack trace elements -+- UInt n_ips = VG_(get_ExeContext_n_ips)(ec); -++ UInt n_ips = VG_(get_ExeContext_n_ips)(ece.ec); -+ vg_assert(n_ips > 0); -+ vg_assert(n_ips <= VG_DEEPEST_BACKTRACE); -+ VG_(apply_StackTrace)(printSuppForIp_nonXML, -+- text, -+- VG_(get_ExeContext_StackTrace)(ec), -++ text, ece.epoch, -++ VG_(get_ExeContext_StackTrace)(ece.ec), -+ n_ips); -+ -+ VG_(xaprintf)(text, "}\n"); -+@@ -441,9 +444,9 @@ static void gen_suppression(const Error* -+ -+ // Print stack trace elements -+ VG_(apply_StackTrace)(printSuppForIp_XML, -+- NULL, -+- VG_(get_ExeContext_StackTrace)(ec), -+- VG_(get_ExeContext_n_ips)(ec)); -++ NULL, ece.epoch, -++ VG_(get_ExeContext_StackTrace)(ece.ec), -++ VG_(get_ExeContext_n_ips)(ece.ec)); -+ -+ // And now the cdata bit -+ // XXX FIXME! properly handle the case where the raw text -+@@ -637,7 +640,7 @@ static void pp_Error ( const Error* err, -+ /* Construct an error */ -+ static -+ void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a, -+- const HChar* s, void* extra, ExeContext* where ) -++ const HChar* s, void* extra, ExeContextAndEpoch where ) -+ { -+ /* DO NOT MAKE unique_counter NON-STATIC */ -+ static UInt unique_counter = 0; -+@@ -650,10 +653,7 @@ void construct_error ( Error* err, Threa -+ err->supp = NULL; -+ err->count = 1; -+ err->tid = tid; -+- if (NULL == where) -+- err->where = VG_(record_ExeContext)( tid, 0 ); -+- else -+- err->where = where; -++ err->where = where; -+ -+ /* Tool-relevant parts */ -+ err->ekind = ekind; -+@@ -744,7 +744,10 @@ void VG_(maybe_record_error) ( ThreadId -+ } -+ -+ /* Build ourselves the error */ -+- construct_error ( &err, tid, ekind, a, s, extra, NULL ); -++ { ExeContextAndEpoch ece -++ = VG_(tag_EC_with_current_epoch)( VG_(record_ExeContext)( tid, 0 ) ); -++ construct_error ( &err, tid, ekind, a, s, extra, ece ); -++ } -+ -+ /* First, see if we've got an error record matching this one. */ -+ em_errlist_searches++; -+@@ -853,7 +856,8 @@ void VG_(maybe_record_error) ( ThreadId -+ Bool 'count_error' dictates whether to count the error in n_errs_found. -+ */ -+ Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s, -+- void* extra, ExeContext* where, Bool print_error, -++ void* extra, ExeContextAndEpoch where, -++ Bool print_error, -+ Bool allow_db_attach, Bool count_error ) -+ { -+ Error err; -+@@ -1016,7 +1020,7 @@ void VG_(show_all_errors) ( Int verbosi -+ vg_assert(! xml); -+ -+ if ((i+1 == VG_(clo_dump_error))) { -+- StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where); -++ StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where.ec); -+ VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/, -+ ips[0], /*debugging*/True, 0xFE/*verbosity*/, -+ /*bbs_done*/0, -+@@ -1500,6 +1504,7 @@ static Bool supploc_IsQuery ( const void -+ allocations and the nr of debuginfo search. */ -+ typedef -+ struct { -++ DiEpoch epoch; // used to interpret .ips -+ StackTrace ips; // stack trace we are lazily completing. -+ UWord n_ips; // nr of elements in ips. -+ -+@@ -1595,9 +1600,11 @@ static void clearIPtoFunOrObjCompleter ( -+ su->sname, -+ filename, -+ su->sname_lineno); -+- } else -++ } else { -+ VG_(dmsg)("errormgr matching end no suppression matched:\n"); -+- VG_(pp_StackTrace) (ip2fo->ips, ip2fo->n_ips); -++ } -++ // JRS 27 July 2017: is it OK to use the current epoch here? -++ VG_(pp_StackTrace) (ip2fo->epoch, ip2fo->ips, ip2fo->n_ips); -+ pp_ip2fo(ip2fo); -+ } -+ if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip); -+@@ -1660,7 +1667,8 @@ static HChar* foComplete(IPtoFunOrObjCom -+ // up comparing "malloc" in the suppression against -+ // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the -+ // two of them need to be made to match. -+- if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->ips[ixInput], -++ if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch, -++ ip2fo->ips[ixInput], -+ &caller, -+ NULL)) -+ caller = "???"; -+@@ -1681,7 +1689,7 @@ static HChar* foComplete(IPtoFunOrObjCom -+ last_expand_pos_ips is the last offset in fun/obj where -+ ips[pos_ips] has been expanded. */ -+ -+- if (!VG_(get_objname)(ip2fo->ips[pos_ips], &caller)) -++ if (!VG_(get_objname)(ip2fo->epoch, ip2fo->ips[pos_ips], &caller)) -+ caller = "???"; -+ -+ // Have all inlined calls pointing at this object name -+@@ -1751,7 +1759,7 @@ static void expandInput (IPtoFunOrObjCom -+ const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded]; -+ InlIPCursor *iipc; -+ -+- iipc = VG_(new_IIPC)(IP); -++ iipc = VG_(new_IIPC)(ip2fo->epoch, IP); -+ // The only thing we really need is the nr of inlined fn calls -+ // corresponding to the IP we will expand. -+ // However, computing this is mostly the same as finding -+@@ -1760,7 +1768,7 @@ static void expandInput (IPtoFunOrObjCom -+ const HChar *caller; -+ grow_offsets(ip2fo, ip2fo->n_expanded+1); -+ ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free; -+- if (!VG_(get_fnname_no_cxx_demangle)(IP, -++ if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch, IP, -+ &caller, -+ iipc)) -+ caller = "???"; -+@@ -1788,18 +1796,18 @@ static void expandInput (IPtoFunOrObjCom -+ } -+ } -+ -+-static Bool haveInputInpC (void* inputCompleter, UWord ixInput ) -++static Bool haveInputInpC (void* inputCompleterV, UWord ixInput ) -+ { -+- IPtoFunOrObjCompleter* ip2fo = inputCompleter; -++ IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV; -+ expandInput(ip2fo, ixInput); -+ return ixInput < ip2fo->n_expanded; -+ } -+ -+ static Bool supp_pattEQinp ( const void* supplocV, const void* addrV, -+- void* inputCompleter, UWord ixInput ) -++ void* inputCompleterV, UWord ixInput ) -+ { -+- const SuppLoc* supploc = supplocV; /* PATTERN */ -+- IPtoFunOrObjCompleter* ip2fo = inputCompleter; -++ const SuppLoc* supploc = (const SuppLoc*)supplocV; /* PATTERN */ -++ IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV; -+ HChar* funobj_name; // Fun or Obj name. -+ Bool ret; -+ -+@@ -1926,8 +1934,9 @@ static Supp* is_suppressible_error ( con -+ em_supplist_searches++; -+ -+ /* Prepare the lazy input completer. */ -+- ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where); -+- ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where); -++ ip2fo.epoch = err->where.epoch; -++ ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where.ec); -++ ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where.ec); -+ ip2fo.n_ips_expanded = 0; -+ ip2fo.n_expanded = 0; -+ ip2fo.sz_offsets = 0; -+Index: valgrind-3.13.0/coregrind/m_execontext.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_execontext.c -++++ valgrind-3.13.0/coregrind/m_execontext.c -+@@ -116,7 +116,7 @@ static ULong ec_cmpAlls; -+ -+ -+ /*------------------------------------------------------------*/ -+-/*--- Exported functions. ---*/ -++/*--- ExeContext functions. ---*/ -+ /*------------------------------------------------------------*/ -+ -+ static ExeContext* record_ExeContext_wrk2 ( const Addr* ips, UInt n_ips ); -+@@ -169,7 +169,9 @@ void VG_(print_ExeContext_stats) ( Bool -+ for (ec = ec_htab[i]; ec; ec = ec->chain) { -+ VG_(message)(Vg_DebugMsg, " exectx: stacktrace ecu %u n_ips %u\n", -+ ec->ecu, ec->n_ips); -+- VG_(pp_StackTrace)( ec->ips, ec->n_ips ); -++ // FIXME JRS 27 July 2017: is a fake epoch here OK? -++ DiEpoch ep = VG_(current_DiEpoch)(); -++ VG_(pp_StackTrace)( ep, ec->ips, ec->n_ips ); -+ } -+ } -+ VG_(message)(Vg_DebugMsg, -+@@ -202,13 +204,6 @@ void VG_(print_ExeContext_stats) ( Bool -+ } -+ -+ -+-/* Print an ExeContext. */ -+-void VG_(pp_ExeContext) ( ExeContext* ec ) -+-{ -+- VG_(pp_StackTrace)( ec->ips, ec->n_ips ); -+-} -+- -+- -+ /* Compare two ExeContexts. Number of callers considered depends on res. */ -+ Bool VG_(eq_ExeContext) ( VgRes res, const ExeContext* e1, -+ const ExeContext* e2 ) -+@@ -544,12 +539,48 @@ ExeContext* VG_(make_ExeContext_from_Sta -+ return record_ExeContext_wrk2(ips, n_ips); -+ } -+ -+-ExeContext* VG_(null_ExeContext) (void) -++ -++/*------------------------------------------------------------*/ -++/*--- ExeContextAndEpoch functions. ---*/ -++/*------------------------------------------------------------*/ -++ -++ExeContextAndEpoch VG_(tag_EC_with_current_epoch)( ExeContext* ec ) -++{ -++ ExeContextAndEpoch ece; -++ ece.ec = ec; -++ ece.epoch = VG_(current_DiEpoch)(); -++ return ece; -++} -++ -++ExeContextAndEpoch VG_(invalid_ExeContextAndEpoch) ( void ) -++{ -++ ExeContextAndEpoch ece; -++ ece.ec = NULL/*invalid ExeContext*/; -++ ece.epoch.n = 0/*invalid epoch*/; -++ return ece; -++} -++ -++ -++void VG_(pp_ExeContextAndEpoch) ( ExeContextAndEpoch ece ) -++{ -++ VG_(pp_StackTrace)( ece.epoch, ece.ec->ips, ece.ec->n_ips ); -++} -++ -++ExeContextAndEpoch VG_(null_ExeContextAndEpoch) ( void ) -+ { -+ init_ExeContext_storage(); -+- return null_ExeContext; -++ ExeContextAndEpoch ece -++ = mk_ExeContextAndEpoch(null_ExeContext, VG_(current_DiEpoch)()); -++ return ece; -+ } -+ -++Bool VG_(is_null_ExeContextAndEpoch)( ExeContextAndEpoch ece ) -++{ -++ init_ExeContext_storage(); -++ return ece.ec == null_ExeContext; -++} -++ -++ -+ /*--------------------------------------------------------------------*/ -+ /*--- end m_execontext.c ---*/ -+ /*--------------------------------------------------------------------*/ -+Index: valgrind-3.13.0/coregrind/m_gdbserver/m_gdbserver.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/m_gdbserver.c -++++ valgrind-3.13.0/coregrind/m_gdbserver/m_gdbserver.c -+@@ -142,14 +142,17 @@ static HChar* sym (Addr addr, Bool is_co -+ PtrdiffT offset; -+ if (w == 2) w = 0; -+ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ if (is_code) { -+ const HChar *name; -+- name = VG_(describe_IP) (addr, NULL); -++ name = VG_(describe_IP) (ep, addr, NULL); -+ if (buf[w]) VG_(free)(buf[w]); -+ buf[w] = VG_(strdup)("gdbserver sym", name); -+ } else { -+ const HChar *name; -+- VG_(get_datasym_and_offset) (addr, &name, &offset); -++ VG_(get_datasym_and_offset) (ep, addr, &name, &offset); -+ if (buf[w]) VG_(free)(buf[w]); -+ buf[w] = VG_(strdup)("gdbserver sym", name); -+ } -+Index: valgrind-3.13.0/coregrind/m_gdbserver/server.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/server.c -++++ valgrind-3.13.0/coregrind/m_gdbserver/server.c -+@@ -195,6 +195,9 @@ int handle_gdb_valgrind_command (char *m -+ int kwdid; -+ int int_value; -+ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ vg_assert (initial_valgrind_sink_saved); -+ -+ strcpy (s, mon); -+@@ -334,7 +337,7 @@ int handle_gdb_valgrind_command (char *m -+ } -+ if (hostvisibility) { -+ const DebugInfo *tooldi -+- = VG_(find_DebugInfo) ((Addr)handle_gdb_valgrind_command); -++ = VG_(find_DebugInfo) (ep, (Addr)handle_gdb_valgrind_command); -+ /* Normally, we should always find the tooldi. In case we -+ do not, suggest a 'likely somewhat working' address: */ -+ const Addr tool_text_start -+@@ -442,14 +445,14 @@ int handle_gdb_valgrind_command (char *m -+ &dummy_sz, &ssaveptr)) { -+ // If tool provides location information, use that. -+ if (VG_(needs).info_location) { -+- VG_TDICT_CALL(tool_info_location, address); -++ VG_TDICT_CALL(tool_info_location, ep, address); -+ } -+ // If tool does not provide location info, use the common one. -+ // Also use the common to compare with tool when debug log is set. -+ if (!VG_(needs).info_location || VG_(debugLog_getLevel)() > 0 ) { -+ AddrInfo ai; -+ ai.tag = Addr_Undescribed; -+- VG_(describe_addr) (address, &ai); -++ VG_(describe_addr) (ep, address, &ai); -+ VG_(pp_addrinfo) (address, &ai); -+ VG_(clear_addrinfo) (&ai); -+ } -+Index: valgrind-3.13.0/coregrind/m_gdbserver/target.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/target.c -++++ valgrind-3.13.0/coregrind/m_gdbserver/target.c -+@@ -209,7 +209,10 @@ void gdbserver_process_exit_encountered -+ static -+ const HChar* sym (Addr addr) -+ { -+- return VG_(describe_IP) (addr, NULL); -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -++ return VG_(describe_IP) (ep, addr, NULL); -+ } -+ -+ ThreadId vgdb_interrupted_tid = 0; -+Index: valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-arm.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/valgrind-low-arm.c -++++ valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-arm.c -+@@ -149,8 +149,12 @@ Addr thumb_pc (Addr pc) -+ // the debug info with the bit0 set -+ // (why can't debug info do that for us ???) -+ // (why if this is a 4 bytes thumb instruction ???) -+- if (VG_(get_fnname_raw) (pc | 1, &fnname)) { -+- if (VG_(lookup_symbol_SLOW)( "*", fnname, &avmas )) { -++ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -++ if (VG_(get_fnname_raw) (ep, pc | 1, &fnname)) { -++ if (VG_(lookup_symbol_SLOW)( ep, "*", fnname, &avmas )) { -+ dlog (1, "fnname %s lookupsym %p => %p %s.\n", -+ fnname, C2v(avmas.main), C2v(pc), -+ (avmas.main & 1 ? "thumb" : "arm")); -+Index: valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-mips32.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/valgrind-low-mips32.c -++++ valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-mips32.c -+@@ -228,7 +228,11 @@ static Addr mips_adjust_breakpoint_addre -+ /* Make sure we don't scan back before the beginning of the current -+ function, since we may fetch constant data or insns that look like -+ a jump. */ -+- if (VG_(get_inst_offset_in_function) (bpaddr, &offset)) { -++ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -++ if (VG_(get_inst_offset_in_function) (ep, bpaddr, &offset)) { -+ func_addr = bpaddr - offset; -+ if (func_addr > boundary && func_addr <= bpaddr) -+ boundary = func_addr; -+Index: valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-mips64.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/valgrind-low-mips64.c -++++ valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-mips64.c -+@@ -229,7 +229,11 @@ static Addr mips_adjust_breakpoint_addre -+ /* Make sure we don't scan back before the beginning of the current -+ function, since we may fetch constant data or insns that look like -+ a jump. */ -+- if (VG_(get_inst_offset_in_function) (bpaddr, &offset)) { -++ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -++ if (VG_(get_inst_offset_in_function) (ep, bpaddr, &offset)) { -+ func_addr = bpaddr - offset; -+ if (func_addr > boundary && func_addr <= bpaddr) -+ boundary = func_addr; -+Index: valgrind-3.13.0/coregrind/m_libcassert.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_libcassert.c -++++ valgrind-3.13.0/coregrind/m_libcassert.c -+@@ -369,7 +369,7 @@ static void show_sched_status_wrk ( Bool -+ ); -+ VG_(printf)("\nhost stacktrace:\n"); -+ VG_(clo_xml) = False; -+- VG_(pp_StackTrace) (ips, n_ips); -++ VG_(pp_StackTrace) (VG_(current_DiEpoch)(), ips, n_ips); -+ VG_(clo_xml) = save_clo_xml; -+ } -+ -+Index: valgrind-3.13.0/coregrind/m_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_main.c -++++ valgrind-3.13.0/coregrind/m_main.c -+@@ -128,6 +128,10 @@ static void usage_NORETURN ( Bool debug_ -+ " --error-exitcode=<number> exit code to return if errors found [0=disable]\n" -+ " --error-markers=<begin>,<end> add lines with begin/end markers before/after\n" -+ " each error output in plain text mode [none]\n" -++" --keep-debuginfo=no|yes Keep symbols etc for unloaded code [no]\n" -++" This allows stack traces for memory leaks to\n" -++" include file/line info for code that has been\n" -++" dlclose'd (or similar)\n" -+ " --show-below-main=no|yes continue stack traces below main() [no]\n" -+ " --default-suppressions=yes|no\n" -+ " load default suppressions [yes]\n" -+@@ -626,6 +630,7 @@ void main_process_cmd_line_options( void -+ else if VG_BOOL_CLO(arg, "--run-libc-freeres", VG_(clo_run_libc_freeres)) {} -+ else if VG_BOOL_CLO(arg, "--run-cxx-freeres", VG_(clo_run_cxx_freeres)) {} -+ else if VG_BOOL_CLO(arg, "--show-below-main", VG_(clo_show_below_main)) {} -++ else if VG_BOOL_CLO(arg, "--keep-debuginfo", VG_(clo_keep_debuginfo)) {} -+ else if VG_BOOL_CLO(arg, "--time-stamp", VG_(clo_time_stamp)) {} -+ else if VG_BOOL_CLO(arg, "--track-fds", VG_(clo_track_fds)) {} -+ else if VG_BOOL_CLO(arg, "--trace-children", VG_(clo_trace_children)) {} -+Index: valgrind-3.13.0/coregrind/m_options.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_options.c -++++ valgrind-3.13.0/coregrind/m_options.c -+@@ -129,6 +129,7 @@ Bool VG_(clo_run_libc_freeres) = True; -+ Bool VG_(clo_run_cxx_freeres) = True; -+ Bool VG_(clo_track_fds) = False; -+ Bool VG_(clo_show_below_main)= False; -++Bool VG_(clo_keep_debuginfo) = False; -+ Bool VG_(clo_show_emwarns) = False; -+ Word VG_(clo_max_stackframe) = 2000000; -+ UInt VG_(clo_max_threads) = MAX_THREADS_DEFAULT; -+Index: valgrind-3.13.0/coregrind/m_redir.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_redir.c -++++ valgrind-3.13.0/coregrind/m_redir.c -+@@ -1859,15 +1859,16 @@ static void show_active ( const HChar* l -+ { -+ Bool ok; -+ const HChar *buf; -+- -+- ok = VG_(get_fnname_w_offset)(act->from_addr, &buf); -++ -++ DiEpoch ep = VG_(current_DiEpoch)(); -++ ok = VG_(get_fnname_w_offset)(ep, act->from_addr, &buf); -+ if (!ok) buf = "???"; -+ // Stash away name1 -+ HChar name1[VG_(strlen)(buf) + 1]; -+ VG_(strcpy)(name1, buf); -+ -+ const HChar *name2; -+- ok = VG_(get_fnname_w_offset)(act->to_addr, &name2); -++ ok = VG_(get_fnname_w_offset)(ep, act->to_addr, &name2); -+ if (!ok) name2 = "???"; -+ -+ VG_(message)(Vg_DebugMsg, "%s0x%08lx (%-20s) %s-> (%04d.%d) 0x%08lx %s\n", -+Index: valgrind-3.13.0/coregrind/m_sbprofile.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_sbprofile.c -++++ valgrind-3.13.0/coregrind/m_sbprofile.c -+@@ -74,6 +74,9 @@ void show_SB_profile ( const SBProfEntry -+ -+ VG_(printf)("Total score = %'llu\n\n", score_total); -+ -++ // FIXME JRS 28 July 2017: this is probably not right in general -++ DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ /* Print an initial per-block summary. */ -+ VG_(printf)("rank ---cumulative--- -----self-----\n"); -+ score_cumul = 0; -+@@ -84,7 +87,7 @@ void show_SB_profile ( const SBProfEntry -+ continue; -+ -+ const HChar *name; -+- VG_(get_fnname_w_offset)(tops[r].addr, &name); -++ VG_(get_fnname_w_offset)(ep, tops[r].addr, &name); -+ -+ score_here = tops[r].score; -+ score_cumul += score_here; -+@@ -123,7 +126,7 @@ void show_SB_profile ( const SBProfEntry -+ continue; -+ -+ const HChar *name; -+- VG_(get_fnname_w_offset)(tops[r].addr, &name); -++ VG_(get_fnname_w_offset)(ep, tops[r].addr, &name); -+ -+ score_here = tops[r].score; -+ score_cumul += score_here; -+@@ -159,7 +162,7 @@ void show_SB_profile ( const SBProfEntry -+ continue; -+ -+ const HChar *name; -+- VG_(get_fnname_w_offset)(tops[r].addr, &name); -++ VG_(get_fnname_w_offset)(ep, tops[r].addr, &name); -+ -+ score_here = tops[r].score; -+ -+Index: valgrind-3.13.0/coregrind/m_scheduler/scheduler.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_scheduler/scheduler.c -++++ valgrind-3.13.0/coregrind/m_scheduler/scheduler.c -+@@ -2037,8 +2037,12 @@ void do_client_request ( ThreadId tid ) -+ -+ VG_(memset)(buf64, 0, 64); -+ UInt linenum = 0; -++ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ Bool ok = VG_(get_filename_linenum)( -+- ip, &buf, NULL, &linenum -++ ep, ip, &buf, NULL, &linenum -+ ); -+ if (ok) { -+ /* For backward compatibility truncate the filename to -+Index: valgrind-3.13.0/coregrind/m_signals.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_signals.c -++++ valgrind-3.13.0/coregrind/m_signals.c -+@@ -1878,7 +1878,7 @@ static void default_action(const vki_sig -+ : VG_(record_depth_1_ExeContext)( tid, -+ first_ip_delta ); -+ vg_assert(ec); -+- VG_(pp_ExeContext)( ec ); -++ VG_(pp_ExeContextAndEpoch)( VG_(tag_EC_with_current_epoch)(ec) ); -+ } -+ if (sigNo == VKI_SIGSEGV -+ && is_signal_from_kernel(tid, sigNo, info->si_code) -+Index: valgrind-3.13.0/coregrind/m_stacktrace.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_stacktrace.c -++++ valgrind-3.13.0/coregrind/m_stacktrace.c -+@@ -446,6 +446,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId -+ /* And, similarly, try for MSVC FPO unwind info. */ -+ if (FPO_info_present -+ && VG_(use_FPO_info)( &uregs.xip, &uregs.xsp, &uregs.xbp, -++ VG_(current_DiEpoch)(), -+ fp_min, fp_max ) ) { -+ if (debug) unwind_case = "MS"; -+ if (do_stats) stats.MS++; -+@@ -1539,12 +1540,12 @@ UInt VG_(get_StackTrace) ( ThreadId tid, -+ stack_highest_byte); -+ } -+ -+-static void printIpDesc(UInt n, Addr ip, void* uu_opaque) -++static void printIpDesc(UInt n, DiEpoch ep, Addr ip, void* uu_opaque) -+ { -+- InlIPCursor *iipc = VG_(new_IIPC)(ip); -++ InlIPCursor *iipc = VG_(new_IIPC)(ep, ip); -+ -+ do { -+- const HChar *buf = VG_(describe_IP)(ip, iipc); -++ const HChar *buf = VG_(describe_IP)(ep, ip, iipc); -+ if (VG_(clo_xml)) { -+ VG_(printf_xml)(" %s\n", buf); -+ } else { -+@@ -1558,14 +1559,14 @@ static void printIpDesc(UInt n, Addr ip, -+ } -+ -+ /* Print a StackTrace. */ -+-void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips ) -++void VG_(pp_StackTrace) ( DiEpoch ep, StackTrace ips, UInt n_ips ) -+ { -+ vg_assert( n_ips > 0 ); -+ -+ if (VG_(clo_xml)) -+ VG_(printf_xml)(" <stack>\n"); -+ -+- VG_(apply_StackTrace)( printIpDesc, NULL, ips, n_ips ); -++ VG_(apply_StackTrace)( printIpDesc, NULL, ep, ips, n_ips ); -+ -+ if (VG_(clo_xml)) -+ VG_(printf_xml)(" </stack>\n"); -+@@ -1580,13 +1581,13 @@ void VG_(get_and_pp_StackTrace) ( Thread -+ NULL/*array to dump SP values in*/, -+ NULL/*array to dump FP values in*/, -+ 0/*first_ip_delta*/); -+- VG_(pp_StackTrace)(ips, n_ips); -++ VG_(pp_StackTrace)(VG_(current_DiEpoch)(), ips, n_ips); -+ } -+ -+ void VG_(apply_StackTrace)( -+- void(*action)(UInt n, Addr ip, void* opaque), -++ void(*action)(UInt n, DiEpoch ep, Addr ip, void* opaque), -+ void* opaque, -+- StackTrace ips, UInt n_ips -++ DiEpoch ep, StackTrace ips, UInt n_ips -+ ) -+ { -+ Int i; -+@@ -1597,7 +1598,7 @@ void VG_(apply_StackTrace)( -+ // or the last appearance of a below main function. -+ // Then decrease n_ips so as to not call action for the below main -+ for (i = n_ips - 1; i >= 0; i--) { -+- Vg_FnNameKind kind = VG_(get_fnname_kind_from_IP)(ips[i]); -++ Vg_FnNameKind kind = VG_(get_fnname_kind_from_IP)(ep, ips[i]); -+ if (Vg_FnNameMain == kind || Vg_FnNameBelowMain == kind) -+ n_ips = i + 1; -+ if (Vg_FnNameMain == kind) -+@@ -1607,7 +1608,7 @@ void VG_(apply_StackTrace)( -+ -+ for (i = 0; i < n_ips; i++) -+ // Act on the ip -+- action(i, ips[i], opaque); -++ action(i, ep, ips[i], opaque); -+ } -+ -+ -+Index: valgrind-3.13.0/coregrind/m_syswrap/syswrap-generic.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_syswrap/syswrap-generic.c -++++ valgrind-3.13.0/coregrind/m_syswrap/syswrap-generic.c -+@@ -540,7 +540,8 @@ typedef struct OpenFd -+ { -+ Int fd; /* The file descriptor */ -+ HChar *pathname; /* NULL if not a regular file or unknown */ -+- ExeContext *where; /* NULL if inherited from parent */ -++ ExeContextAndEpoch where; /* VG_(null_ExeContextAndEpoch) -++ if inherited from parent */ -+ struct OpenFd *next, *prev; -+ } OpenFd; -+ -+@@ -614,7 +615,10 @@ void ML_(record_fd_open_with_given_name) -+ -+ i->fd = fd; -+ i->pathname = VG_(strdup)("syswrap.rfdowgn.2", pathname); -+- i->where = (tid == -1) ? NULL : VG_(record_ExeContext)(tid, 0/*first_ip_delta*/); -++ i->where = (tid == -1) -++ ? VG_(null_ExeContextAndEpoch)() -++ : VG_(tag_EC_with_current_epoch)( -++ VG_(record_ExeContext)(tid, 0/*first_ip_delta*/)); -+ } -+ -+ // Record opening of an fd, and find its name. -+@@ -846,8 +850,8 @@ void VG_(show_open_fds) (const HChar* wh -+ } -+ } -+ -+- if(i->where) { -+- VG_(pp_ExeContext)(i->where); -++ if (!VG_(is_null_ExeContextAndEpoch)(i->where)) { -++ VG_(pp_ExeContextAndEpoch)(i->where); -+ VG_(message)(Vg_UserMsg, "\n"); -+ } else { -+ VG_(message)(Vg_UserMsg, " <inherited from parent>\n"); -+Index: valgrind-3.13.0/coregrind/m_tooliface.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_tooliface.c -++++ valgrind-3.13.0/coregrind/m_tooliface.c -+@@ -323,7 +323,7 @@ void VG_(needs_print_stats) ( -+ } -+ -+ void VG_(needs_info_location) ( -+- void (*info_location)(Addr) -++ void (*info_location)(DiEpoch, Addr) -+ ) -+ { -+ VG_(needs).info_location = True; -+Index: valgrind-3.13.0/coregrind/m_translate.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_translate.c -++++ valgrind-3.13.0/coregrind/m_translate.c -+@@ -1527,24 +1527,25 @@ Bool VG_(translate) ( ThreadId tid, -+ Bool ok; -+ const HChar *buf; -+ const HChar *name2; -++ const DiEpoch ep = VG_(current_DiEpoch)(); -+ -+ /* Try also to get the soname (not the filename) of the "from" -+ object. This makes it much easier to debug redirection -+ problems. */ -+ const HChar* nraddr_soname = "???"; -+- DebugInfo* nraddr_di = VG_(find_DebugInfo)(nraddr); -++ DebugInfo* nraddr_di = VG_(find_DebugInfo)(ep, nraddr); -+ if (nraddr_di) { -+ const HChar* t = VG_(DebugInfo_get_soname)(nraddr_di); -+ if (t) -+ nraddr_soname = t; -+ } -+ -+- ok = VG_(get_fnname_w_offset)(nraddr, &buf); -++ ok = VG_(get_fnname_w_offset)(ep, nraddr, &buf); -+ if (!ok) buf = "???"; -+ // Stash away name1 -+ HChar name1[VG_(strlen)(buf) + 1]; -+ VG_(strcpy)(name1, buf); -+- ok = VG_(get_fnname_w_offset)(addr, &name2); -++ ok = VG_(get_fnname_w_offset)(ep, addr, &name2); -+ if (!ok) name2 = "???"; -+ -+ VG_(message)(Vg_DebugMsg, -+@@ -1561,7 +1562,8 @@ Bool VG_(translate) ( ThreadId tid, -+ if (VG_(clo_trace_flags) || debugging_translation) { -+ const HChar* objname = "UNKNOWN_OBJECT"; -+ OffT objoff = 0; -+- DebugInfo* di = VG_(find_DebugInfo)( addr ); -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ DebugInfo* di = VG_(find_DebugInfo)( ep, addr ); -+ if (di) { -+ objname = VG_(DebugInfo_get_filename)(di); -+ objoff = addr - VG_(DebugInfo_get_text_bias)(di); -+@@ -1569,7 +1571,7 @@ Bool VG_(translate) ( ThreadId tid, -+ vg_assert(objname); -+ -+ const HChar *fnname; -+- Bool ok = VG_(get_fnname_w_offset)(addr, &fnname); -++ Bool ok = VG_(get_fnname_w_offset)(ep, addr, &fnname); -+ if (!ok) fnname = "UNKNOWN_FUNCTION"; -+ VG_(printf)( -+ "==== SB %u (evchecks %llu) [tid %u] 0x%lx %s %s%c0x%lx\n", -+Index: valgrind-3.13.0/coregrind/m_xtree.c -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/m_xtree.c -++++ valgrind-3.13.0/coregrind/m_xtree.c -+@@ -438,6 +438,9 @@ void VG_(XT_callgrind_print) -+ const HChar* filename_dir; -+ const HChar* filename_name; -+ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ if (fp == NULL) -+ return; -+ -+@@ -501,7 +504,7 @@ void VG_(XT_callgrind_print) -+ // the strings called_filename/called_fnname. -+ #define CALLED_FLF(n) \ -+ if ((n) < 0 \ -+- || !VG_(get_filename_linenum)(ips[(n)], \ -++ || !VG_(get_filename_linenum)(ep, ips[(n)], \ -+ &filename_name, \ -+ &filename_dir, \ -+ &called_linenum)) { \ -+@@ -509,7 +512,7 @@ void VG_(XT_callgrind_print) -+ called_linenum = 0; \ -+ } \ -+ if ((n) < 0 \ -+- || !VG_(get_fnname)(ips[(n)], &called_fnname)) { \ -++ || !VG_(get_fnname)(ep, ips[(n)], &called_fnname)) { \ -+ called_fnname = "UnknownFn???"; \ -+ } \ -+ { \ -+@@ -554,7 +557,9 @@ void VG_(XT_callgrind_print) -+ -+ if (0) { -+ VG_(printf)("entry img %s\n", img); -+- VG_(pp_ExeContext)(xe->ec); -++ // JRS 27 July 2017: it may be a hack to use the current epoch -++ // here. I don't know. -++ VG_(pp_ExeContextAndEpoch)(VG_(tag_EC_with_current_epoch)(xe->ec)); -+ VG_(printf)("\n"); -+ } -+ xt->add_data_fn(xt->tmp_data, VG_(indexXA)(xt->data, xecu)); -+@@ -762,11 +767,14 @@ static void ms_output_group (VgFile* fp, -+ ms_make_groups(depth+1, group->ms_ec, group->n_ec, sig_sz, -+ &n_groups, &groups); -+ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ FP("%*s" "n%u: %ld %s\n", -+ depth + 1, "", -+ n_groups, -+ group->total, -+- VG_(describe_IP)(group->ms_ec->ips[depth] - 1, NULL)); -++ VG_(describe_IP)(ep, group->ms_ec->ips[depth] - 1, NULL)); -+ /* XTREE??? Massif original code removes 1 to get the IP description. I am -+ wondering if this is not something that predates revision r8818, -+ which introduced a -1 in the stack unwind (see m_stacktrace.c) -+@@ -963,6 +971,10 @@ Int VG_(XT_offset_main_or_below_main)(Ad -+ from there. -+ If no main is found, we will then do a search for main or -+ below main function till the top. */ -++ -++ // FIXME JRS 28 July 2017: HACK! Is this correct? -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ static Int deepest_main = 0; -+ Vg_FnNameKind kind = Vg_FnNameNormal; -+ Int mbm = n_ips - 1; // Position of deepest main or below main. -+@@ -972,7 +984,7 @@ Int VG_(XT_offset_main_or_below_main)(Ad -+ for (i = n_ips - 1 - deepest_main; -+ i < n_ips; -+ i++) { -+- mbmkind = VG_(get_fnname_kind_from_IP)(ips[i]); -++ mbmkind = VG_(get_fnname_kind_from_IP)(ep, ips[i]); -+ if (mbmkind != Vg_FnNameNormal) { -+ mbm = i; -+ break; -+@@ -983,7 +995,7 @@ Int VG_(XT_offset_main_or_below_main)(Ad -+ for (i = mbm - 1; -+ i >= 0 && mbmkind != Vg_FnNameMain; -+ i--) { -+- kind = VG_(get_fnname_kind_from_IP)(ips[i]); -++ kind = VG_(get_fnname_kind_from_IP)(ep, ips[i]); -+ if (kind != Vg_FnNameNormal) { -+ mbm = i; -+ mbmkind = kind; -+Index: valgrind-3.13.0/coregrind/pub_core_debuginfo.h -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/pub_core_debuginfo.h -++++ valgrind-3.13.0/coregrind/pub_core_debuginfo.h -+@@ -86,20 +86,21 @@ extern void VG_(di_discard_ALL_debuginfo -+ * It should only be used in cases where the names of interest will have -+ * particular (ie. non-mangled) forms, or the mangled form is acceptable. */ -+ extern -+-Bool VG_(get_fnname_raw) ( Addr a, const HChar** buf ); -++Bool VG_(get_fnname_raw) ( DiEpoch ep, Addr a, const HChar** buf ); -+ -+ /* Like VG_(get_fnname), but without C++ demangling. (But it does -+ Z-demangling and below-main renaming.) -+ iipc argument: same usage as in VG_(describe_IP) in pub_tool_debuginfo.h. */ -+ extern -+-Bool VG_(get_fnname_no_cxx_demangle) ( Addr a, const HChar** buf, -++Bool VG_(get_fnname_no_cxx_demangle) ( DiEpoch ep, Addr a, const HChar** buf, -+ const InlIPCursor* iipc ); -+ -+ /* mips-linux only: find the offset of current address. This is needed for -+ stack unwinding for MIPS. -+ */ -+ extern -+-Bool VG_(get_inst_offset_in_function)( Addr a, /*OUT*/PtrdiffT* offset ); -++Bool VG_(get_inst_offset_in_function)( DiEpoch ep, Addr a, -++ /*OUT*/PtrdiffT* offset ); -+ -+ -+ /* Use DWARF2/3 CFA information to do one step of stack unwinding. -+@@ -158,6 +159,7 @@ extern Bool VG_(FPO_info_present)(void); -+ extern Bool VG_(use_FPO_info) ( /*MOD*/Addr* ipP, -+ /*MOD*/Addr* spP, -+ /*MOD*/Addr* fpP, -++ DiEpoch ep, -+ Addr min_accessible, -+ Addr max_accessible ); -+ -+@@ -217,7 +219,7 @@ void VG_(DebugInfo_syms_getidx) ( const -+ /* ppc64-linux only: find the TOC pointer (R2 value) that should be in -+ force at the entry point address of the function containing -+ guest_code_addr. Returns 0 if not known. */ -+-extern Addr VG_(get_tocptr) ( Addr guest_code_addr ); -++extern Addr VG_(get_tocptr) ( DiEpoch ep, Addr guest_code_addr ); -+ -+ /* Map a function name to its SymAVMAs. Is done by -+ sequential search of all symbol tables, so is very slow. To -+@@ -227,7 +229,8 @@ extern Addr VG_(get_tocptr) ( Addr guest -+ platforms, a symbol is deemed to be found only if it has a nonzero -+ TOC pointer. */ -+ extern -+-Bool VG_(lookup_symbol_SLOW)(const HChar* sopatt, const HChar* name, -++Bool VG_(lookup_symbol_SLOW)(DiEpoch ep, -++ const HChar* sopatt, const HChar* name, -+ SymAVMAs* avmas); -+ -+ #endif // __PUB_CORE_DEBUGINFO_H -+Index: valgrind-3.13.0/coregrind/pub_core_tooliface.h -+=================================================================== -+--- valgrind-3.13.0.orig/coregrind/pub_core_tooliface.h -++++ valgrind-3.13.0/coregrind/pub_core_tooliface.h -+@@ -156,7 +156,7 @@ typedef struct { -+ void (*tool_print_stats)(void); -+ -+ // VG_(needs).info_location -+- void (*tool_info_location)(Addr a); -++ void (*tool_info_location)(DiEpoch ep, Addr a); -+ -+ // VG_(needs).malloc_replacement -+ void* (*tool_malloc) (ThreadId, SizeT); -+Index: valgrind-3.13.0/docs/xml/manual-core.xml -+=================================================================== -+--- valgrind-3.13.0.orig/docs/xml/manual-core.xml -++++ valgrind-3.13.0/docs/xml/manual-core.xml -+@@ -1219,6 +1219,19 @@ that can report errors, e.g. Memcheck, b -+ </listitem> -+ </varlistentry> -+ -++ <varlistentry id="opt.keep-debuginfo" xreflabel="--keep-debuginfo"> -++ <term> -++ <option><![CDATA[--keep-debuginfo=<yes|no> [default: no] ]]></option> -++ </term> -++ <listitem> -++ <para>When enabled, keep symbols and all other debuginfo for unloaded -++ code. This allows stack traces for memory leaks to include file/line -++ info for code that has been dlclose'd (or similar). Be careful with -++ this, since it can lead to unbounded memory use for programs which -++ repeatedly load and unload shard objects.</para> -++ </listitem> -++ </varlistentry> -++ -+ <varlistentry id="opt.show-below-main" xreflabel="--show-below-main"> -+ <term> -+ <option><![CDATA[--show-below-main=<yes|no> [default: no] ]]></option> -+Index: valgrind-3.13.0/drd/drd_error.c -+=================================================================== -+--- valgrind-3.13.0.orig/drd/drd_error.c -++++ valgrind-3.13.0/drd/drd_error.c -+@@ -139,12 +139,14 @@ static void first_observed(const Addr ob -+ " <what>%pS</what>\n" -+ " <address>0x%lx</address>\n", -+ DRD_(clientobj_type_name)(cl->any.type), obj); -+- VG_(pp_ExeContext)(cl->any.first_observed_at); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(cl->any.first_observed_at)); -+ print_err_detail(" </first_observed_at>\n"); -+ } else { -+ print_err_detail("%s 0x%lx was first observed at:\n", -+ DRD_(clientobj_type_name)(cl->any.type), obj); -+- VG_(pp_ExeContext)(cl->any.first_observed_at); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(cl->any.first_observed_at)); -+ } -+ } -+ } -+@@ -161,6 +163,7 @@ void drd_report_data_race(const Error* c -+ const HChar* const indent = xml ? " " : ""; -+ AddrInfo ai; -+ -++ DiEpoch ep = VG_(current_DiEpoch)(); -+ XArray* /* of HChar */ descr1 -+ = VG_(newXA)( VG_(malloc), "drd.error.drdr2.1", -+ VG_(free), sizeof(HChar) ); -+@@ -172,7 +175,7 @@ void drd_report_data_race(const Error* c -+ tl_assert(dri->addr); -+ tl_assert(dri->size > 0); -+ -+- (void) VG_(get_data_description)(descr1, descr2, dri->addr); -++ (void) VG_(get_data_description)(descr1, descr2, ep, dri->addr); -+ /* If there's nothing in descr1/2, free them. Why is it safe to -+ VG_(indexXA) at zero here? Because VG_(get_data_description) -+ guarantees to zero terminate descr1/2 regardless of the outcome -+@@ -202,7 +205,7 @@ void drd_report_data_race(const Error* c -+ what_prefix, dri->access_type == eStore ? "store" : "load", -+ dri->tid, dri->addr, dri->size, what_suffix); -+ -+- VG_(pp_ExeContext)(VG_(get_error_where)(err)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(err)); -+ if (descr1 != NULL) { -+ print_err_detail("%s%s\n", indent, (HChar*)VG_(indexXA)(descr1, 0)); -+ if (descr2 != NULL) -+@@ -216,7 +219,7 @@ void drd_report_data_race(const Error* c -+ print_err_detail(" <allocation_context>\n"); -+ else -+ print_err_detail(" Allocation context:\n"); -+- VG_(pp_ExeContext)(ai.lastchange); -++ VG_(pp_ExeContextAndEpoch)(mk_ExeContextAndEpoch(ai.lastchange, ep)); -+ if (xml) -+ print_err_detail(" </allocation_context>\n"); -+ } else { -+@@ -322,7 +325,7 @@ static void drd_tool_error_pp(const Erro -+ print_err_detail("%sThe object at address 0x%lx is not a mutex.%s\n", -+ what_prefix, p->mutex, what_suffix); -+ } -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ first_observed(p->mutex); -+ break; -+ } -+@@ -330,7 +333,7 @@ static void drd_tool_error_pp(const Erro -+ CondErrInfo* cdei =(CondErrInfo*)(VG_(get_error_extra)(e)); -+ print_err_detail("%s%s: cond 0x%lx%s\n", what_prefix, -+ VG_(get_error_string)(e), cdei->cond, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ first_observed(cdei->cond); -+ break; -+ } -+@@ -339,7 +342,7 @@ static void drd_tool_error_pp(const Erro -+ print_err_detail("%s%s: cond 0x%lx, mutex 0x%lx locked by thread %u%s\n", -+ what_prefix, VG_(get_error_string)(e), cdi->cond, -+ cdi->mutex, cdi->owner, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ first_observed(cdi->mutex); -+ break; -+ } -+@@ -349,7 +352,7 @@ static void drd_tool_error_pp(const Erro -+ " has been signaled but the associated mutex 0x%lx is" -+ " not locked by the signalling thread.%s\n", -+ what_prefix, cei->cond, cei->mutex, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ first_observed(cei->cond); -+ first_observed(cei->mutex); -+ break; -+@@ -359,7 +362,7 @@ static void drd_tool_error_pp(const Erro -+ print_err_detail("%s%s: condition variable 0x%lx, mutexes 0x%lx and" -+ " 0x%lx%s\n", what_prefix, VG_(get_error_string)(e), -+ cwei->cond, cwei->mutex1, cwei->mutex2, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ first_observed(cwei->cond); -+ first_observed(cwei->mutex1); -+ first_observed(cwei->mutex2); -+@@ -370,7 +373,7 @@ static void drd_tool_error_pp(const Erro -+ tl_assert(sei); -+ print_err_detail("%s%s: semaphore 0x%lx%s\n", what_prefix, -+ VG_(get_error_string)(e), sei->semaphore, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ first_observed(sei->semaphore); -+ break; -+ } -+@@ -379,13 +382,14 @@ static void drd_tool_error_pp(const Erro -+ tl_assert(bei); -+ print_err_detail("%s%s: barrier 0x%lx%s\n", what_prefix, -+ VG_(get_error_string)(e), bei->barrier, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ if (bei->other_context) { -+ if (xml) -+ print_err_detail(" <confl_wait_call>\n"); -+ print_err_detail("%sConflicting wait call by thread %u:%s\n", -+ what_prefix, bei->other_tid, what_suffix); -+- VG_(pp_ExeContext)(bei->other_context); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(bei->other_context)); -+ if (xml) -+ print_err_detail(" </confl_wait_call>\n"); -+ } -+@@ -397,7 +401,7 @@ static void drd_tool_error_pp(const Erro -+ tl_assert(p); -+ print_err_detail("%s%s: rwlock 0x%lx.%s\n", what_prefix, -+ VG_(get_error_string)(e), p->rwlock, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ first_observed(p->rwlock); -+ break; -+ } -+@@ -409,14 +413,15 @@ static void drd_tool_error_pp(const Erro -+ print_err_detail(" <acquired_at>\n"); -+ else -+ print_err_detail("Acquired at:\n"); -+- VG_(pp_ExeContext)(p->acquired_at); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(p->acquired_at)); -+ if (xml) -+ print_err_detail(" </acquired_at>\n"); -+ print_err_detail("%sLock on %s 0x%lx was held during %u ms" -+ " (threshold: %u ms).%s\n", what_prefix, -+ VG_(get_error_string)(e), p->synchronization_object, -+ p->hold_time_ms, p->threshold_ms, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ first_observed(p->synchronization_object); -+ break; -+ } -+@@ -424,7 +429,7 @@ static void drd_tool_error_pp(const Erro -+ GenericErrInfo* gei = (GenericErrInfo*)(VG_(get_error_extra)(e)); -+ print_err_detail("%s%s%s\n", what_prefix, VG_(get_error_string)(e), -+ what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ if (gei->addr) -+ first_observed(gei->addr); -+ break; -+@@ -433,7 +438,7 @@ static void drd_tool_error_pp(const Erro -+ InvalidThreadIdInfo* iti =(InvalidThreadIdInfo*)(VG_(get_error_extra)(e)); -+ print_err_detail("%s%s 0x%llx%s\n", what_prefix, VG_(get_error_string)(e), -+ iti->ptid, what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ break; -+ } -+ case UnimpHgClReq: { -+@@ -441,7 +446,7 @@ static void drd_tool_error_pp(const Erro -+ print_err_detail("%sThe annotation macro %s has not yet been implemented" -+ " in %ps%s\n", what_prefix, uicr->descr, -+ "<valgrind/helgrind.h>", what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ break; -+ } -+ case UnimpDrdClReq: { -+@@ -449,13 +454,13 @@ static void drd_tool_error_pp(const Erro -+ print_err_detail("%sThe annotation macro %s has not yet been implemented" -+ " in %ps%s\n", what_prefix, uicr->descr, -+ "<valgrind/drd.h>", what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ break; -+ } -+ default: -+ print_err_detail("%s%s%s\n", what_prefix, VG_(get_error_string)(e), -+ what_suffix); -+- VG_(pp_ExeContext)(VG_(get_error_where)(e)); -++ VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e)); -+ break; -+ } -+ } -+Index: valgrind-3.13.0/drd/drd_thread.c -+=================================================================== -+--- valgrind-3.13.0.orig/drd/drd_thread.c -++++ valgrind-3.13.0/drd/drd_thread.c -+@@ -1338,7 +1338,8 @@ static void show_call_stack(const DrdThr -+ -+ if (vg_tid != VG_INVALID_THREADID) { -+ if (callstack) -+- VG_(pp_ExeContext)(callstack); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(callstack)); -+ else -+ VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size)); -+ } else { -+Index: valgrind-3.13.0/exp-bbv/bbv_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/exp-bbv/bbv_main.c -++++ valgrind-3.13.0/exp-bbv/bbv_main.c -+@@ -346,6 +346,7 @@ static IRSB* bbv_instrument ( VgCallback -+ IRDirty *di; -+ IRExpr **argv, *arg1; -+ Int regparms,opcode_type; -++ DiEpoch ep = VG_(current_DiEpoch)(); -+ -+ /* We don't handle a host/guest word size mismatch */ -+ if (gWordTy != hWordTy) { -+@@ -392,8 +393,8 @@ static IRSB* bbv_instrument ( VgCallback -+ block_num++; -+ /* get function name and entry point information */ -+ const HChar *fn_name; -+- VG_(get_fnname)(origAddr, &fn_name); -+- bbInfo->is_entry=VG_(get_fnname_if_entry)(origAddr, &fn_name); -++ VG_(get_fnname)(ep, origAddr, &fn_name); -++ bbInfo->is_entry=VG_(get_fnname_if_entry)(ep, origAddr, &fn_name); -+ bbInfo->fn_name =VG_(strdup)("bbv_strings", fn_name); -+ /* insert structure into table */ -+ VG_(OSetGen_Insert)( instr_info_table, bbInfo ); -+Index: valgrind-3.13.0/exp-dhat/dh_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/exp-dhat/dh_main.c -++++ valgrind-3.13.0/exp-dhat/dh_main.c -+@@ -1146,7 +1146,7 @@ static void show_APInfo ( APInfo* api ) -+ bufR, bufW, -+ api->n_reads, api->n_writes); -+ -+- VG_(pp_ExeContext)(api->ap); -++ VG_(pp_ExeContextAndEpoch)(VG_(tag_EC_with_current_epoch)(api->ap)); -+ -+ if (api->histo && api->xsize_tag == Exactly) { -+ VG_(umsg)("\nAggregated access counts by offset:\n"); -+Index: valgrind-3.13.0/exp-sgcheck/pc_common.c -+=================================================================== -+--- valgrind-3.13.0.orig/exp-sgcheck/pc_common.c -++++ valgrind-3.13.0/exp-sgcheck/pc_common.c -+@@ -322,7 +322,7 @@ void pc_pp_Error ( const Error* err ) -+ emit( " <what>Invalid %s of size %ld</what>\n", -+ xe->XE.SorG.sszB < 0 ? "write" : "read", -+ Word__abs(xe->XE.SorG.sszB) ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ emit( " <auxwhat>Address %#lx expected vs actual:</auxwhat>\n", -+ xe->XE.SorG.addr ); -+@@ -336,7 +336,7 @@ void pc_pp_Error ( const Error* err ) -+ emit( "Invalid %s of size %ld\n", -+ xe->XE.SorG.sszB < 0 ? "write" : "read", -+ Word__abs(xe->XE.SorG.sszB) ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ emit( " Address %#lx expected vs actual:\n", xe->XE.SorG.addr ); -+ emit( " Expected: %s\n", &xe->XE.SorG.expect[0] ); -+@@ -362,7 +362,7 @@ void pc_pp_Error ( const Error* err ) -+ emit( " <what>Invalid %s of size %ld</what>\n", -+ readwrite(xe->XE.Heap.sszB), -+ Word__abs(xe->XE.Heap.sszB) ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ emit( " <auxwhat>Address %#lx is not derived from " -+ "any known block</auxwhat>\n", a ); -+@@ -372,7 +372,7 @@ void pc_pp_Error ( const Error* err ) -+ emit( "Invalid %s of size %ld\n", -+ readwrite(xe->XE.Heap.sszB), -+ Word__abs(xe->XE.Heap.sszB) ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ emit( " Address %#lx is not derived from " -+ "any known block\n", a ); -+@@ -397,7 +397,7 @@ void pc_pp_Error ( const Error* err ) -+ how_invalid, -+ readwrite(xe->XE.Heap.sszB), -+ Word__abs(xe->XE.Heap.sszB) ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ emit( " <auxwhat>Address %#lx is %lu bytes %s " -+ "the accessing pointer's</auxwhat>\n", -+@@ -406,7 +406,8 @@ void pc_pp_Error ( const Error* err ) -+ "a block of size %lu %s</auxwhat>\n", -+ legit, Seg__size(vseg), -+ Seg__is_freed(vseg) ? "free'd" : "alloc'd" ); -+- VG_(pp_ExeContext)(Seg__where(vseg)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(vseg))); -+ -+ } else { -+ -+@@ -414,14 +415,15 @@ void pc_pp_Error ( const Error* err ) -+ how_invalid, -+ readwrite(xe->XE.Heap.sszB), -+ Word__abs(xe->XE.Heap.sszB) ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ emit( " Address %#lx is %lu bytes %s the accessing pointer's\n", -+ a, miss_size, place ); -+ emit( " %slegitimate range, a block of size %lu %s\n", -+ legit, Seg__size(vseg), -+ Seg__is_freed(vseg) ? "free'd" : "alloc'd" ); -+- VG_(pp_ExeContext)(Seg__where(vseg)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(vseg))); -+ -+ } -+ } -+@@ -477,7 +479,7 @@ void pc_pp_Error ( const Error* err ) -+ -+ emit( " <what>Invalid arguments to %s</what>\n", -+ xe->XE.Arith.opname ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ if (seg1 != seg2) { -+ if (NONPTR == seg1) { -+@@ -488,7 +490,8 @@ void pc_pp_Error ( const Error* err ) -+ emit( " <auxwhat>First arg derived from address %#lx of " -+ "%lu-byte block alloc'd</auxwhat>\n", -+ Seg__addr(seg1), Seg__size(seg1) ); -+- VG_(pp_ExeContext)(Seg__where(seg1)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seg1))); -+ } -+ which = "Second arg"; -+ } else { -+@@ -500,14 +503,15 @@ void pc_pp_Error ( const Error* err ) -+ emit( " <auxwhat>%s derived from address %#lx of " -+ "%lu-byte block alloc'd</auxwhat>\n", -+ which, Seg__addr(seg2), Seg__size(seg2) ); -+- VG_(pp_ExeContext)(Seg__where(seg2)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seg2))); -+ } -+ -+ } else { -+ -+ emit( "Invalid arguments to %s\n", -+ xe->XE.Arith.opname ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ if (seg1 != seg2) { -+ if (NONPTR == seg1) { -+@@ -518,7 +522,8 @@ void pc_pp_Error ( const Error* err ) -+ emit( " First arg derived from address %#lx of " -+ "%lu-byte block alloc'd\n", -+ Seg__addr(seg1), Seg__size(seg1) ); -+- VG_(pp_ExeContext)(Seg__where(seg1)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seg1))); -+ } -+ which = "Second arg"; -+ } else { -+@@ -530,7 +535,8 @@ void pc_pp_Error ( const Error* err ) -+ emit( " %s derived from address %#lx of " -+ "%lu-byte block alloc'd\n", -+ which, Seg__addr(seg2), Seg__size(seg2) ); -+- VG_(pp_ExeContext)(Seg__where(seg2)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seg2))); -+ } -+ -+ } -+@@ -562,23 +568,25 @@ void pc_pp_Error ( const Error* err ) -+ -+ emit( " <what>%s%s contains unaddressable byte(s)</what>\n", -+ what, s ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ emit( " <auxwhat>Address %#lx is %lu bytes inside a " -+ "%lu-byte block free'd</auxwhat>\n", -+ lo, lo-Seg__addr(seglo), Seg__size(seglo) ); -+- VG_(pp_ExeContext)(Seg__where(seglo)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seglo))); -+ -+ } else { -+ -+ emit( " %s%s contains unaddressable byte(s)\n", -+ what, s ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ emit( " Address %#lx is %lu bytes inside a " -+ "%lu-byte block free'd\n", -+ lo, lo-Seg__addr(seglo), Seg__size(seglo) ); -+- VG_(pp_ExeContext)(Seg__where(seglo)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seglo))); -+ -+ } -+ -+@@ -589,7 +597,7 @@ void pc_pp_Error ( const Error* err ) -+ -+ emit( " <what>%s%s is non-contiguous</what>\n", -+ what, s ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ if (UNKNOWN == seglo) { -+ emit( " <auxwhat>First byte is " -+@@ -598,7 +606,8 @@ void pc_pp_Error ( const Error* err ) -+ emit( " <auxwhat>First byte (%#lx) is %lu bytes inside a " -+ "%lu-byte block alloc'd</auxwhat>\n", -+ lo, lo-Seg__addr(seglo), Seg__size(seglo) ); -+- VG_(pp_ExeContext)(Seg__where(seglo)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seglo))); -+ } -+ -+ if (UNKNOWN == seghi) { -+@@ -608,14 +617,15 @@ void pc_pp_Error ( const Error* err ) -+ emit( " <auxwhat>Last byte (%#lx) is %lu bytes inside a " -+ "%lu-byte block alloc'd</auxwhat>\n", -+ hi, hi-Seg__addr(seghi), Seg__size(seghi) ); -+- VG_(pp_ExeContext)(Seg__where(seghi)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seghi))); -+ } -+ -+ } else { -+ -+ emit( "%s%s is non-contiguous\n", -+ what, s ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ if (UNKNOWN == seglo) { -+ emit( " First byte is not inside a known block\n" ); -+@@ -623,7 +633,8 @@ void pc_pp_Error ( const Error* err ) -+ emit( " First byte (%#lx) is %lu bytes inside a " -+ "%lu-byte block alloc'd\n", -+ lo, lo-Seg__addr(seglo), Seg__size(seglo) ); -+- VG_(pp_ExeContext)(Seg__where(seglo)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seglo))); -+ } -+ -+ if (UNKNOWN == seghi) { -+@@ -632,7 +643,8 @@ void pc_pp_Error ( const Error* err ) -+ emit( " Last byte (%#lx) is %lu bytes inside a " -+ "%lu-byte block alloc'd\n", -+ hi, hi-Seg__addr(seghi), Seg__size(seghi) ); -+- VG_(pp_ExeContext)(Seg__where(seghi)); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)(Seg__where(seghi))); -+ } -+ -+ } -+@@ -650,6 +662,8 @@ void pc_pp_Error ( const Error* err ) -+ UInt pc_update_Error_extra ( const Error* err ) -+ { -+ XError *xe = (XError*)VG_(get_error_extra)(err); -++ DiEpoch ep = VG_(get_error_where)(err).epoch; -++ -+ tl_assert(xe); -+ switch (xe->tag) { -+ case XE_SorG: -+@@ -675,7 +689,7 @@ UInt pc_update_Error_extra ( const Error -+ have_descr -+ = VG_(get_data_description)( xe->XE.Heap.descr1, -+ xe->XE.Heap.descr2, -+- xe->XE.Heap.addr ); -++ ep, xe->XE.Heap.addr ); -+ -+ /* If there's nothing in descr1/2, free it. Why is it safe to -+ to VG_(indexXA) at zero here? Because -+@@ -699,7 +713,7 @@ UInt pc_update_Error_extra ( const Error -+ if (!have_descr) { -+ const HChar *name; -+ if (VG_(get_datasym_and_offset)( -+- xe->XE.Heap.addr, &name, -++ ep, xe->XE.Heap.addr, &name, -+ &xe->XE.Heap.datasymoff ) -+ ) { -+ xe->XE.Heap.datasym = -+Index: valgrind-3.13.0/exp-sgcheck/sg_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/exp-sgcheck/sg_main.c -++++ valgrind-3.13.0/exp-sgcheck/sg_main.c -+@@ -1936,7 +1936,8 @@ void shadowStack_new_frame ( ThreadId ti -+ const HChar *fnname; -+ Bool ok; -+ Addr ip = ip_post_call_insn; -+- ok = VG_(get_fnname_w_offset)( ip, &fnname ); -++ DiEpoch ep = VG_(current_DiEpoch)(); -++ ok = VG_(get_fnname_w_offset)( ep, ip, &fnname ); -+ while (d > 0) { -+ VG_(printf)(" "); -+ d--; -+Index: valgrind-3.13.0/helgrind/hg_addrdescr.c -+=================================================================== -+--- valgrind-3.13.0.orig/helgrind/hg_addrdescr.c -++++ valgrind-3.13.0/helgrind/hg_addrdescr.c -+@@ -45,7 +45,7 @@ -+ #include "hg_lock_n_thread.h" -+ #include "hg_addrdescr.h" /* self */ -+ -+-void HG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai ) -++void HG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai ) -+ { -+ tl_assert(ai->tag == Addr_Undescribed); -+ -+@@ -75,13 +75,14 @@ void HG_(describe_addr) ( Addr a, /*OUT* -+ ai->Addr.Block.block_desc = "block"; -+ ai->Addr.Block.block_szB = hszB; -+ ai->Addr.Block.rwoffset = (Word)(a) - (Word)(haddr); -+- ai->Addr.Block.allocated_at = hctxt; -++ ai->Addr.Block.allocated_at.ec = hctxt; -++ ai->Addr.Block.allocated_at.epoch = ep; -+ VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo); -+ ai->Addr.Block.alloc_tinfo.tnr = tnr; -+- ai->Addr.Block.freed_at = VG_(null_ExeContext)();; -++ ai->Addr.Block.freed_at = VG_(null_ExeContextAndEpoch)(); -+ } else { -+ /* No block found. Search a non-heap block description. */ -+- VG_(describe_addr) (a, ai); -++ VG_(describe_addr) (ep, a, ai); -+ -+ /* In case ai contains a tid, set tnr to the corresponding helgrind -+ thread number. */ -+@@ -100,14 +101,14 @@ void HG_(describe_addr) ( Addr a, /*OUT* -+ } -+ } -+ -+-Bool HG_(get_and_pp_addrdescr) (Addr addr) -++Bool HG_(get_and_pp_addrdescr) (DiEpoch ep, Addr addr) -+ { -+ -+ Bool ret; -+ AddrInfo glai; -+ -+ glai.tag = Addr_Undescribed; -+- HG_(describe_addr) (addr, &glai); -++ HG_(describe_addr) (ep, addr, &glai); -+ VG_(pp_addrinfo) (addr, &glai); -+ ret = glai.tag != Addr_Unknown; -+ -+Index: valgrind-3.13.0/helgrind/hg_addrdescr.h -+=================================================================== -+--- valgrind-3.13.0.orig/helgrind/hg_addrdescr.h -++++ valgrind-3.13.0/helgrind/hg_addrdescr.h -+@@ -37,12 +37,12 @@ -+ lock description, putting the result in ai. -+ This might allocate some memory in ai, to be cleared with -+ VG_(clear_addrinfo). */ -+-extern void HG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai ); -++extern void HG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai ); -+ -+ /* Get a readable description of addr, then print it using HG_(pp_addrdescr) -+ using xml False and VG_(printf) to emit the characters. -+ Returns True if a description was found/printed, False otherwise. */ -+-extern Bool HG_(get_and_pp_addrdescr) (Addr a); -++extern Bool HG_(get_and_pp_addrdescr) (DiEpoch ep, Addr a); -+ -+ /* For error creation/address description: -+ map 'data_addr' to a malloc'd chunk, if any. -+Index: valgrind-3.13.0/helgrind/hg_errors.c -+=================================================================== -+--- valgrind-3.13.0.orig/helgrind/hg_errors.c -++++ valgrind-3.13.0/helgrind/hg_errors.c -+@@ -421,7 +421,8 @@ UInt HG_(update_extra) ( const Error* er -+ VG_(printf)("HG_(update_extra): " -+ "%d conflicting-event queries\n", xxx); -+ -+- HG_(describe_addr) (xe->XE.Race.data_addr, &xe->XE.Race.data_addrinfo); -++ HG_(describe_addr) (VG_(get_error_where)(err).epoch, -++ xe->XE.Race.data_addr, &xe->XE.Race.data_addrinfo); -+ -+ /* And poke around in the conflicting-event map, to see if we -+ can rustle up a plausible-looking conflicting memory access -+@@ -748,7 +749,8 @@ static Bool announce_one_thread ( Thread -+ VG_(printf_xml)(" <isrootthread></isrootthread>\n"); -+ } else { -+ tl_assert(thr->created_at != NULL); -+- VG_(pp_ExeContext)( thr->created_at ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( thr->created_at ) ); -+ } -+ VG_(printf_xml)("</announcethread>\n\n"); -+ -+@@ -767,7 +769,8 @@ static Bool announce_one_thread ( Thread -+ tl_assert(thr->created_at != NULL); -+ VG_(message)(Vg_UserMsg, "Thread #%d was created\n", -+ thr->errmsg_index); -+- VG_(pp_ExeContext)( thr->created_at ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( thr->created_at ) ); -+ } -+ VG_(message)(Vg_UserMsg, "\n"); -+ -+@@ -789,19 +792,21 @@ static void announce_LockP ( Lock* lk ) -+ if (lk->appeared_at) { -+ emit( " <auxwhat>Lock at %p was first observed</auxwhat>\n", -+ (void*)lk ); -+- VG_(pp_ExeContext)( lk->appeared_at ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( lk->appeared_at ) ); -+ } -+ -+ } else { -+ if (lk->appeared_at) { -+ VG_(umsg)( " Lock at %p was first observed\n", -+ (void*)lk->guestaddr ); -+- VG_(pp_ExeContext)( lk->appeared_at ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( lk->appeared_at ) ); -+ } else { -+ VG_(umsg)( " Lock at %p : no stacktrace for first observation\n", -+ (void*)lk->guestaddr ); -+ } -+- HG_(get_and_pp_addrdescr) (lk->guestaddr); -++ HG_(get_and_pp_addrdescr) (VG_(current_DiEpoch)(), lk->guestaddr); -+ VG_(umsg)("\n"); -+ } -+ } -+@@ -941,11 +946,12 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( " <hthreadid>%d</hthreadid>\n", -+ (Int)xe->XE.Misc.thr->errmsg_index ); -+ emit( " </xwhat>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ if (xe->XE.Misc.auxstr) { -+ emit(" <auxwhat>%s</auxwhat>\n", xe->XE.Misc.auxstr); -+ if (xe->XE.Misc.auxctx) -+- VG_(pp_ExeContext)( xe->XE.Misc.auxctx ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( xe->XE.Misc.auxctx )); -+ } -+ -+ } else { -+@@ -953,11 +959,12 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( "Thread #%d: %s\n", -+ (Int)xe->XE.Misc.thr->errmsg_index, -+ xe->XE.Misc.errstr ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ if (xe->XE.Misc.auxstr) { -+ emit(" %s\n", xe->XE.Misc.auxstr); -+ if (xe->XE.Misc.auxctx) -+- VG_(pp_ExeContext)( xe->XE.Misc.auxctx ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( xe->XE.Misc.auxctx )); -+ } -+ -+ } -+@@ -978,17 +985,21 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( " <hthreadid>%d</hthreadid>\n", -+ (Int)xe->XE.LockOrder.thr->errmsg_index ); -+ emit( " </xwhat>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ if (xe->XE.LockOrder.shouldbe_earlier_ec -+ && xe->XE.LockOrder.shouldbe_later_ec) { -+ emit( " <auxwhat>Required order was established by " -+ "acquisition of lock at %p</auxwhat>\n", -+ (void*)xe->XE.LockOrder.shouldbe_earlier_lk->guestaddr ); -+- VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_earlier_ec ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.LockOrder.shouldbe_earlier_ec )); -+ emit( " <auxwhat>followed by a later acquisition " -+ "of lock at %p</auxwhat>\n", -+ (void*)xe->XE.LockOrder.shouldbe_later_lk->guestaddr ); -+- VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_later_ec ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.LockOrder.shouldbe_later_ec )); -+ } -+ announce_LockP ( xe->XE.LockOrder.shouldbe_earlier_lk ); -+ announce_LockP ( xe->XE.LockOrder.shouldbe_later_lk ); -+@@ -1004,25 +1015,31 @@ void HG_(pp_Error) ( const Error* err ) -+ "acquisition of lock at %p\n", -+ (void*)xe->XE.LockOrder.shouldbe_later_lk->guestaddr); -+ if (xe->XE.LockOrder.actual_earlier_ec) { -+- VG_(pp_ExeContext)(xe->XE.LockOrder.actual_earlier_ec); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.LockOrder.actual_earlier_ec)); -+ } else { -+ emit(" (stack unavailable)\n"); -+ } -+ emit( "\n" ); -+ emit(" followed by a later acquisition of lock at %p\n", -+ (void*)xe->XE.LockOrder.shouldbe_earlier_lk->guestaddr); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ if (xe->XE.LockOrder.shouldbe_earlier_ec -+ && xe->XE.LockOrder.shouldbe_later_ec) { -+ emit("\n"); -+ emit( "Required order was established by " -+ "acquisition of lock at %p\n", -+ (void*)xe->XE.LockOrder.shouldbe_earlier_lk->guestaddr ); -+- VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_earlier_ec ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.LockOrder.shouldbe_earlier_ec )); -+ emit( "\n" ); -+ emit( " followed by a later acquisition of lock at %p\n", -+ (void*)xe->XE.LockOrder.shouldbe_later_lk->guestaddr ); -+- VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_later_ec ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.LockOrder.shouldbe_later_ec )); -+ } -+ emit("\n"); -+ announce_LockP ( xe->XE.LockOrder.shouldbe_earlier_lk ); -+@@ -1048,7 +1065,7 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( " </xwhat>\n" ); -+ emit( " <what>with error code %ld (%s)</what>\n", -+ xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ } else { -+ -+@@ -1057,7 +1074,7 @@ void HG_(pp_Error) ( const Error* err ) -+ xe->XE.PthAPIerror.fnname ); -+ emit( " with error code %ld (%s)\n", -+ xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ } -+ -+@@ -1077,14 +1094,14 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( " <hthreadid>%d</hthreadid>\n", -+ (Int)xe->XE.UnlockBogus.thr->errmsg_index ); -+ emit( " </xwhat>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ } else { -+ -+ emit( "Thread #%d unlocked an invalid lock at %p\n", -+ (Int)xe->XE.UnlockBogus.thr->errmsg_index, -+ (void*)xe->XE.UnlockBogus.lock_ga ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ } -+ -+@@ -1109,7 +1126,7 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( " <hthreadid>%d</hthreadid>\n", -+ (Int)xe->XE.UnlockForeign.owner->errmsg_index ); -+ emit( " </xwhat>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ announce_LockP ( xe->XE.UnlockForeign.lock ); -+ -+ } else { -+@@ -1119,7 +1136,7 @@ void HG_(pp_Error) ( const Error* err ) -+ (Int)xe->XE.UnlockForeign.thr->errmsg_index, -+ (void*)xe->XE.UnlockForeign.lock->guestaddr, -+ (Int)xe->XE.UnlockForeign.owner->errmsg_index ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ announce_LockP ( xe->XE.UnlockForeign.lock ); -+ -+ } -+@@ -1141,7 +1158,7 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( " <hthreadid>%d</hthreadid>\n", -+ (Int)xe->XE.UnlockUnlocked.thr->errmsg_index ); -+ emit( " </xwhat>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ announce_LockP ( xe->XE.UnlockUnlocked.lock); -+ -+ } else { -+@@ -1149,7 +1166,7 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( "Thread #%d unlocked a not-locked lock at %p\n", -+ (Int)xe->XE.UnlockUnlocked.thr->errmsg_index, -+ (void*)xe->XE.UnlockUnlocked.lock->guestaddr ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ announce_LockP ( xe->XE.UnlockUnlocked.lock); -+ -+ } -+@@ -1179,7 +1196,7 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( " <hthreadid>%d</hthreadid>\n", -+ (Int)xe->XE.Race.thr->errmsg_index ); -+ emit( " </xwhat>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ if (xe->XE.Race.h2_ct) { -+ tl_assert(xe->XE.Race.h2_ct_accEC); // assured by update_extra -+@@ -1192,7 +1209,8 @@ void HG_(pp_Error) ( const Error* err ) -+ emit( " <hthreadid>%d</hthreadid>\n", -+ xe->XE.Race.h2_ct->errmsg_index); -+ emit(" </xauxwhat>\n"); -+- VG_(pp_ExeContext)( xe->XE.Race.h2_ct_accEC ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( xe->XE.Race.h2_ct_accEC )); -+ } -+ -+ if (xe->XE.Race.h1_ct) { -+@@ -1204,13 +1222,17 @@ void HG_(pp_Error) ( const Error* err ) -+ xe->XE.Race.h1_ct->errmsg_index ); -+ emit(" </xauxwhat>\n"); -+ if (xe->XE.Race.h1_ct_mbsegstartEC) { -+- VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegstartEC ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.Race.h1_ct_mbsegstartEC )); -+ } else { -+ emit( " <auxwhat>(the start of the thread)</auxwhat>\n" ); -+ } -+ emit( " <auxwhat>but before</auxwhat>\n" ); -+ if (xe->XE.Race.h1_ct_mbsegendEC) { -+- VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegendEC ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.Race.h1_ct_mbsegendEC )); -+ } else { -+ emit( " <auxwhat>(the end of the thread)</auxwhat>\n" ); -+ } -+@@ -1228,7 +1250,7 @@ void HG_(pp_Error) ( const Error* err ) -+ -+ tl_assert(xe->XE.Race.locksHeldW); -+ show_LockP_summary_textmode( xe->XE.Race.locksHeldW, "" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ if (xe->XE.Race.h2_ct) { -+ tl_assert(xe->XE.Race.h2_ct_accEC); // assured by update_extra -+@@ -1240,7 +1262,8 @@ void HG_(pp_Error) ( const Error* err ) -+ xe->XE.Race.h2_ct_accSzB, -+ xe->XE.Race.h2_ct->errmsg_index ); -+ show_LockP_summary_textmode( xe->XE.Race.h2_ct_locksHeldW, "" ); -+- VG_(pp_ExeContext)( xe->XE.Race.h2_ct_accEC ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( xe->XE.Race.h2_ct_accEC )); -+ } -+ -+ if (xe->XE.Race.h1_ct) { -+@@ -1248,13 +1271,17 @@ void HG_(pp_Error) ( const Error* err ) -+ "after\n", -+ xe->XE.Race.h1_ct->errmsg_index ); -+ if (xe->XE.Race.h1_ct_mbsegstartEC) { -+- VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegstartEC ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.Race.h1_ct_mbsegstartEC )); -+ } else { -+ emit( " (the start of the thread)\n" ); -+ } -+ emit( " but before\n" ); -+ if (xe->XE.Race.h1_ct_mbsegendEC) { -+- VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegendEC ); -++ VG_(pp_ExeContextAndEpoch)( -++ VG_(tag_EC_with_current_epoch)( -++ xe->XE.Race.h1_ct_mbsegendEC )); -+ } else { -+ emit( " (the end of the thread)\n" ); -+ } -+@@ -1307,7 +1334,7 @@ void HG_(print_access) (StackTrace ips, -+ show_LockP_summary_textmode( locksHeldW_P, "" ); -+ HG_(free) (locksHeldW_P); -+ } -+- VG_(pp_StackTrace) (ips, n_ips); -++ VG_(pp_StackTrace)( VG_(current_DiEpoch)(), ips, n_ips ); -+ VG_(printf) ("\n"); -+ } -+ -+Index: valgrind-3.13.0/helgrind/hg_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/helgrind/hg_main.c -++++ valgrind-3.13.0/helgrind/hg_main.c -+@@ -483,13 +483,14 @@ static void pp_Lock ( Int d, Lock* lk, -+ Bool show_lock_addrdescr, -+ Bool show_internal_data) -+ { -++ DiEpoch ep = VG_(current_DiEpoch)(); -+ space(d+0); -+ if (show_internal_data) -+ VG_(printf)("Lock %p (ga %#lx) {\n", lk, lk->guestaddr); -+ else -+ VG_(printf)("Lock ga %#lx {\n", lk->guestaddr); -+ if (!show_lock_addrdescr -+- || !HG_(get_and_pp_addrdescr) ((Addr) lk->guestaddr)) -++ || !HG_(get_and_pp_addrdescr) (ep, (Addr) lk->guestaddr)) -+ VG_(printf)("\n"); -+ -+ if (sHOW_ADMIN) { -+@@ -4598,7 +4599,7 @@ static Bool is_in_dynamic_linker_shared_ -+ DebugInfo* dinfo; -+ const HChar* soname; -+ -+- dinfo = VG_(find_DebugInfo)( ga ); -++ dinfo = VG_(find_DebugInfo)( VG_(current_DiEpoch)(), ga ); -+ if (!dinfo) return False; -+ -+ soname = VG_(DebugInfo_get_soname)(dinfo); -+@@ -5817,9 +5818,9 @@ static void hg_post_clo_init ( void ) -+ VG_(XTMemory_Full_init)(VG_(XT_filter_1top_and_maybe_below_main)); -+ } -+ -+-static void hg_info_location (Addr a) -++static void hg_info_location (DiEpoch ep, Addr a) -+ { -+- (void) HG_(get_and_pp_addrdescr) (a); -++ (void) HG_(get_and_pp_addrdescr) (ep, a); -+ } -+ -+ static void hg_pre_clo_init ( void ) -+Index: valgrind-3.13.0/helgrind/libhb_core.c -+=================================================================== -+--- valgrind-3.13.0.orig/helgrind/libhb_core.c -++++ valgrind-3.13.0/helgrind/libhb_core.c -+@@ -4095,7 +4095,7 @@ static void note_local_Kw_n_stack_for ( -+ VG_(printf)("LOCAL Kw: thr %p, Kw %llu, ec %p\n", -+ thr, pair.ull, pair.ec ); -+ if (0) -+- VG_(pp_ExeContext)(pair.ec); -++ VG_(pp_ExeContextAndEpoch)(VG_(tag_EC_with_current_epoch)(pair.ec)); -+ } -+ -+ static Int cmp__ULong_n_EC__by_ULong ( const ULong_n_EC* pair1, -+Index: valgrind-3.13.0/include/pub_tool_addrinfo.h -+=================================================================== -+--- valgrind-3.13.0.orig/include/pub_tool_addrinfo.h -++++ valgrind-3.13.0/include/pub_tool_addrinfo.h -+@@ -135,6 +135,7 @@ struct _AddrInfo { -+ // (spoffset will be negative, as stacks are assumed growing down). -+ struct { -+ ThreadInfo tinfo; -++ DiEpoch epoch; -+ Addr IP; -+ Int frameNo; -+ StackPos stackPos; -+@@ -151,9 +152,9 @@ struct _AddrInfo { -+ const HChar* block_desc; // "block","mempool","user-defined",arena -+ SizeT block_szB; -+ PtrdiffT rwoffset; -+- ExeContext* allocated_at; // might be null_ExeContext. -+- ThreadInfo alloc_tinfo; // which thread did alloc this block. -+- ExeContext* freed_at; // might be null_ExeContext. -++ ExeContextAndEpoch allocated_at; // might contain null_ExeContext. -++ ThreadInfo alloc_tinfo; // which thread alloc'd this block. -++ ExeContextAndEpoch freed_at; // might contain null_ExeContext. -+ } Block; -+ -+ // In a global .data symbol. This holds -+@@ -204,7 +205,7 @@ struct _AddrInfo { -+ On entry, ai->tag must be equal to Addr_Undescribed. -+ This might allocate some memory, that can be cleared with -+ VG_(clear_addrinfo). */ -+-extern void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai ); -++extern void VG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai ); -+ -+ extern void VG_(clear_addrinfo) ( AddrInfo* ai); -+ -+Index: valgrind-3.13.0/include/pub_tool_basics.h -+=================================================================== -+--- valgrind-3.13.0.orig/include/pub_tool_basics.h -++++ valgrind-3.13.0/include/pub_tool_basics.h -+@@ -129,6 +129,24 @@ typedef struct { UWord uw1; UWord uw2; -+ /* ThreadIds are simply indices into the VG_(threads)[] array. */ -+ typedef UInt ThreadId; -+ -++ -++/* You need a debuginfo epoch in order to convert an address into any source -++ level entity, since that conversion depends on what objects were mapped -++ in at the time. An epoch is simply a monotonically increasing counter, -++ which we wrap up in a struct so as to enable the C type system to -++ distinguish it from other kinds of numbers. m_debuginfo holds and -++ maintains the current epoch number. */ -++typedef struct { UInt n; } DiEpoch; -++ -++static inline DiEpoch DiEpoch_INVALID ( void ) { -++ DiEpoch dep; dep.n = 0; return dep; -++} -++ -++static inline Bool is_DiEpoch_INVALID ( DiEpoch dep ) { -++ return dep.n == 0; -++} -++ -++ -+ /* Many data structures need to allocate and release memory. -+ The allocation/release functions must be provided by the caller. -+ The Alloc_Fn_t function must allocate a chunk of memory of size szB. -+Index: valgrind-3.13.0/include/pub_tool_debuginfo.h -+=================================================================== -+--- valgrind-3.13.0.orig/include/pub_tool_debuginfo.h -++++ valgrind-3.13.0/include/pub_tool_debuginfo.h -+@@ -31,11 +31,20 @@ -+ #ifndef __PUB_TOOL_DEBUGINFO_H -+ #define __PUB_TOOL_DEBUGINFO_H -+ -+-#include "pub_tool_basics.h" // VG_ macro -++#include "pub_tool_basics.h" // VG_ macro, DiEpoch -+ #include "pub_tool_xarray.h" // XArray -+ -++ -+ /*====================================================================*/ -+-/*=== Obtaining debug information ===*/ -++/*=== Debuginfo epochs. ===*/ -++/*====================================================================*/ -++ -++// This returns the current epoch. -++DiEpoch VG_(current_DiEpoch)(void); -++ -++ -++/*====================================================================*/ -++/*=== Obtaining information pertaining to source artefacts. ===*/ -+ /*====================================================================*/ -+ -+ /* IMPORTANT COMMENT about memory persistence and ownership. -+@@ -76,11 +85,11 @@ -+ demangles C++ function names. VG_(get_fnname_w_offset) is the -+ same, except it appends "+N" to symbol names to indicate offsets. -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership. */ -+-extern Bool VG_(get_filename) ( Addr a, const HChar** filename ); -+-extern Bool VG_(get_fnname) ( Addr a, const HChar** fnname ); -+-extern Bool VG_(get_linenum) ( Addr a, UInt* linenum ); -++extern Bool VG_(get_filename) ( DiEpoch ep, Addr a, const HChar** filename ); -++extern Bool VG_(get_fnname) ( DiEpoch ep, Addr a, const HChar** fnname ); -++extern Bool VG_(get_linenum) ( DiEpoch ep, Addr a, UInt* linenum ); -+ extern Bool VG_(get_fnname_w_offset) -+- ( Addr a, const HChar** fnname ); -++ ( DiEpoch ep, Addr a, const HChar** fnname ); -+ -+ /* This one is the most general. It gives filename, line number and -+ optionally directory name. filename and linenum may not be NULL. -+@@ -95,7 +104,7 @@ extern Bool VG_(get_fnname_w_offset) -+ Returned value indicates whether any filename/line info could be -+ found. */ -+ extern Bool VG_(get_filename_linenum) -+- ( Addr a, -++ ( DiEpoch ep, Addr a, -+ /*OUT*/const HChar** filename, -+ /*OUT*/const HChar** dirname, -+ /*OUT*/UInt* linenum ); -+@@ -108,7 +117,8 @@ extern Bool VG_(get_filename_linenum) -+ of its symbols, this function will not be able to recognise function -+ entry points within it. -+ NOTE: See IMPORTANT COMMENT above about persistence and ownership. */ -+-extern Bool VG_(get_fnname_if_entry) ( Addr a, const HChar** fnname ); -++extern Bool VG_(get_fnname_if_entry) ( DiEpoch ep, Addr a, -++ const HChar** fnname ); -+ -+ typedef -+ enum { -+@@ -121,13 +131,13 @@ typedef -+ extern Vg_FnNameKind VG_(get_fnname_kind) ( const HChar* name ); -+ -+ /* Like VG_(get_fnname_kind), but takes a code address. */ -+-extern Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( Addr ip ); -++extern Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( DiEpoch ep, Addr ip ); -+ -+ /* Looks up data_addr in the collection of data symbols, and if found -+ puts its name (or as much as will fit) into dname[0 .. n_dname-1], -+ which is guaranteed to be zero terminated. Also data_addr's offset -+ from the symbol start is put into *offset. */ -+-extern Bool VG_(get_datasym_and_offset)( Addr data_addr, -++extern Bool VG_(get_datasym_and_offset)( DiEpoch ep, Addr data_addr, -+ /*OUT*/const HChar** dname, -+ /*OUT*/PtrdiffT* offset ); -+ -+@@ -147,14 +157,14 @@ extern Bool VG_(get_datasym_and_offset)( -+ Bool VG_(get_data_description)( -+ /*MOD*/ XArray* /* of HChar */ dname1v, -+ /*MOD*/ XArray* /* of HChar */ dname2v, -+- Addr data_addr -++ DiEpoch ep, Addr data_addr -+ ); -+ -+ /* Succeeds if the address is within a shared object or the main executable. -+ It first searches if Addr a belongs to the text segment of debug info. -+ If not found, it asks the address space manager whether it -+ knows the name of the file associated with this mapping. */ -+-extern Bool VG_(get_objname) ( Addr a, const HChar** objname ); -++extern Bool VG_(get_objname) ( DiEpoch ep, Addr a, const HChar** objname ); -+ -+ -+ /* Cursor allowing to describe inlined function calls at an IP, -+@@ -169,7 +179,7 @@ typedef struct _InlIPCursor InlIPCursor -+ eip can possibly corresponds to inlined function call(s). -+ To describe eip and the inlined function calls, the following must -+ be done: -+- InlIPCursor *iipc = VG_(new_IIPC)(eip); -++ InlIPCursor *iipc = VG_(new_IIPC)(ep, eip); -+ do { -+ buf = VG_(describe_IP)(eip, iipc); -+ ... use buf ... -+@@ -182,12 +192,16 @@ typedef struct _InlIPCursor InlIPCursor -+ Note, that the returned string is allocated in a static buffer local to -+ VG_(describe_IP). That buffer will be overwritten with every invocation. -+ Therefore, callers need to possibly stash away the string. -++ -++ Since this maps a code location to a source artefact (function names), -++ new_IIPC requires a DiEpoch argument (ep) too. -+ */ -+-extern const HChar* VG_(describe_IP)(Addr eip, const InlIPCursor* iipc); -++extern const HChar* VG_(describe_IP)(DiEpoch ep, Addr eip, -++ const InlIPCursor* iipc); -+ -+ /* Builds a IIPC (Inlined IP Cursor) to describe eip and all the inlined calls -+ at eip. Such a cursor must be deleted after use using VG_(delete_IIPC). */ -+-extern InlIPCursor* VG_(new_IIPC)(Addr eip); -++extern InlIPCursor* VG_(new_IIPC)(DiEpoch ep, Addr eip); -+ /* Move the cursor to the next call to describe. -+ Returns True if there are still calls to describe. -+ False if nothing to describe anymore. */ -+@@ -239,7 +253,7 @@ VG_(di_get_global_blocks_from_dihandle) -+ -+ -+ /*====================================================================*/ -+-/*=== Obtaining debug information ===*/ -++/*=== Obtaining information pertaining to shared objects. ===*/ -+ /*====================================================================*/ -+ -+ /* A way to make limited debuginfo queries on a per-mapped-object -+@@ -248,7 +262,7 @@ typedef struct _DebugInfo DebugInfo; -+ -+ /* Returns NULL if the DebugInfo isn't found. It doesn't matter if -+ debug info is present or not. */ -+-DebugInfo* VG_(find_DebugInfo) ( Addr a ); -++DebugInfo* VG_(find_DebugInfo) ( DiEpoch ep, Addr a ); -+ -+ /* Fish bits out of DebugInfos. */ -+ Addr VG_(DebugInfo_get_text_avma) ( const DebugInfo *di ); -+Index: valgrind-3.13.0/include/pub_tool_errormgr.h -+=================================================================== -+--- valgrind-3.13.0.orig/include/pub_tool_errormgr.h -++++ valgrind-3.13.0/include/pub_tool_errormgr.h -+@@ -56,11 +56,11 @@ typedef -+ -+ /* Useful in VG_(tdict).tool_error_matches_suppression(), -+ * VG_(tdict).tool_pp_Error(), etc */ -+-ExeContext* VG_(get_error_where) ( const Error* err ); -+-ErrorKind VG_(get_error_kind) ( const Error* err ); -+-Addr VG_(get_error_address) ( const Error* err ); -+-const HChar* VG_(get_error_string) ( const Error* err ); -+-void* VG_(get_error_extra) ( const Error* err ); -++ExeContextAndEpoch VG_(get_error_where) ( const Error* err ); -++ErrorKind VG_(get_error_kind) ( const Error* err ); -++Addr VG_(get_error_address) ( const Error* err ); -++const HChar* VG_(get_error_string) ( const Error* err ); -++void* VG_(get_error_extra) ( const Error* err ); -+ -+ /* Call this when an error occurs. It will be recorded if it hasn't been -+ seen before. If it has, the existing error record will have its count -+@@ -90,7 +90,7 @@ extern void VG_(maybe_record_error) ( Th -+ whether to add the error in the error total count (another mild hack). */ -+ extern Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, -+ Addr a, const HChar* s, void* extra, -+- ExeContext* where, Bool print_error, -++ ExeContextAndEpoch where, Bool print_error, -+ Bool allow_GDB_attach, Bool count_error ); -+ -+ /* Gets from fd (an opened suppression file) a non-blank, non-comment -+Index: valgrind-3.13.0/include/pub_tool_execontext.h -+=================================================================== -+--- valgrind-3.13.0.orig/include/pub_tool_execontext.h -++++ valgrind-3.13.0/include/pub_tool_execontext.h -+@@ -30,7 +30,13 @@ -+ #ifndef __PUB_TOOL_EXECONTEXT_H -+ #define __PUB_TOOL_EXECONTEXT_H -+ -+-#include "pub_tool_basics.h" // ThreadID -++#include "pub_tool_basics.h" // ThreadID -++#include "pub_tool_debuginfo.h" // DiEpoch -++ -++ -++/*====================================================================*/ -++/*=== ExeContext ===*/ -++/*====================================================================*/ -+ -+ // It's an abstract type. -+ typedef -+@@ -84,9 +90,6 @@ extern void VG_(apply_ExeContext)( void( -+ extern Bool VG_(eq_ExeContext) ( VgRes res, const ExeContext* e1, -+ const ExeContext* e2 ); -+ -+-// Print an ExeContext. -+-extern void VG_(pp_ExeContext) ( ExeContext* ec ); -+- -+ // Get the 32-bit unique reference number for this ExeContext -+ // (the "ExeContext Unique"). Guaranteed to be nonzero and to be a -+ // multiple of four (iow, the lowest two bits are guaranteed to -+@@ -113,10 +116,52 @@ static inline Bool VG_(is_plausible_ECU) -+ // Make an ExeContext containing exactly the specified stack frames. -+ ExeContext* VG_(make_ExeContext_from_StackTrace)( const Addr* ips, UInt n_ips ); -+ -+-// Returns the "null" exe context. The null execontext is an artificial -+-// exe context, with a stack trace made of one Addr (the NULL address). -+-extern -+-ExeContext* VG_(null_ExeContext) (void); -++ -++/*====================================================================*/ -++/*=== ExeContextAndEpoch ===*/ -++/*====================================================================*/ -++ -++/* A plain ExeContext is not generally symbolisable, since we also need to -++ know which DebugInfo epoch it pertains to. ExeContextAndEpoch pairs them -++ up. Note this is just two words, so passing it around by value is -++ fine. */ -++typedef -++ struct { -++ ExeContext* ec; -++ DiEpoch epoch; -++ } -++ ExeContextAndEpoch; -++ -++// A trivial constructor. -++static inline ExeContextAndEpoch mk_ExeContextAndEpoch ( ExeContext* ec, -++ DiEpoch ep ) { -++ ExeContextAndEpoch ece; -++ ece.ec = ec; -++ ece.epoch = ep; -++ return ece; -++} -++ -++// Generates a completely invalid ExeContextAndEpoch, with NULL for .ec and -++// zero for .epoch. Both values are invalid. -++ExeContextAndEpoch VG_(invalid_ExeContextAndEpoch) ( void ); -++ -++// Takes an ExeContext and tags it with the current epoch, which is -++// generally what we want to do. -++ExeContextAndEpoch VG_(tag_EC_with_current_epoch)( ExeContext* ec ); -++ -++// Print an ExeContextAndEpoch. We can't print a plain ExeContext -++// because we can't symbolising it without knowing which debuginfo -++// epoch it pertains to. -++void VG_(pp_ExeContextAndEpoch) ( ExeContextAndEpoch ece ); -++ -++// Returns the "null" exe context tagged with the current debuginfo -++// epoch. The null execontext is an artificial exe context, with a stack -++// trace made of one Addr (the NULL address), and the current epoch. -++ExeContextAndEpoch VG_(null_ExeContextAndEpoch) ( void ); -++ -++// Is this a value obtained from VG_(null_ExeContextAndEpoch) ? -++Bool VG_(is_null_ExeContextAndEpoch)( ExeContextAndEpoch ece ); -++ -+ -+ #endif // __PUB_TOOL_EXECONTEXT_H -+ -+Index: valgrind-3.13.0/include/pub_tool_options.h -+=================================================================== -+--- valgrind-3.13.0.orig/include/pub_tool_options.h -++++ valgrind-3.13.0/include/pub_tool_options.h -+@@ -249,6 +249,12 @@ extern Int VG_(clo_backtrace_size); -+ /* Continue stack traces below main()? Default: NO */ -+ extern Bool VG_(clo_show_below_main); -+ -++/* Keep symbols (and all other debuginfo) for code that is unloaded (dlclose -++ or similar) so that stack traces can still give line/file info for -++ previously captured stack traces. e.g. ... showing where a block was -++ allocated e.g. leaks of or accesses just outside a block. */ -++extern Bool VG_(clo_keep_debuginfo); -++ -+ -+ /* Used to expand file names. "option_name" is the option name, eg. -+ "--log-file". 'format' is what follows, eg. "cachegrind.out.%p". In -+Index: valgrind-3.13.0/include/pub_tool_stacktrace.h -+=================================================================== -+--- valgrind-3.13.0.orig/include/pub_tool_stacktrace.h -++++ valgrind-3.13.0/include/pub_tool_stacktrace.h -+@@ -31,7 +31,7 @@ -+ #ifndef __PUB_TOOL_STACKTRACE_H -+ #define __PUB_TOOL_STACKTRACE_H -+ -+-#include "pub_tool_basics.h" // Addr -++#include "pub_tool_basics.h" // Addr, DiEpoch -+ -+ // The basic stack trace type: just an array of code addresses. -+ typedef Addr* StackTrace; -+@@ -64,19 +64,19 @@ extern UInt VG_(get_StackTrace) ( Thread -+ /*OUT*/StackTrace fps, -+ Word first_ip_delta ); -+ -+-// Apply a function to every element in the StackTrace. The parameter -+-// 'n' gives the index of the passed ip. 'opaque' is an arbitrary -+-// pointer provided to each invocation of 'action' (a poor man's -+-// closure). Doesn't go below main() unless --show-below-main=yes is -+-// set. -++// Apply a function to every element in the StackTrace. The parameter 'n' -++// gives the index of the passed ip. 'opaque' is an arbitrary pointer -++// provided to each invocation of 'action' (a poor man's closure). 'ep' is -++// the debuginfo epoch assumed to apply to all code addresses in the stack -++// trace. Doesn't go below main() unless --show-below-main=yes is set. -+ extern void VG_(apply_StackTrace)( -+- void(*action)(UInt n, Addr ip, void* opaque), -++ void(*action)(UInt n, DiEpoch ep, Addr ip, void* opaque), -+ void* opaque, -+- StackTrace ips, UInt n_ips -++ DiEpoch ep, StackTrace ips, UInt n_ips -+ ); -+ -+ // Print a StackTrace. -+-extern void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips ); -++extern void VG_(pp_StackTrace) ( DiEpoch ep, StackTrace ips, UInt n_ips ); -+ -+ // Gets and immediately prints a StackTrace. Just a bit simpler than -+ // calling VG_(get_StackTrace)() then VG_(pp_StackTrace)(). -+Index: valgrind-3.13.0/include/pub_tool_tooliface.h -+=================================================================== -+--- valgrind-3.13.0.orig/include/pub_tool_tooliface.h -++++ valgrind-3.13.0/include/pub_tool_tooliface.h -+@@ -463,7 +463,7 @@ extern void VG_(needs_print_stats) ( -+ of an address ? */ -+ extern void VG_(needs_info_location) ( -+ // Get and pp information about Addr -+- void (*info_location)(Addr) -++ void (*info_location)(DiEpoch, Addr) -+ ); -+ -+ /* Do we need to see variable type and location information? */ -+Index: valgrind-3.13.0/lackey/lk_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/lackey/lk_main.c -++++ valgrind-3.13.0/lackey/lk_main.c -+@@ -664,6 +664,7 @@ IRSB* lk_instrument ( VgCallbackClosure* -+ Addr iaddr = 0, dst; -+ UInt ilen = 0; -+ Bool condition_inverted = False; -++ DiEpoch ep = VG_(current_DiEpoch)(); -+ -+ if (gWordTy != hWordTy) { -+ /* We don't currently support this case. */ -+@@ -750,7 +751,7 @@ IRSB* lk_instrument ( VgCallbackClosure* -+ tl_assert(clo_fnname); -+ tl_assert(clo_fnname[0]); -+ const HChar *fnname; -+- if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr, -++ if (VG_(get_fnname_if_entry)(ep, st->Ist.IMark.addr, -+ &fnname) -+ && 0 == VG_(strcmp)(fnname, clo_fnname)) { -+ di = unsafeIRDirty_0_N( -+Index: valgrind-3.13.0/massif/ms_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/massif/ms_main.c -++++ valgrind-3.13.0/massif/ms_main.c -+@@ -520,8 +520,9 @@ void filter_IPs (Addr* ips, Int n_ips, -+ // alloc function 'inside' a stacktrace e.g. -+ // 0x1 0x2 0x3 alloc func1 main -+ // becomes 0x1 0x2 0x3 func1 main -++ DiEpoch ep = VG_(current_DiEpoch)(); -+ for (i = *top; i < n_ips; i++) { -+- top_has_fnname = VG_(get_fnname)(ips[*top], &fnname); -++ top_has_fnname = VG_(get_fnname)(ep, ips[*top], &fnname); -+ if (top_has_fnname && VG_(strIsMemberXA)(alloc_fns, fnname)) { -+ VERB(4, "filtering alloc fn %s\n", fnname); -+ (*top)++; -+@@ -576,7 +577,8 @@ static ExeContext* make_ec(ThreadId tid, -+ if (exclude_first_entry && n_ips > 0) { -+ const HChar *fnname; -+ VERB(4, "removing top fn %s from stacktrace\n", -+- VG_(get_fnname)(ips[0], &fnname) ? fnname : "???"); -++ VG_(get_fnname)(VG_(current_DiEpoch)(), ips[0], &fnname) -++ ? fnname : "???"); -+ return VG_(make_ExeContext_from_StackTrace)(ips+1, n_ips-1); -+ } else -+ return VG_(make_ExeContext_from_StackTrace)(ips, n_ips); -+Index: valgrind-3.13.0/memcheck/mc_errors.c -+=================================================================== -+--- valgrind-3.13.0.orig/memcheck/mc_errors.c -++++ valgrind-3.13.0/memcheck/mc_errors.c -+@@ -94,15 +94,15 @@ struct _MC_Error { -+ struct { -+ SizeT szB; // size of value in bytes -+ // Origin info -+- UInt otag; // origin tag -+- ExeContext* origin_ec; // filled in later -++ UInt otag; // origin tag -++ ExeContextAndEpoch origin_ece; // filled in later -+ } Value; -+ -+ // Use of an undefined value in a conditional branch or move. -+ struct { -+ // Origin info -+- UInt otag; // origin tag -+- ExeContext* origin_ec; // filled in later -++ UInt otag; // origin tag -++ ExeContextAndEpoch origin_ece; // filled in later -+ } Cond; -+ -+ // Addressability error in core (signal-handling) operation. -+@@ -127,8 +127,8 @@ struct _MC_Error { -+ // System call register input contains undefined bytes. -+ struct { -+ // Origin info -+- UInt otag; // origin tag -+- ExeContext* origin_ec; // filled in later -++ UInt otag; // origin tag -++ ExeContextAndEpoch origin_ece; // filled in later -+ } RegParam; -+ -+ // System call memory input contains undefined/unaddressable bytes -+@@ -136,8 +136,8 @@ struct _MC_Error { -+ Bool isAddrErr; // Addressability or definedness error? -+ AddrInfo ai; -+ // Origin info -+- UInt otag; // origin tag -+- ExeContext* origin_ec; // filled in later -++ UInt otag; // origin tag -++ ExeContextAndEpoch origin_ece; // filled in later -+ } MemParam; -+ -+ // Problem found from a client request like CHECK_MEM_IS_ADDRESSABLE. -+@@ -145,8 +145,8 @@ struct _MC_Error { -+ Bool isAddrErr; // Addressability or definedness error? -+ AddrInfo ai; -+ // Origin info -+- UInt otag; // origin tag -+- ExeContext* origin_ec; // filled in later -++ UInt otag; // origin tag -++ ExeContextAndEpoch origin_ece; // filled in later -+ } User; -+ -+ // Program tried to free() something that's not a heap block (this -+@@ -279,10 +279,10 @@ static const HChar* pp_Reachedness_for_l -+ } -+ } -+ -+-static void mc_pp_origin ( ExeContext* ec, UInt okind ) -++static void mc_pp_origin ( ExeContextAndEpoch ece, UInt okind ) -+ { -+ const HChar* src = NULL; -+- tl_assert(ec); -++ tl_assert(ece.ec); -+ -+ switch (okind) { -+ case MC_OKIND_STACK: src = " by a stack allocation"; break; -+@@ -295,10 +295,10 @@ static void mc_pp_origin ( ExeContext* e -+ if (VG_(clo_xml)) { -+ emit( " <auxwhat>Uninitialised value was created%s</auxwhat>\n", -+ src); -+- VG_(pp_ExeContext)( ec ); -++ VG_(pp_ExeContextAndEpoch)( ece ); -+ } else { -+ emit( " Uninitialised value was created%s\n", src); -+- VG_(pp_ExeContext)( ec ); -++ VG_(pp_ExeContextAndEpoch)( ece ); -+ } -+ } -+ -+@@ -379,7 +379,7 @@ static void pp_LossRecord(UInt n_this_re -+ emit( " <leakedblocks>%u</leakedblocks>\n", lr->num_blocks); -+ emit( " </xwhat>\n" ); -+ } -+- VG_(pp_ExeContext)(lr->key.allocated_at); -++ VG_(pp_ExeContextAndEpoch)(lr->key.allocated_at); -+ } else { /* ! if (xml) */ -+ if (lr->indirect_szB > 0) { -+ emit( -+@@ -401,7 +401,7 @@ static void pp_LossRecord(UInt n_this_re -+ n_this_record, n_total_records -+ ); -+ } -+- VG_(pp_ExeContext)(lr->key.allocated_at); -++ VG_(pp_ExeContextAndEpoch)(lr->key.allocated_at); -+ } /* if (xml) */ -+ } -+ -+@@ -427,11 +427,11 @@ void MC_(pp_Error) ( const Error* err ) -+ emit( " <kind>CoreMemError</kind>\n" ); -+ emit( " <what>%pS contains unaddressable byte(s)</what>\n", -+ VG_(get_error_string)(err)); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ } else { -+ emit( "%s contains unaddressable byte(s)\n", -+ VG_(get_error_string)(err)); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ } -+ break; -+ -+@@ -441,19 +441,19 @@ void MC_(pp_Error) ( const Error* err ) -+ emit( " <kind>UninitValue</kind>\n" ); -+ emit( " <what>Use of uninitialised value of size %lu</what>\n", -+ extra->Err.Value.szB ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -+- if (extra->Err.Value.origin_ec) -+- mc_pp_origin( extra->Err.Value.origin_ec, -+- extra->Err.Value.otag & 3 ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -++ if (extra->Err.Value.origin_ece.ec) -++ mc_pp_origin( extra->Err.Value.origin_ece, -++ extra->Err.Value.otag & 3 ); -+ } else { -+ /* Could also show extra->Err.Cond.otag if debugging origin -+ tracking */ -+ emit( "Use of uninitialised value of size %lu\n", -+ extra->Err.Value.szB ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -+- if (extra->Err.Value.origin_ec) -+- mc_pp_origin( extra->Err.Value.origin_ec, -+- extra->Err.Value.otag & 3 ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -++ if (extra->Err.Value.origin_ece.ec) -++ mc_pp_origin( extra->Err.Value.origin_ece, -++ extra->Err.Value.otag & 3 ); -+ } -+ break; -+ -+@@ -463,18 +463,18 @@ void MC_(pp_Error) ( const Error* err ) -+ emit( " <kind>UninitCondition</kind>\n" ); -+ emit( " <what>Conditional jump or move depends" -+ " on uninitialised value(s)</what>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -+- if (extra->Err.Cond.origin_ec) -+- mc_pp_origin( extra->Err.Cond.origin_ec, -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -++ if (extra->Err.Cond.origin_ece.ec) -++ mc_pp_origin( extra->Err.Cond.origin_ece, -+ extra->Err.Cond.otag & 3 ); -+ } else { -+ /* Could also show extra->Err.Cond.otag if debugging origin -+ tracking */ -+ emit( "Conditional jump or move depends" -+ " on uninitialised value(s)\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -+- if (extra->Err.Cond.origin_ec) -+- mc_pp_origin( extra->Err.Cond.origin_ec, -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -++ if (extra->Err.Cond.origin_ece.ec) -++ mc_pp_origin( extra->Err.Cond.origin_ece, -+ extra->Err.Cond.otag & 3 ); -+ } -+ break; -+@@ -486,16 +486,16 @@ void MC_(pp_Error) ( const Error* err ) -+ emit( " <what>Syscall param %pS contains " -+ "uninitialised byte(s)</what>\n", -+ VG_(get_error_string)(err) ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -+- if (extra->Err.RegParam.origin_ec) -+- mc_pp_origin( extra->Err.RegParam.origin_ec, -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -++ if (extra->Err.RegParam.origin_ece.ec) -++ mc_pp_origin( extra->Err.RegParam.origin_ece, -+ extra->Err.RegParam.otag & 3 ); -+ } else { -+ emit( "Syscall param %s contains uninitialised byte(s)\n", -+ VG_(get_error_string)(err) ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -+- if (extra->Err.RegParam.origin_ec) -+- mc_pp_origin( extra->Err.RegParam.origin_ec, -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -++ if (extra->Err.RegParam.origin_ece.ec) -++ mc_pp_origin( extra->Err.RegParam.origin_ece, -+ extra->Err.RegParam.otag & 3 ); -+ } -+ break; -+@@ -509,24 +509,24 @@ void MC_(pp_Error) ( const Error* err ) -+ VG_(get_error_string)(err), -+ extra->Err.MemParam.isAddrErr -+ ? "unaddressable" : "uninitialised" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), -+ &extra->Err.MemParam.ai, False); -+- if (extra->Err.MemParam.origin_ec -++ if (extra->Err.MemParam.origin_ece.ec -+ && !extra->Err.MemParam.isAddrErr) -+- mc_pp_origin( extra->Err.MemParam.origin_ec, -++ mc_pp_origin( extra->Err.MemParam.origin_ece, -+ extra->Err.MemParam.otag & 3 ); -+ } else { -+ emit( "Syscall param %s points to %s byte(s)\n", -+ VG_(get_error_string)(err), -+ extra->Err.MemParam.isAddrErr -+ ? "unaddressable" : "uninitialised" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), -+ &extra->Err.MemParam.ai, False); -+- if (extra->Err.MemParam.origin_ec -++ if (extra->Err.MemParam.origin_ece.ec -+ && !extra->Err.MemParam.isAddrErr) -+- mc_pp_origin( extra->Err.MemParam.origin_ec, -++ mc_pp_origin( extra->Err.MemParam.origin_ece, -+ extra->Err.MemParam.otag & 3 ); -+ } -+ break; -+@@ -540,21 +540,21 @@ void MC_(pp_Error) ( const Error* err ) -+ "during client check request</what>\n", -+ extra->Err.User.isAddrErr -+ ? "Unaddressable" : "Uninitialised" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), &extra->Err.User.ai, -+ False); -+- if (extra->Err.User.origin_ec && !extra->Err.User.isAddrErr) -+- mc_pp_origin( extra->Err.User.origin_ec, -++ if (extra->Err.User.origin_ece.ec && !extra->Err.User.isAddrErr) -++ mc_pp_origin( extra->Err.User.origin_ece, -+ extra->Err.User.otag & 3 ); -+ } else { -+ emit( "%s byte(s) found during client check request\n", -+ extra->Err.User.isAddrErr -+ ? "Unaddressable" : "Uninitialised" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), &extra->Err.User.ai, -+ False); -+- if (extra->Err.User.origin_ec && !extra->Err.User.isAddrErr) -+- mc_pp_origin( extra->Err.User.origin_ec, -++ if (extra->Err.User.origin_ece.ec && !extra->Err.User.isAddrErr) -++ mc_pp_origin( extra->Err.User.origin_ece, -+ extra->Err.User.otag & 3 ); -+ } -+ break; -+@@ -564,12 +564,12 @@ void MC_(pp_Error) ( const Error* err ) -+ emit( " <kind>InvalidFree</kind>\n" ); -+ emit( " <what>Invalid free() / delete / delete[]" -+ " / realloc()</what>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), -+ &extra->Err.Free.ai, False ); -+ } else { -+ emit( "Invalid free() / delete / delete[] / realloc()\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), -+ &extra->Err.Free.ai, False ); -+ } -+@@ -579,12 +579,12 @@ void MC_(pp_Error) ( const Error* err ) -+ if (xml) { -+ emit( " <kind>MismatchedFree</kind>\n" ); -+ emit( " <what>Mismatched free() / delete / delete []</what>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), -+ &extra->Err.FreeMismatch.ai, False); -+ } else { -+ emit( "Mismatched free() / delete / delete []\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), -+ &extra->Err.FreeMismatch.ai, False); -+ } -+@@ -597,7 +597,7 @@ void MC_(pp_Error) ( const Error* err ) -+ emit( " <what>Invalid %s of size %lu</what>\n", -+ extra->Err.Addr.isWrite ? "write" : "read", -+ extra->Err.Addr.szB ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), -+ &extra->Err.Addr.ai, -+ extra->Err.Addr.maybe_gcc ); -+@@ -605,7 +605,7 @@ void MC_(pp_Error) ( const Error* err ) -+ emit( "Invalid %s of size %lu\n", -+ extra->Err.Addr.isWrite ? "write" : "read", -+ extra->Err.Addr.szB ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ -+ VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), -+ &extra->Err.Addr.ai, -+@@ -618,12 +618,12 @@ void MC_(pp_Error) ( const Error* err ) -+ emit( " <kind>InvalidJump</kind>\n" ); -+ emit( " <what>Jump to the invalid address stated " -+ "on the next line</what>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), &extra->Err.Jump.ai, -+ False ); -+ } else { -+ emit( "Jump to the invalid address stated on the next line\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), &extra->Err.Jump.ai, -+ False ); -+ } -+@@ -644,7 +644,7 @@ void MC_(pp_Error) ( const Error* err ) -+ extra->Err.Overlap.dst, extra->Err.Overlap.src, -+ extra->Err.Overlap.szB ); -+ } -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ } else { -+ if (extra->Err.Overlap.szB == 0) { -+ emit( "Source and destination overlap in %s(%#lx, %#lx)\n", -+@@ -656,7 +656,7 @@ void MC_(pp_Error) ( const Error* err ) -+ extra->Err.Overlap.dst, extra->Err.Overlap.src, -+ extra->Err.Overlap.szB ); -+ } -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ } -+ break; -+ -+@@ -666,12 +666,12 @@ void MC_(pp_Error) ( const Error* err ) -+ if (xml) { -+ emit( " <kind>InvalidMemPool</kind>\n" ); -+ emit( " <what>Illegal memory pool address</what>\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), -+ &extra->Err.IllegalMempool.ai, False ); -+ } else { -+ emit( "Illegal memory pool address\n" ); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), -+ &extra->Err.IllegalMempool.ai, False ); -+ } -+@@ -695,14 +695,14 @@ void MC_(pp_Error) ( const Error* err ) -+ extra->Err.FishyValue.function_name, -+ (SSizeT)extra->Err.FishyValue.value); -+ emit( "</what>"); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ } else { -+ emit( "Argument '%s' of function %s has a fishy " -+ "(possibly negative) value: %ld\n", -+ extra->Err.FishyValue.argument_name, -+ extra->Err.FishyValue.function_name, -+ (SSizeT)extra->Err.FishyValue.value); -+- VG_(pp_ExeContext)( VG_(get_error_where)(err) ); -++ VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) ); -+ } -+ break; -+ -+@@ -773,9 +773,10 @@ void MC_(record_value_error) ( ThreadId -+ tl_assert( MC_(clo_mc_level) >= 2 ); -+ if (otag > 0) -+ tl_assert( MC_(clo_mc_level) == 3 ); -+- extra.Err.Value.szB = szB; -+- extra.Err.Value.otag = otag; -+- extra.Err.Value.origin_ec = NULL; /* Filled in later */ -++ extra.Err.Value.szB = szB; -++ extra.Err.Value.otag = otag; -++ extra.Err.Value.origin_ece = VG_(invalid_ExeContextAndEpoch)(); -++ /* Filled in later */ -+ VG_(maybe_record_error)( tid, Err_Value, /*addr*/0, /*s*/NULL, &extra ); -+ } -+ -+@@ -785,8 +786,9 @@ void MC_(record_cond_error) ( ThreadId t -+ tl_assert( MC_(clo_mc_level) >= 2 ); -+ if (otag > 0) -+ tl_assert( MC_(clo_mc_level) == 3 ); -+- extra.Err.Cond.otag = otag; -+- extra.Err.Cond.origin_ec = NULL; /* Filled in later */ -++ extra.Err.Cond.otag = otag; -++ extra.Err.Cond.origin_ece = VG_(invalid_ExeContextAndEpoch)(); -++ /* Filled in later */ -+ VG_(maybe_record_error)( tid, Err_Cond, /*addr*/0, /*s*/NULL, &extra ); -+ } -+ -+@@ -804,8 +806,9 @@ void MC_(record_regparam_error) ( Thread -+ tl_assert(VG_INVALID_THREADID != tid); -+ if (otag > 0) -+ tl_assert( MC_(clo_mc_level) == 3 ); -+- extra.Err.RegParam.otag = otag; -+- extra.Err.RegParam.origin_ec = NULL; /* Filled in later */ -++ extra.Err.RegParam.otag = otag; -++ extra.Err.RegParam.origin_ece = VG_(invalid_ExeContextAndEpoch)(); -++ /* Filled in later */ -+ VG_(maybe_record_error)( tid, Err_RegParam, /*addr*/0, msg, &extra ); -+ } -+ -+@@ -820,10 +823,11 @@ void MC_(record_memparam_error) ( Thread -+ tl_assert( MC_(clo_mc_level) == 3 ); -+ tl_assert( !isAddrErr ); -+ } -+- extra.Err.MemParam.isAddrErr = isAddrErr; -+- extra.Err.MemParam.ai.tag = Addr_Undescribed; -+- extra.Err.MemParam.otag = otag; -+- extra.Err.MemParam.origin_ec = NULL; /* Filled in later */ -++ extra.Err.MemParam.isAddrErr = isAddrErr; -++ extra.Err.MemParam.ai.tag = Addr_Undescribed; -++ extra.Err.MemParam.otag = otag; -++ extra.Err.MemParam.origin_ece = VG_(invalid_ExeContextAndEpoch)(); -++ /* Filled in later */ -+ VG_(maybe_record_error)( tid, Err_MemParam, a, msg, &extra ); -+ } -+ -+@@ -925,10 +929,11 @@ void MC_(record_user_error) ( ThreadId t -+ tl_assert( MC_(clo_mc_level) >= 2 ); -+ } -+ tl_assert(VG_INVALID_THREADID != tid); -+- extra.Err.User.isAddrErr = isAddrErr; -+- extra.Err.User.ai.tag = Addr_Undescribed; -+- extra.Err.User.otag = otag; -+- extra.Err.User.origin_ec = NULL; /* Filled in later */ -++ extra.Err.User.isAddrErr = isAddrErr; -++ extra.Err.User.ai.tag = Addr_Undescribed; -++ extra.Err.User.otag = otag; -++ extra.Err.User.origin_ece = VG_(invalid_ExeContextAndEpoch)(); -++ /* Filled in later */ -+ VG_(maybe_record_error)( tid, Err_User, a, /*s*/NULL, &extra ); -+ } -+ -+@@ -1053,7 +1058,7 @@ static Bool mempool_block_maybe_describe -+ -+ /* Describe an address as best you can, for error messages, -+ putting the result in ai. */ -+-static void describe_addr ( Addr a, /*OUT*/AddrInfo* ai ) -++static void describe_addr ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai ) -+ { -+ MC_Chunk* mc; -+ -+@@ -1121,28 +1126,30 @@ static void describe_addr ( Addr a, /*OU -+ } -+ -+ /* No block found. Search a non-heap block description. */ -+- VG_(describe_addr) (a, ai); -++ VG_(describe_addr) (ep, a, ai); -+ } -+ -+-void MC_(pp_describe_addr) ( Addr a ) -++void MC_(pp_describe_addr) ( DiEpoch ep, Addr a ) -+ { -+ AddrInfo ai; -+ -+ ai.tag = Addr_Undescribed; -+- describe_addr (a, &ai); -++ describe_addr (ep, a, &ai); -+ VG_(pp_addrinfo_mc) (a, &ai, /* maybe_gcc */ False); -+ VG_(clear_addrinfo) (&ai); -+ } -+ -+-/* Fill in *origin_ec as specified by otag, or NULL it out if otag -++/* Fill in *origin_ece as specified by otag, or NULL it out if otag -+ does not refer to a known origin. */ -+-static void update_origin ( /*OUT*/ExeContext** origin_ec, -++static void update_origin ( /*OUT*/ExeContextAndEpoch* origin_ece, -+ UInt otag ) -+ { -+ UInt ecu = otag & ~3; -+- *origin_ec = NULL; -+ if (VG_(is_plausible_ECU)(ecu)) { -+- *origin_ec = VG_(get_ExeContext_from_ECU)( ecu ); -++ *origin_ece -++ = VG_(tag_EC_with_current_epoch)(VG_(get_ExeContext_from_ECU)( ecu )); -++ } else { -++ *origin_ece = VG_(invalid_ExeContextAndEpoch)(); -+ } -+ } -+ -+@@ -1150,6 +1157,7 @@ static void update_origin ( /*OUT*/ExeCo -+ UInt MC_(update_Error_extra)( const Error* err ) -+ { -+ MC_Error* extra = VG_(get_error_extra)(err); -++ DiEpoch ep = VG_(get_error_where)(err).epoch; -+ -+ switch (VG_(get_error_kind)(err)) { -+ // These ones don't have addresses associated with them, and so don't -+@@ -1169,45 +1177,45 @@ UInt MC_(update_Error_extra)( const Erro -+ // origin tag. Note that it is a kludge to assume that -+ // a length-1 trace indicates a stack origin. FIXME. -+ case Err_Value: -+- update_origin( &extra->Err.Value.origin_ec, -++ update_origin( &extra->Err.Value.origin_ece, -+ extra->Err.Value.otag ); -+ return sizeof(MC_Error); -+ case Err_Cond: -+- update_origin( &extra->Err.Cond.origin_ec, -++ update_origin( &extra->Err.Cond.origin_ece, -+ extra->Err.Cond.otag ); -+ return sizeof(MC_Error); -+ case Err_RegParam: -+- update_origin( &extra->Err.RegParam.origin_ec, -++ update_origin( &extra->Err.RegParam.origin_ece, -+ extra->Err.RegParam.otag ); -+ return sizeof(MC_Error); -+ -+ // These ones always involve a memory address. -+ case Err_Addr: -+- describe_addr ( VG_(get_error_address)(err), -++ describe_addr ( ep, VG_(get_error_address)(err), -+ &extra->Err.Addr.ai ); -+ return sizeof(MC_Error); -+ case Err_MemParam: -+- describe_addr ( VG_(get_error_address)(err), -++ describe_addr ( ep, VG_(get_error_address)(err), -+ &extra->Err.MemParam.ai ); -+- update_origin( &extra->Err.MemParam.origin_ec, -++ update_origin( &extra->Err.MemParam.origin_ece, -+ extra->Err.MemParam.otag ); -+ return sizeof(MC_Error); -+ case Err_Jump: -+- describe_addr ( VG_(get_error_address)(err), -++ describe_addr ( ep, VG_(get_error_address)(err), -+ &extra->Err.Jump.ai ); -+ return sizeof(MC_Error); -+ case Err_User: -+- describe_addr ( VG_(get_error_address)(err), -++ describe_addr ( ep, VG_(get_error_address)(err), -+ &extra->Err.User.ai ); -+- update_origin( &extra->Err.User.origin_ec, -++ update_origin( &extra->Err.User.origin_ece, -+ extra->Err.User.otag ); -+ return sizeof(MC_Error); -+ case Err_Free: -+- describe_addr ( VG_(get_error_address)(err), -++ describe_addr ( ep, VG_(get_error_address)(err), -+ &extra->Err.Free.ai ); -+ return sizeof(MC_Error); -+ case Err_IllegalMempool: -+- describe_addr ( VG_(get_error_address)(err), -++ describe_addr ( ep, VG_(get_error_address)(err), -+ &extra->Err.IllegalMempool.ai ); -+ return sizeof(MC_Error); -+ -+@@ -1252,7 +1260,7 @@ static Bool client_block_maybe_describe( -+ ai->Addr.Block.rwoffset = (Word)(a) - (Word)(cgbs[i].start); -+ ai->Addr.Block.allocated_at = cgbs[i].where; -+ VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo); -+- ai->Addr.Block.freed_at = VG_(null_ExeContext)();; -++ ai->Addr.Block.freed_at = VG_(null_ExeContextAndEpoch)(); -+ return True; -+ } -+ } -+Index: valgrind-3.13.0/memcheck/mc_include.h -+=================================================================== -+--- valgrind-3.13.0.orig/memcheck/mc_include.h -++++ valgrind-3.13.0/memcheck/mc_include.h -+@@ -67,17 +67,17 @@ typedef -+ Addr data; // Address of the actual block. -+ SizeT szB : (sizeof(SizeT)*8)-2; // Size requested; 30 or 62 bits. -+ MC_AllocKind allockind : 2; // Which operation did the allocation. -+- ExeContext* where[0]; -++ ExeContextAndEpoch where[0]; -+ /* Variable-length array. The size depends on MC_(clo_keep_stacktraces). -+ This array optionally stores the alloc and/or free stack trace. */ -+ } -+ MC_Chunk; -+ -+-/* Returns the execontext where the MC_Chunk was allocated/freed. -++/* Returns the execontext and epoch where the MC_Chunk was allocated/freed. -+ Returns VG_(null_ExeContext)() if the execontext has not been recorded (due -+ to MC_(clo_keep_stacktraces) and/or because block not yet freed). */ -+-ExeContext* MC_(allocated_at) (MC_Chunk*); -+-ExeContext* MC_(freed_at) (MC_Chunk*); -++ExeContextAndEpoch MC_(allocated_at) (MC_Chunk*); -++ExeContextAndEpoch MC_(freed_at) (MC_Chunk*); -+ -+ /* Records and sets execontext according to MC_(clo_keep_stacktraces) */ -+ void MC_(set_allocated_at) (ThreadId, MC_Chunk*); -+@@ -432,8 +432,8 @@ typedef -+ /* When a LossRecord is put into an OSet, these elements represent the key. */ -+ typedef -+ struct _LossRecordKey { -+- Reachedness state; // LC_Extra.state value shared by all blocks. -+- ExeContext* allocated_at; // Where they were allocated. -++ Reachedness state; // LC_Extra.state value shared by all blocks. -++ ExeContextAndEpoch allocated_at; // Where they were allocated. -+ } -+ LossRecordKey; -+ -+@@ -569,8 +569,8 @@ Bool MC_(record_fishy_value_error) ( Th -+ /* Leak kinds tokens to call VG_(parse_enum_set). */ -+ extern const HChar* MC_(parse_leak_kinds_tokens); -+ -+-/* prints a description of address a */ -+-void MC_(pp_describe_addr) (Addr a); -++/* prints a description of address a in the specified debuginfo epoch */ -++void MC_(pp_describe_addr) ( DiEpoch ep, Addr a ); -+ -+ /* Is this address in a user-specified "ignored range" ? */ -+ Bool MC_(in_ignored_range) ( Addr a ); -+@@ -588,10 +588,10 @@ Bool MC_(in_ignored_range_below_sp) ( Ad -+ start == size == 0. */ -+ typedef -+ struct { -+- Addr start; -+- SizeT size; -+- ExeContext* where; -+- HChar* desc; -++ Addr start; -++ SizeT size; -++ ExeContextAndEpoch where; -++ HChar* desc; -+ } -+ CGenBlock; -+ -+Index: valgrind-3.13.0/memcheck/mc_leakcheck.c -+=================================================================== -+--- valgrind-3.13.0.orig/memcheck/mc_leakcheck.c -++++ valgrind-3.13.0/memcheck/mc_leakcheck.c -+@@ -1060,6 +1060,8 @@ lc_scan_memory(Addr start, SizeT len, Bo -+ const Addr end = VG_ROUNDDN(start+len, sizeof(Addr)); -+ fault_catcher_t prev_catcher; -+ -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ if (VG_DEBUG_LEAKCHECK) -+ VG_(printf)("scan %#lx-%#lx (%lu)\n", start, end, len); -+ -+@@ -1139,14 +1141,14 @@ lc_scan_memory(Addr start, SizeT len, Bo -+ if (addr >= searched && addr < searched + szB) { -+ if (addr == searched) { -+ VG_(umsg)("*%#lx points at %#lx\n", ptr, searched); -+- MC_(pp_describe_addr) (ptr); -++ MC_(pp_describe_addr) (ep, ptr); // FIXME JRS: ep correct? -+ } else { -+ Int ch_no; -+ MC_Chunk *ch; -+ LC_Extra *ex; -+ VG_(umsg)("*%#lx interior points at %lu bytes inside %#lx\n", -+ ptr, (long unsigned) addr - searched, searched); -+- MC_(pp_describe_addr) (ptr); -++ MC_(pp_describe_addr) (ep, ptr); // FIXME JRS: ep correct? -+ if (lc_is_a_chunk_ptr(addr, &ch_no, &ch, &ex) ) { -+ Int h; -+ for (h = LchStdString; h < N_LEAK_CHECK_HEURISTICS; h++) { -+@@ -1203,13 +1205,17 @@ static Word cmp_LossRecordKey_LossRecord -+ // Compare on states first because that's fast. -+ if (a->state < b->state) return -1; -+ if (a->state > b->state) return 1; -+- // Ok, the states are equal. Now compare the locations, which is slower. -++ // Also on epochs, for the same reason. -++ if (a->allocated_at.epoch.n < b->allocated_at.epoch.n) return -1; -++ if (a->allocated_at.epoch.n > b->allocated_at.epoch.n) return 1; -++ // Ok, the states and epochs are equal. Now compare the locations, which -++ // is slower. -+ if (VG_(eq_ExeContext)( -+- MC_(clo_leak_resolution), a->allocated_at, b->allocated_at)) -++ MC_(clo_leak_resolution), a->allocated_at.ec, b->allocated_at.ec)) -+ return 0; -+ // Different locations. Ordering is arbitrary, just use the ec pointer. -+- if (a->allocated_at < b->allocated_at) return -1; -+- if (a->allocated_at > b->allocated_at) return 1; -++ if (a->allocated_at.ec < b->allocated_at.ec) return -1; -++ if (a->allocated_at.ec > b->allocated_at.ec) return 1; -+ VG_(tool_panic)("bad LossRecord comparison"); -+ } -+ -+@@ -1231,10 +1237,15 @@ static Int cmp_LossRecords(const void* v -+ // possible. So: compare num_blocks. -+ if (lr_a->num_blocks < lr_b->num_blocks) return -1; -+ if (lr_a->num_blocks > lr_b->num_blocks) return 1; -++ // Then epochs. -++ if (lr_a->key.allocated_at.epoch.n < lr_b->key.allocated_at.epoch.n) -++ return -1; -++ if (lr_a->key.allocated_at.epoch.n > lr_b->key.allocated_at.epoch.n) -++ return 1; -+ // Finally, compare ExeContext addresses... older ones are likely to have -+ // lower addresses. -+- if (lr_a->key.allocated_at < lr_b->key.allocated_at) return -1; -+- if (lr_a->key.allocated_at > lr_b->key.allocated_at) return 1; -++ if (lr_a->key.allocated_at.ec < lr_b->key.allocated_at.ec) return -1; -++ if (lr_a->key.allocated_at.ec > lr_b->key.allocated_at.ec) return 1; -+ return 0; -+ } -+ -+@@ -1381,7 +1392,7 @@ static void XT_insert_lr (LossRecord* lr -+ xtl.xt_lr[i].vid[XT_Decrease].num_blocks -+ = lr->old_num_blocks - lr->num_blocks; -+ -+- VG_(XT_add_to_ec)(leak_xt, lr->key.allocated_at, &xtl); -++ VG_(XT_add_to_ec)(leak_xt, lr->key.allocated_at.ec, &xtl); -+ } -+ -+ static void MC_(XT_Leak_sub) (void* from, const void* xtleak) -+@@ -2133,9 +2144,9 @@ void MC_(detect_memory_leaks) ( ThreadId -+ VG_(umsg)("Block 0x%lx..0x%lx overlaps with block 0x%lx..0x%lx\n", -+ start1, end1, start2, end2); -+ VG_(umsg)("Blocks allocation contexts:\n"), -+- VG_(pp_ExeContext)( MC_(allocated_at)(ch1)); -++ VG_(pp_ExeContextAndEpoch)( MC_(allocated_at)(ch1)); -+ VG_(umsg)("\n"), -+- VG_(pp_ExeContext)( MC_(allocated_at)(ch2)); -++ VG_(pp_ExeContextAndEpoch)( MC_(allocated_at)(ch2)); -+ VG_(umsg)("This is usually caused by using "); -+ VG_(umsg)("VALGRIND_MALLOCLIKE_BLOCK in an inappropriate way.\n"); -+ tl_assert (0); -+Index: valgrind-3.13.0/memcheck/mc_main.c -+=================================================================== -+--- valgrind-3.13.0.orig/memcheck/mc_main.c -++++ valgrind-3.13.0/memcheck/mc_main.c -+@@ -6719,9 +6719,11 @@ static Bool handle_gdb_monitor_command ( -+ const HChar* src; -+ UInt otag; -+ UInt ecu; -+- ExeContext* origin_ec; -++ ExeContextAndEpoch origin_ece; -+ MC_ReadResult res; -+ -++ const DiEpoch ep = VG_(current_DiEpoch)(); -++ -+ Int kwdid = VG_(keyword_id) -+ ("addressable defined", -+ VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all); -+@@ -6738,7 +6740,8 @@ static Bool handle_gdb_monitor_command ( -+ VG_(printf) -+ ("Address %p len %lu not addressable:\nbad address %p\n", -+ (void *)address, szB, (void *) bad_addr); -+- MC_(pp_describe_addr) (address); -++ // FIXME JRS epoch ok? -++ MC_(pp_describe_addr) (ep, address); -+ break; -+ case 1: /* defined */ -+ res = is_mem_defined ( address, szB, &bad_addr, &otag ); -+@@ -6765,14 +6768,16 @@ static Bool handle_gdb_monitor_command ( -+ (void *)address, szB, (void *) bad_addr, src); -+ ecu = otag & ~3; -+ if (VG_(is_plausible_ECU)(ecu)) { -+- origin_ec = VG_(get_ExeContext_from_ECU)( ecu ); -+- VG_(pp_ExeContext)( origin_ec ); -++ origin_ece = VG_(tag_EC_with_current_epoch)( -++ VG_(get_ExeContext_from_ECU)( ecu )); -++ VG_(pp_ExeContextAndEpoch)( origin_ece ); -+ } -+ } -+ else -+ VG_(printf) ("Address %p len %lu defined\n", -+ (void *)address, szB); -+- MC_(pp_describe_addr) (address); -++ // FIXME JRS epoch ok? -++ MC_(pp_describe_addr) (ep, address); -+ break; -+ default: tl_assert(0); -+ } -+@@ -7049,7 +7054,9 @@ static Bool mc_handle_client_request ( T -+ cgbs[i].start = arg[1]; -+ cgbs[i].size = arg[2]; -+ cgbs[i].desc = VG_(strdup)("mc.mhcr.1", (HChar *)arg[3]); -+- cgbs[i].where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ ); -++ cgbs[i].where = VG_(tag_EC_with_current_epoch)( -++ VG_(record_ExeContext) ( tid, -++ 0/*first_ip_delta*/ )); -+ *ret = i; -+ } else -+ *ret = -1; -+@@ -7917,7 +7924,7 @@ static void mc_post_clo_init ( void ) -+ } -+ -+ MC_(chunk_poolalloc) = VG_(newPA) -+- (sizeof(MC_Chunk) + MC_(n_where_pointers)() * sizeof(ExeContext*), -++ (sizeof(MC_Chunk) + MC_(n_where_pointers)() * sizeof(ExeContextAndEpoch), -+ 1000, -+ VG_(malloc), -+ "mc.cMC.1 (MC_Chunk pools)", -+Index: valgrind-3.13.0/memcheck/mc_malloc_wrappers.c -+=================================================================== -+--- valgrind-3.13.0.orig/memcheck/mc_malloc_wrappers.c -++++ valgrind-3.13.0/memcheck/mc_malloc_wrappers.c -+@@ -199,8 +199,8 @@ MC_Chunk* create_MC_Chunk ( ThreadId tid -+ mc->szB = szB; -+ mc->allockind = kind; -+ switch ( MC_(n_where_pointers)() ) { -+- case 2: mc->where[1] = 0; // fallback to 1 -+- case 1: mc->where[0] = 0; // fallback to 0 -++ case 2: mc->where[1] = VG_(invalid_ExeContextAndEpoch)(); // fall thru -++ case 1: mc->where[0] = VG_(invalid_ExeContextAndEpoch)(); // fall thru -+ case 0: break; -+ default: tl_assert(0); -+ } -+@@ -268,30 +268,34 @@ static Bool live_block (MC_Chunk* mc) -+ return in_block_list ( MC_(malloc_list), mc ); -+ } -+ -+-ExeContext* MC_(allocated_at) (MC_Chunk* mc) -++ExeContextAndEpoch MC_(allocated_at) (MC_Chunk* mc) -+ { -+ switch (MC_(clo_keep_stacktraces)) { -+- case KS_none: return VG_(null_ExeContext) (); -++ case KS_none: return VG_(null_ExeContextAndEpoch) (); -+ case KS_alloc: return mc->where[0]; -+- case KS_free: return VG_(null_ExeContext) (); -+- case KS_alloc_then_free: return (live_block(mc) ? -+- mc->where[0] : VG_(null_ExeContext) ()); -++ case KS_free: return VG_(null_ExeContextAndEpoch) (); -++ case KS_alloc_then_free: return live_block(mc) -++ ? mc->where[0] -++ : VG_(null_ExeContextAndEpoch) (); -+ case KS_alloc_and_free: return mc->where[0]; -+ default: tl_assert (0); -+ } -+ } -+ -+-ExeContext* MC_(freed_at) (MC_Chunk* mc) -++ExeContextAndEpoch MC_(freed_at) (MC_Chunk* mc) -+ { -+ switch (MC_(clo_keep_stacktraces)) { -+- case KS_none: return VG_(null_ExeContext) (); -+- case KS_alloc: return VG_(null_ExeContext) (); -+- case KS_free: return (mc->where[0] ? -+- mc->where[0] : VG_(null_ExeContext) ()); -+- case KS_alloc_then_free: return (live_block(mc) ? -+- VG_(null_ExeContext) () : mc->where[0]); -+- case KS_alloc_and_free: return (mc->where[1] ? -+- mc->where[1] : VG_(null_ExeContext) ()); -++ case KS_none: return VG_(null_ExeContextAndEpoch) (); -++ case KS_alloc: return VG_(null_ExeContextAndEpoch) (); -++ case KS_free: return mc->where[0].ec -++ ? mc->where[0] -++ : VG_(null_ExeContextAndEpoch) (); -++ case KS_alloc_then_free: return live_block(mc) -++ ? VG_(null_ExeContextAndEpoch) () -++ : mc->where[0]; -++ case KS_alloc_and_free: return mc->where[1].ec -++ ? mc->where[1] -++ : VG_(null_ExeContextAndEpoch) (); -+ default: tl_assert (0); -+ } -+ } -+@@ -306,15 +310,16 @@ void MC_(set_allocated_at) (ThreadId ti -+ case KS_alloc_and_free: break; -+ default: tl_assert (0); -+ } -+- mc->where[0] = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ ); -++ mc->where[0] = VG_(tag_EC_with_current_epoch)( -++ VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ )); -+ if (UNLIKELY(VG_(clo_xtree_memory) == Vg_XTMemory_Full)) -+- VG_(XTMemory_Full_alloc)(mc->szB, mc->where[0]); -++ VG_(XTMemory_Full_alloc)(mc->szB, mc->where[0].ec); -+ } -+ -+ void MC_(set_freed_at) (ThreadId tid, MC_Chunk* mc) -+ { -+ Int pos; -+- ExeContext* ec_free; -++ ExeContextAndEpoch ec_free; -+ -+ switch (MC_(clo_keep_stacktraces)) { -+ case KS_none: return; -+@@ -333,9 +338,10 @@ void MC_(set_freed_at) (ThreadId tid, M -+ Note: we are guaranteed to find the ec_alloc in mc->where[0], as -+ mc_post_clo_init verifies the consistency of --xtree-memory and -+ --keep-stacktraces. */ -+- ec_free = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ ); -++ ec_free = VG_(tag_EC_with_current_epoch)( -++ VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ )); -+ if (UNLIKELY(VG_(clo_xtree_memory) == Vg_XTMemory_Full)) -+- VG_(XTMemory_Full_free)(mc->szB, mc->where[0], ec_free); -++ VG_(XTMemory_Full_free)(mc->szB, mc->where[0].ec, ec_free.ec); -+ if (LIKELY(pos >= 0)) -+ mc->where[pos] = ec_free; -+ } -+@@ -391,7 +397,7 @@ void* MC_(new_block) ( ThreadId tid, -+ if (is_zeroed) -+ MC_(make_mem_defined)( p, szB ); -+ else { -+- UInt ecu = VG_(get_ECU_from_ExeContext)(MC_(allocated_at)(mc)); -++ UInt ecu = VG_(get_ECU_from_ExeContext)(MC_(allocated_at)(mc).ec); -+ tl_assert(VG_(is_plausible_ECU)(ecu)); -+ MC_(make_mem_undefined_w_otag)( p, szB, ecu | MC_OKIND_HEAP ); -+ } -+@@ -605,7 +611,7 @@ void* MC_(realloc) ( ThreadId tid, void* -+ // If the block has grown, we mark the grown area as undefined. -+ // We have to do that after VG_(HT_add_node) to ensure the ecu -+ // execontext is for a fully allocated block. -+- ecu = VG_(get_ECU_from_ExeContext)(MC_(allocated_at)(new_mc)); -++ ecu = VG_(get_ECU_from_ExeContext)(MC_(allocated_at)(new_mc).ec); -+ tl_assert(VG_(is_plausible_ECU)(ecu)); -+ MC_(make_mem_undefined_w_otag)( a_new+old_szB, -+ new_szB-old_szB, -+@@ -673,7 +679,7 @@ void MC_(handle_resizeInPlace)(ThreadId -+ return; -+ -+ if (UNLIKELY(VG_(clo_xtree_memory) == Vg_XTMemory_Full)) -+- VG_(XTMemory_Full_resize_in_place)(oldSizeB, newSizeB, mc->where[0]); -++ VG_(XTMemory_Full_resize_in_place)(oldSizeB, newSizeB, mc->where[0].ec); -+ -+ mc->szB = newSizeB; -+ if (newSizeB < oldSizeB) { -+@@ -887,7 +893,7 @@ check_mempool_sane(MC_Mempool* mp) -+ chunks[i]->data, -+ chunks[i]->data + chunks[i]->szB); -+ -+- VG_(pp_ExeContext)(MC_(allocated_at)(chunks[i])); -++ VG_(pp_ExeContextAndEpoch)(MC_(allocated_at)(chunks[i])); -+ } -+ } -+ VG_(free)(chunks); -+@@ -1147,7 +1153,7 @@ static void xtmemory_report_next_block(X -+ if (mc) { -+ xta->nbytes = mc->szB; -+ xta->nblocks = 1; -+- *ec_alloc = MC_(allocated_at)(mc); -++ *ec_alloc = MC_(allocated_at)(mc).ec; -+ } else -+ xta->nblocks = 0; -+ } -+Index: valgrind-3.13.0/memcheck/tests/linux/Makefile.am -+=================================================================== -+--- valgrind-3.13.0.orig/memcheck/tests/linux/Makefile.am -++++ valgrind-3.13.0/memcheck/tests/linux/Makefile.am -+@@ -6,6 +6,10 @@ dist_noinst_SCRIPTS = filter_stderr -+ EXTRA_DIST = \ -+ brk.stderr.exp brk.vgtest \ -+ capget.vgtest capget.stderr.exp capget.stderr.exp2 \ -++ dlclose_leak-no-keep.stderr.exp dlclose_leak-no-keep.stdout.exp \ -++ dlclose_leak-no-keep.vgtest \ -++ dlclose_leak.stderr.exp dlclose_leak.stdout.exp \ -++ dlclose_leak.vgtest \ -+ ioctl-tiocsig.vgtest ioctl-tiocsig.stderr.exp \ -+ lsframe1.vgtest lsframe1.stdout.exp lsframe1.stderr.exp \ -+ lsframe2.vgtest lsframe2.stdout.exp lsframe2.stderr.exp \ -+@@ -25,6 +29,7 @@ EXTRA_DIST = \ -+ check_PROGRAMS = \ -+ brk \ -+ capget \ -++ dlclose_leak dlclose_leak_so.so \ -+ ioctl-tiocsig \ -+ getregset \ -+ lsframe1 \ -+@@ -48,3 +53,15 @@ AM_CXXFLAGS += $(AM_FLAG_M3264_PRI) -+ stack_switch_LDADD = -lpthread -+ timerfd_syscall_LDADD = -lrt -+ -++# Build shared object for dlclose_leak -++dlclose_leak_so_so_SOURCES = dlclose_leak_so.c -++dlclose_leak_so_so_CFLAGS = $(AM_CFLAGS) -fpic -g -O0 -++dlclose_leak_so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared -Wl,-soname \ -++ -Wl,dlclose_leak_so.so -++ -++dlclose_leak_SOURCES = dlclose_leak.c -++dlclose_leak_DEPENDENCIES = dlclose_leak_so.so -++dlclose_leak_LDADD = dlclose_leak_so.so -++dlclose_leak_LDFLAGS = $(AM_FLAG_M3264_PRI) \ -++ -ldl \ -++ -Wl,-rpath,$(top_builddir)/memcheck/tests/linux -+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak-no-keep.stderr.exp -+=================================================================== -+--- /dev/null -++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak-no-keep.stderr.exp -+@@ -0,0 +1,30 @@ -++ -++Conditional jump or move depends on uninitialised value(s) -++ ... -++ -++Invalid read of size 1 -++ ... -++ Address 0x........ is 1 bytes before a block of size 1 alloc'd -++ at 0x........: malloc (vg_replace_malloc.c:...) -++ ... -++ -++done! -++ -++HEAP SUMMARY: -++ in use at exit: 1 bytes in 1 blocks -++ total heap usage: 4 allocs, 3 frees, 123 bytes allocated -++ -++1 bytes in 1 blocks are definitely lost in loss record ... of ... -++ at 0x........: malloc (vg_replace_malloc.c:...) -++ ... -++ -++LEAK SUMMARY: -++ definitely lost: 1 bytes in 1 blocks -++ indirectly lost: 0 bytes in 0 blocks -++ possibly lost: 0 bytes in 0 blocks -++ still reachable: 0 bytes in 0 blocks -++ suppressed: 0 bytes in 0 blocks -++ -++For counts of detected and suppressed errors, rerun with: -v -++Use --track-origins=yes to see where uninitialised values come from -++ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0) -+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak-no-keep.vgtest -+=================================================================== -+--- /dev/null -++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak-no-keep.vgtest -+@@ -0,0 +1,3 @@ -++prog: dlclose_leak -++stderr_filter: ../filter_stderr -++vgopts: --leak-check=yes --keep-debuginfo=no -+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.c -+=================================================================== -+--- /dev/null -++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.c -+@@ -0,0 +1,32 @@ -++/* Test reporting of memory leaks in objects that have been dlopen'ed. -++ * File: dlclose_leak.c */ -++ -++#include <stdio.h> -++#include <stdlib.h> -++#include <dlfcn.h> -++#include <assert.h> -++ -++int (*jmp_on_uninit)(void); -++char* (*alloc_1_byte)(void); -++ -++int main(int argc, char** argv) { -++ char* memToLeak; -++ char x; -++ void* handle = dlopen("./dlclose_leak_so.so", RTLD_NOW); -++ if(!handle) { -++ printf("FAILURE to dlopen dlclose_leak_so.so\n"); -++ return EXIT_FAILURE; -++ } -++ jmp_on_uninit = dlsym(handle,"jmp_on_uninit"); -++ //fprintf(stderr, "jmp_on_uninit: %p\n", jmp_on_uninit); -++ assert(jmp_on_uninit); -++ alloc_1_byte = dlsym(handle,"alloc_1_byte"); -++ //fprintf(stderr, "alloc_1_byte: %p\n", alloc_1_byte); -++ assert(alloc_1_byte); -++ (void)jmp_on_uninit(); -++ memToLeak = alloc_1_byte(); -++ dlclose(handle); -++ x = memToLeak[-1]; -++ fprintf(stderr, "done!\n"); -++ return (EXIT_SUCCESS); -++} -+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.stderr.exp -+=================================================================== -+--- /dev/null -++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.stderr.exp -+@@ -0,0 +1,33 @@ -++ -++Conditional jump or move depends on uninitialised value(s) -++ at 0x........: jmp_on_uninit (dlclose_leak_so.c:10) -++ by 0x........: main (dlclose_leak.c:26) -++ -++Invalid read of size 1 -++ at 0x........: main (dlclose_leak.c:29) -++ Address 0x........ is 1 bytes before a block of size 1 alloc'd -++ at 0x........: malloc (vg_replace_malloc.c:...) -++ by 0x........: alloc_1_byte (dlclose_leak_so.c:20) -++ by 0x........: main (dlclose_leak.c:27) -++ -++done! -++ -++HEAP SUMMARY: -++ in use at exit: 1 bytes in 1 blocks -++ total heap usage: 4 allocs, 3 frees, 123 bytes allocated -++ -++1 bytes in 1 blocks are definitely lost in loss record ... of ... -++ at 0x........: malloc (vg_replace_malloc.c:...) -++ by 0x........: alloc_1_byte (dlclose_leak_so.c:20) -++ by 0x........: main (dlclose_leak.c:27) -++ -++LEAK SUMMARY: -++ definitely lost: 1 bytes in 1 blocks -++ indirectly lost: 0 bytes in 0 blocks -++ possibly lost: 0 bytes in 0 blocks -++ still reachable: 0 bytes in 0 blocks -++ suppressed: 0 bytes in 0 blocks -++ -++For counts of detected and suppressed errors, rerun with: -v -++Use --track-origins=yes to see where uninitialised values come from -++ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0) -+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.vgtest -+=================================================================== -+--- /dev/null -++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.vgtest -+@@ -0,0 +1,3 @@ -++prog: dlclose_leak -++stderr_filter: ../filter_stderr -++vgopts: --leak-check=yes --keep-debuginfo=yes -+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak_so.c -+=================================================================== -+--- /dev/null -++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak_so.c -+@@ -0,0 +1,21 @@ -++/* dlclose_leak_so.c */ -++ -++#include <stdlib.h> -++ -++/** Makes a jump based on an uninitialized variable in order to make sure -++ * errors reported while the dlopen'ed object is loaded work. */ -++int jmp_on_uninit(void) { -++ int uninit[27]; -++ __asm__ __volatile("":::"cc","memory"); -++ if(uninit[13]) { -++ return 1; -++ } else { -++ return 0; -++ } -++} -++ -++/** Leak 1 byte of memory. This is to test the stack check reported after the -++ * object has been dlclose'd. */ -++char* alloc_1_byte(void) { -++ return (char*)malloc(1); -++} -+Index: valgrind-3.13.0/none/tests/cmdline1.stdout.exp -+=================================================================== -+--- valgrind-3.13.0.orig/none/tests/cmdline1.stdout.exp -++++ valgrind-3.13.0/none/tests/cmdline1.stdout.exp -+@@ -42,6 +42,10 @@ usage: valgrind [options] prog-and-args -+ --error-exitcode=<number> exit code to return if errors found [0=disable] -+ --error-markers=<begin>,<end> add lines with begin/end markers before/after -+ each error output in plain text mode [none] -++ --keep-debuginfo=no|yes Keep symbols etc for unloaded code [no] -++ This allows stack traces for memory leaks to -++ include file/line info for code that has been -++ dlclose'd (or similar) -+ --show-below-main=no|yes continue stack traces below main() [no] -+ --default-suppressions=yes|no -+ load default suppressions [yes] -+Index: valgrind-3.13.0/none/tests/cmdline2.stdout.exp -+=================================================================== -+--- valgrind-3.13.0.orig/none/tests/cmdline2.stdout.exp -++++ valgrind-3.13.0/none/tests/cmdline2.stdout.exp -+@@ -42,6 +42,10 @@ usage: valgrind [options] prog-and-args -+ --error-exitcode=<number> exit code to return if errors found [0=disable] -+ --error-markers=<begin>,<end> add lines with begin/end markers before/after -+ each error output in plain text mode [none] -++ --keep-debuginfo=no|yes Keep symbols etc for unloaded code [no] -++ This allows stack traces for memory leaks to -++ include file/line info for code that has been -++ dlclose'd (or similar) -+ --show-below-main=no|yes continue stack traces below main() [no] -+ --default-suppressions=yes|no -+ load default suppressions [yes]
--- a/build/unix/elfhack/elfhack.cpp +++ b/build/unix/elfhack/elfhack.cpp @@ -1104,17 +1104,17 @@ int do_relocation_section(Elf *elf, unsi // But sometimes it appears *before* the eh_frame_hdr section. eh_frame = eh_frame_hdr->getPrevious(); first = eh_frame; second = eh_frame_hdr; } if (eh_frame_hdr && (!eh_frame || strcmp(eh_frame->getName(), ".eh_frame"))) { throw std::runtime_error("Expected to find an .eh_frame section adjacent to .eh_frame_hdr"); } - if (eh_frame && first->getAddr() > relhack->getAddr() && second->getAddr() < relhackcode->getAddr()) { + if (eh_frame && first->getAddr() > relhack->getAddr() && second->getAddr() < first_executable->getAddr()) { // The distance between both sections needs to be preserved because eh_frame_hdr // contains relative offsets to eh_frame. Well, they could be relocated too, but // it's not worth the effort for the few number of bytes this would save. unsigned int distance = second->getAddr() - first->getAddr(); unsigned int origAddr = eh_frame->getAddr(); ElfSection* previous = first->getPrevious(); first->getShdr().sh_addr = (previous->getAddr() + previous->getSize() + first->getAddrAlign() - 1)
--- a/devtools/client/debugger/new/test/mochitest/browser.ini +++ b/devtools/client/debugger/new/test/mochitest/browser.ini @@ -736,15 +736,15 @@ skip-if = os != "mac" || debug || !night skip-if = os != "mac" || debug || !nightly_build [browser_dbg_rr_stepping-02.js] skip-if = os != "mac" || debug || !nightly_build [browser_dbg_rr_stepping-03.js] skip-if = os != "mac" || debug || !nightly_build [browser_dbg_rr_stepping-04.js] skip-if = os != "mac" || debug || !nightly_build [browser_dbg_rr_recovery-01.js] -skip-if = os != "mac" || debug || !nightly_build +skip-if = true # See bug 1481009 [browser_dbg_rr_replay-01.js] skip-if = os != "mac" || debug || !nightly_build [browser_dbg_rr_replay-02.js] skip-if = os != "mac" || debug || !nightly_build [browser_dbg_rr_replay-03.js] skip-if = os != "mac" || debug || !nightly_build
--- a/devtools/client/netmonitor/test/browser_net_headers_sorted.js +++ b/devtools/client/netmonitor/test/browser_net_headers_sorted.js @@ -80,17 +80,17 @@ async function verifyRawHeaders(monitor) const actualRequestHeaders = []; const expectedResponseHeaders = ["cache-control", "pragma", "expires", "set-cookie", "set-cookie", "content-type", "foo-bar", "foo-bar", "foo-bar", "connection", "server", "date", "content-length"]; const expectedRequestHeaders = ["Host", "User-Agent", "Accept", "Accept-Language", - "Accept-Encoding", "Cookie", "Connection", + "Accept-Encoding", "Connection", "Cookie", "Upgrade-Insecure-Requests", "Pragma", "Cache-Control"]; // Click the 'Raw headers' button to show original headers source. const rawHeadersBtn = document.querySelector(".raw-headers-button"); rawHeadersBtn.click(); // Wait till raw headers are available.
--- a/docshell/base/nsDocShellTreeOwner.cpp +++ b/docshell/base/nsDocShellTreeOwner.cpp @@ -1365,17 +1365,17 @@ ChromeTooltipListener::sTooltipCallback( self->mPossibleTooltipNode, getter_Copies(tooltipText), getter_Copies(directionText), &textFound); if (textFound) { LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset(); double scaleFactor = 1.0; if (shell->GetPresContext()) { nsDeviceContext* dc = shell->GetPresContext()->DeviceContext(); - scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel()) / + scaleFactor = double(AppUnitsPerCSSPixel()) / dc->AppUnitsPerDevPixelAtUnitFullZoom(); } // ShowTooltip expects widget-relative position. self->ShowTooltip(self->mMouseScreenX - screenDot.x / scaleFactor, self->mMouseScreenY - screenDot.y / scaleFactor, tooltipText, directionText); } }
--- a/dom/base/DOMRect.cpp +++ b/dom/base/DOMRect.cpp @@ -82,14 +82,14 @@ RoundFloat(double aValue) void DOMRect::SetLayoutRect(const nsRect& aLayoutRect) { double scale = 65536.0; // Round to the nearest 1/scale units. We choose scale so it can be represented // exactly by machine floating point. double scaleInv = 1/scale; - double t2pScaled = scale/nsPresContext::AppUnitsPerCSSPixel(); + double t2pScaled = scale/AppUnitsPerCSSPixel(); double x = RoundFloat(aLayoutRect.x*t2pScaled)*scaleInv; double y = RoundFloat(aLayoutRect.y*t2pScaled)*scaleInv; SetRect(x, y, RoundFloat(aLayoutRect.XMost()*t2pScaled)*scaleInv - x, RoundFloat(aLayoutRect.YMost()*t2pScaled)*scaleInv - y); }
--- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -6,16 +6,17 @@ // Needs to be first. #include "base/basictypes.h" #include "Navigator.h" #include "nsIXULAppInfo.h" #include "nsPluginArray.h" #include "nsMimeTypeArray.h" +#include "mozilla/AntiTrackingCommon.h" #include "mozilla/MemoryReporting.h" #include "mozilla/dom/BodyExtractor.h" #include "mozilla/dom/FetchBinding.h" #include "mozilla/dom/File.h" #include "nsGeolocation.h" #include "nsIClassOfService.h" #include "nsIHttpProtocolHandler.h" #include "nsIContentPolicy.h" @@ -58,16 +59,17 @@ #include "mozilla/dom/Event.h" // for Event #include "nsGlobalWindow.h" #include "nsIPermissionManager.h" #include "nsMimeTypes.h" #include "nsNetUtil.h" #include "nsRFPService.h" #include "nsStringStream.h" #include "nsComponentManagerUtils.h" +#include "nsICookieService.h" #include "nsIStringStream.h" #include "nsIHttpChannel.h" #include "nsIHttpChannelInternal.h" #include "nsStreamUtils.h" #include "WidgetUtils.h" #include "nsIPresentationService.h" #include "nsIScriptError.h" @@ -508,25 +510,21 @@ Navigator::Storage() if(!mStorageManager) { mStorageManager = new StorageManager(mWindow->AsGlobal()); } return mStorageManager; } -// Values for the network.cookie.cookieBehavior pref are documented in -// nsCookieService.cpp. -#define COOKIE_BEHAVIOR_REJECT 2 - bool Navigator::CookieEnabled() { bool cookieEnabled = (StaticPrefs::network_cookie_cookieBehavior() != - COOKIE_BEHAVIOR_REJECT); + nsICookieService::BEHAVIOR_REJECT); // Check whether an exception overrides the global cookie behavior // Note that the code for getting the URI here matches that in // nsHTMLDocument::SetCookie. if (!mWindow || !mWindow->GetDocShell()) { return cookieEnabled; } @@ -539,30 +537,18 @@ Navigator::CookieEnabled() doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); if (!codebaseURI) { // Not a codebase, so technically can't set cookies, but let's // just return the default value. return cookieEnabled; } - nsCOMPtr<nsICookiePermission> permMgr = - do_GetService(NS_COOKIEPERMISSION_CONTRACTID); - NS_ENSURE_TRUE(permMgr, cookieEnabled); - - // Pass null for the channel, just like the cookie service does. - nsCookieAccess access; - nsresult rv = permMgr->CanAccess(doc->NodePrincipal(), &access); - NS_ENSURE_SUCCESS(rv, cookieEnabled); - - if (access != nsICookiePermission::ACCESS_DEFAULT) { - cookieEnabled = access != nsICookiePermission::ACCESS_DENY; - } - - return cookieEnabled; + return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(mWindow, + codebaseURI); } bool Navigator::OnLine() { return !NS_IsOffline(); }
--- a/dom/base/Selection.cpp +++ b/dom/base/Selection.cpp @@ -2020,17 +2020,17 @@ Selection::DoAutoScroll(nsIFrame* aFrame } if (!didScroll && !done) { // If aPoint is at the screen edge then try to scroll anyway, once. RefPtr<nsDeviceContext> dx = shell->GetViewManager()->GetDeviceContext(); nsRect screen; dx->GetRect(screen); nsPoint screenPoint = globalPoint + rootmostFrame->GetScreenRectInAppUnits().TopLeft(); - nscoord onePx = nsPresContext::AppUnitsPerCSSPixel(); + nscoord onePx = AppUnitsPerCSSPixel(); nscoord scrollAmount = 10 * onePx; if (std::abs(screen.x - screenPoint.x) <= onePx) { aPoint.x -= scrollAmount; } else if (std::abs(screen.XMost() - screenPoint.x) <= onePx) { aPoint.x += scrollAmount; } else if (std::abs(screen.y - screenPoint.y) <= onePx) { aPoint.y -= scrollAmount; } else if (std::abs(screen.YMost() - screenPoint.y) <= onePx) {
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -212,18 +212,18 @@ #include "nsWidgetsCID.h" #include "nsIWindowProvider.h" #include "nsWrapperCacheInlines.h" #include "nsXULPopupManager.h" #include "xpcprivate.h" // nsXPConnect #include "HTMLSplitOnSpacesTokenizer.h" #include "nsContentTypeParser.h" #include "nsICookiePermission.h" +#include "nsICookieService.h" #include "mozIThirdPartyUtil.h" -#include "nsICookieService.h" #include "mozilla/EnumSet.h" #include "mozilla/BloomFilter.h" #include "TabChild.h" #include "mozilla/dom/DocGroup.h" #include "mozilla/dom/TabGroup.h" #include "nsIWebNavigationInfo.h" #include "nsPluginHost.h" #include "mozilla/HangAnnotations.h" @@ -8746,57 +8746,50 @@ nsContentUtils::StorageAccess nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal) { return InternalStorageAllowedForPrincipal(aPrincipal, nullptr, nullptr, nullptr); } // static, private void -nsContentUtils::GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal, - uint32_t* aLifetimePolicy, - uint32_t* aBehavior) +nsContentUtils::GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal, + uint32_t* aLifetimePolicy) { *aLifetimePolicy = sCookiesLifetimePolicy; - *aBehavior = StaticPrefs::network_cookie_cookieBehavior(); // Any permissions set for the given principal will override our default // settings from preferences. nsCOMPtr<nsIPermissionManager> permissionManager = services::GetPermissionManager(); if (!permissionManager) { return; } uint32_t perm; permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm); switch (perm) { case nsICookiePermission::ACCESS_ALLOW: - *aBehavior = nsICookieService::BEHAVIOR_ACCEPT; *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; break; case nsICookiePermission::ACCESS_DENY: - *aBehavior = nsICookieService::BEHAVIOR_REJECT; *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; break; case nsICookiePermission::ACCESS_SESSION: - *aBehavior = nsICookieService::BEHAVIOR_ACCEPT; *aLifetimePolicy = nsICookieService::ACCEPT_SESSION; break; case nsICookiePermission::ACCESS_ALLOW_FIRST_PARTY_ONLY: - *aBehavior = nsICookieService::BEHAVIOR_REJECT_FOREIGN; // NOTE: The decision was made here to override the lifetime policy to be // ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does // prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a // specific domain. As BEHAVIOR_REJECT_FOREIGN isn't visible in our UI, // this is probably not an issue. *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; break; case nsICookiePermission::ACCESS_LIMIT_THIRD_PARTY: - *aBehavior = nsICookieService::BEHAVIOR_LIMIT_FOREIGN; // NOTE: The decision was made here to override the lifetime policy to be // ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does // prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a // specific domain. As BEHAVIOR_LIMIT_FOREIGN isn't visible in our UI, // this is probably not an issue. *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; break; } @@ -8856,96 +8849,82 @@ nsContentUtils::IsTrackingResourceWindow } return httpChannel->GetIsTrackingResource(); } static bool StorageDisabledByAntiTrackingInternal(nsPIDOMWindowInner* aWindow, nsIChannel* aChannel, + nsIPrincipal* aPrincipal, nsIURI* aURI) { - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { - return false; - } - - // Let's check if this is a 3rd party context. - if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) { - return false; - } + MOZ_ASSERT(aWindow || aChannel || aPrincipal); if (aWindow) { - nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow); - nsGlobalWindowOuter* outerWindow = - nsGlobalWindowOuter::Cast(innerWindow->GetOuterWindow()); - if (NS_WARN_IF(!outerWindow)) { - return false; - } - - // We are a first party resource. - if (outerWindow->IsTopLevelWindow()) { - return false; - } - nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI(); - if (documentURI && - AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow, - documentURI)) { + return !documentURI || + !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow, + documentURI); + } + + if (aChannel) { + nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); + if (!httpChannel) { return false; } - return true; - } - - // aChannel and aWindow are mutually exclusive. - MOZ_ASSERT(aChannel); - - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); - if (!httpChannel) { - return false; - } - - // If this is not a tracking resource, nothing is disabled. - if (!httpChannel->GetIsTrackingResource()) { - return false; - } - - nsCOMPtr<nsIURI> uri; - nsresult rv = httpChannel->GetURI(getter_AddRefs(uri)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - - return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel, - uri); + nsCOMPtr<nsIURI> uri; + nsresult rv = httpChannel->GetURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel, + uri); + } + + MOZ_ASSERT(aPrincipal); + return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aPrincipal); } // static public bool nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow, nsIChannel* aChannel, + nsIPrincipal* aPrincipal, nsIURI* aURI) { bool disabled = - StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aURI); + StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aPrincipal, aURI); if (disabled && StaticPrefs::privacy_restrict3rdpartystorage_ui_enabled()) { nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil(); if (!thirdPartyUtil) { return false; } - nsCOMPtr<mozIDOMWindowProxy> win; - nsresult rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, - getter_AddRefs(win)); - NS_ENSURE_SUCCESS(rv, false); - auto* pwin = nsPIDOMWindowOuter::From(win); - - pwin->NotifyContentBlockingState( - nsIWebProgressListener::STATE_BLOCKED_TRACKING_COOKIES, aChannel); + nsCOMPtr<nsPIDOMWindowOuter> pwin; + if (aWindow) { + auto* outer = nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow()); + if (outer) { + pwin = outer->GetTopOuter(); + } + } else if (aChannel) { + nsCOMPtr<mozIDOMWindowProxy> win; + nsresult rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, + getter_AddRefs(win)); + NS_ENSURE_SUCCESS(rv, false); + pwin = nsPIDOMWindowOuter::From(win); + } + + if (pwin) { + pwin->NotifyContentBlockingState( + nsIWebProgressListener::STATE_BLOCKED_TRACKING_COOKIES, aChannel); + } } return disabled; } // static, private nsContentUtils::StorageAccess nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal, nsPIDOMWindowInner* aWindow, @@ -8957,45 +8936,39 @@ nsContentUtils::InternalStorageAllowedFo StorageAccess access = StorageAccess::eAllow; // We don't allow storage on the null principal, in general. Even if the // calling context is chrome. if (aPrincipal->GetIsNullPrincipal()) { return StorageAccess::eDeny; } - if (StorageDisabledByAntiTracking(aWindow, aChannel, aURI)) { - return StorageAccess::eDeny; - } - if (aWindow) { // If the document is sandboxed, then it is not permitted to use storage nsIDocument* document = aWindow->GetExtantDoc(); if (document && document->GetSandboxFlags() & SANDBOXED_ORIGIN) { return StorageAccess::eDeny; } // Check if we are in private browsing, and record that fact if (IsInPrivateBrowsing(document)) { access = StorageAccess::ePrivateBrowsing; } } uint32_t lifetimePolicy; - uint32_t behavior; // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior // and ACCEPT_NORMALLY as lifetimePolicy (See Bug 1406675 for rationale). auto policy = BasePrincipal::Cast(aPrincipal)->AddonPolicy(); if (policy) { - behavior = nsICookieService::BEHAVIOR_ACCEPT; lifetimePolicy = nsICookieService::ACCEPT_NORMALLY; } else { - GetCookieBehaviorForPrincipal(aPrincipal, &lifetimePolicy, &behavior); + GetCookieLifetimePolicyForPrincipal(aPrincipal, &lifetimePolicy); } // Check if we should only allow storage for the session, and record that fact if (lifetimePolicy == nsICookieService::ACCEPT_SESSION) { // Storage could be StorageAccess::ePrivateBrowsing or StorageAccess::eAllow // so perform a std::min comparison to make sure we preserve ePrivateBrowsing // if it has been set. access = std::min(StorageAccess::eSessionScoped, access); @@ -9031,29 +9004,17 @@ nsContentUtils::InternalStorageAllowedFo if (uri) { bool isAbout = false; MOZ_ALWAYS_SUCCEEDS(uri->SchemeIs("about", &isAbout)); if (isAbout) { return access; } } - // We don't want to prompt for every attempt to access permissions. - if (behavior == nsICookieService::BEHAVIOR_REJECT) { - return StorageAccess::eDeny; - } - - if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN || - behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) && - IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) { - // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by - // simply rejecting the request to use the storage. In the future, if we - // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense - // for non-cookie storage types, this may change. - + if (StorageDisabledByAntiTracking(aWindow, aChannel, aPrincipal, aURI)) { return StorageAccess::eDeny; } return access; } namespace {
--- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2946,21 +2946,23 @@ public: /* * Checks if storage for the given principal is permitted by the user's * preferences. The caller is assumed to not be a third-party iframe. * (if that is possible, the caller should use StorageAllowedForWindow) */ static StorageAccess StorageAllowedForPrincipal(nsIPrincipal* aPrincipal); /* - * Returns true if this window/channel should disable storages because of the - * anti-tracking feature. + * Returns true if this window/channel/aPrincipal should disable storages + * because of the anti-tracking feature. + * Note that either aWindow or aChannel may be null when calling this function. */ static bool StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow, nsIChannel* aChannel, + nsIPrincipal* aPrincipal, nsIURI* aURI); /* * Returns true if this window/channel is a 3rd party context. */ static bool IsThirdPartyWindowOrChannel(nsPIDOMWindowInner* aWindow, nsIChannel* aChannel, nsIURI* aURI); @@ -3337,24 +3339,23 @@ private: mozilla::dom::AutocompleteInfo& aInfo, bool aGrantAllValidValue = false); static bool CallOnAllRemoteChildren(mozilla::dom::MessageBroadcaster* aManager, CallOnRemoteChildFunction aCallback, void* aArg); /** - * Gets the current cookie lifetime policy and cookie behavior for a given - * principal by checking with preferences and the permission manager. + * Gets the current cookie lifetime policy for a given principal by checking + * with preferences and the permission manager. * * Used in the implementation of InternalStorageAllowedForPrincipal. */ - static void GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal, - uint32_t* aLifetimePolicy, - uint32_t* aBehavior); + static void GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal, + uint32_t* aLifetimePolicy); /* * Checks if storage for a given principal is permitted by the user's * preferences. If aWindow is non-null, its principal must be passed as * aPrincipal, and the third-party iframe and sandboxing status of the window * are also checked. If aURI is non-null, then it is used as the comparison * against aWindow to determine if this is a third-party load. We also * allow a channel instead of the window reference when determining 3rd party
--- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -273,16 +273,17 @@ #include "nsIURIClassifier.h" #include "nsIURIMutator.h" #include "mozilla/DocumentStyleRootIterator.h" #include "mozilla/RestyleManager.h" #include "mozilla/ClearOnShutdown.h" #include "nsHTMLTags.h" #include "NodeUbiReporting.h" +#include "nsICookieService.h" using namespace mozilla; using namespace mozilla::dom; typedef nsTArray<Link*> LinkArray; static LazyLogModule gDocumentLeakPRLog("DocumentLeak"); static LazyLogModule gCspPRLog("CSP"); @@ -12638,17 +12639,18 @@ nsIDocument::SetDocTreeHadPlayRevoked() if (topLevelDoc) { topLevelDoc->mDocTreeHadPlayRevoked = true; } } void nsIDocument::MaybeAllowStorageForOpener() { - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { + if (StaticPrefs::network_cookie_cookieBehavior() != + nsICookieService::BEHAVIOR_REJECT_TRACKER) { return; } // This will probably change for project fission, but currently this document // and the opener are on the same process. In the future, we should make this // part async. nsPIDOMWindowInner* inner = GetInnerWindow();
--- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -3453,17 +3453,17 @@ nsGlobalWindowOuter::GetDevicePixelRatio } float overrideDPPX = presContext->GetOverrideDPPX(); if (overrideDPPX > 0) { return overrideDPPX; } - return double(nsPresContext::AppUnitsPerCSSPixel()) / + return double(AppUnitsPerCSSPixel()) / double(presContext->AppUnitsPerDevPixel()); } float nsPIDOMWindowOuter::GetDevicePixelRatio(CallerType aCallerType) { return nsGlobalWindowOuter::Cast(this)->GetDevicePixelRatioOuter(aCallerType); } @@ -6999,17 +6999,17 @@ nsGlobalWindowOuter::OpenInternal(const } } NS_ENSURE_SUCCESS(rv, rv); // success! - if (!aCalledNoScript && !windowExists && uri) { + if (!aCalledNoScript && !windowExists && uri && !forceNoOpener) { MaybeAllowStorageForOpenedWindow(uri); } NS_ENSURE_TRUE(domReturn, NS_OK); nsCOMPtr<nsPIDOMWindowOuter> outerReturn = nsPIDOMWindowOuter::From(domReturn); outerReturn.swap(*aReturn);
--- a/dom/broadcastchannel/BroadcastChannel.cpp +++ b/dom/broadcastchannel/BroadcastChannel.cpp @@ -12,20 +12,20 @@ #include "mozilla/dom/StructuredCloneHolder.h" #include "mozilla/dom/ipc/StructuredCloneData.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRef.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/PBackgroundChild.h" -#include "mozilla/StaticPrefs.h" #include "nsContentUtils.h" #include "nsIBFCacheEntry.h" +#include "nsICookieService.h" #include "nsIDocument.h" #include "nsISupportsPrimitives.h" #ifdef XP_WIN #undef PostMessage #endif namespace mozilla { @@ -68,22 +68,24 @@ GetPrincipalFromThreadSafeWorkerRef(Thre return wp->GetPrincipal(); } class InitializeRunnable final : public WorkerMainThreadRunnable { public: InitializeRunnable(ThreadSafeWorkerRef* aWorkerRef, nsACString& aOrigin, - PrincipalInfo& aPrincipalInfo, ErrorResult& aRv) + PrincipalInfo& aPrincipalInfo, bool* aThirdPartyWindow, + ErrorResult& aRv) : WorkerMainThreadRunnable(aWorkerRef->Private(), NS_LITERAL_CSTRING("BroadcastChannel :: Initialize")) , mWorkerRef(aWorkerRef) , mOrigin(aOrigin) , mPrincipalInfo(aPrincipalInfo) + , mThirdPartyWindow(aThirdPartyWindow) , mRv(aRv) { MOZ_ASSERT(mWorkerRef); } bool MainThreadRun() override { MOZ_ASSERT(NS_IsMainThread()); @@ -111,23 +113,27 @@ public: } // Window doesn't exist for some kind of workers (eg: SharedWorkers) nsPIDOMWindowInner* window = wp->GetWindow(); if (!window) { return true; } + *mThirdPartyWindow = + nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr, nullptr); + return true; } private: RefPtr<ThreadSafeWorkerRef> mWorkerRef; nsACString& mOrigin; PrincipalInfo& mPrincipalInfo; + bool* mThirdPartyWindow; ErrorResult& mRv; }; class CloseRunnable final : public nsIRunnable, public nsICancelableRunnable { public: NS_DECL_ISUPPORTS @@ -296,53 +302,56 @@ BroadcastChannel::Constructor(const Glob return nullptr; } aRv = PrincipalToPrincipalInfo(principal, &principalInfo); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } - if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() && + if (nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr, + nullptr) && nsContentUtils::StorageAllowedForWindow(window) != nsContentUtils::StorageAccess::eAllow) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } } else { JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); - if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() && - !workerPrivate->IsStorageAllowed()) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } - RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(workerPrivate, "BroadcastChannel", [bc] () { bc->Shutdown(); }); // We are already shutting down the worker. Let's return a non-active // object. if (NS_WARN_IF(!workerRef)) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr<ThreadSafeWorkerRef> tsr = new ThreadSafeWorkerRef(workerRef); + bool thirdPartyWindow = false; + RefPtr<InitializeRunnable> runnable = - new InitializeRunnable(tsr, origin, principalInfo, aRv); + new InitializeRunnable(tsr, origin, principalInfo, &thirdPartyWindow, + aRv); runnable->Dispatch(Canceling, aRv); if (aRv.Failed()) { return nullptr; } + if (thirdPartyWindow && !workerPrivate->IsStorageAllowed()) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + bc->mWorkerRef = std::move(workerRef); } // Register this component to PBackground. PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); if (NS_WARN_IF(!actorChild)) { // Firefox is probably shutting down. Let's return a 'generic' error. aRv.Throw(NS_ERROR_FAILURE);
--- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -2845,29 +2845,29 @@ public: , mExplicitLanguage(aExplicitLanguage) , mPresContext(aPresContext) { } virtual float GetEmLength() const override { return NSAppUnitsToFloatPixels(mFont.size, - nsPresContext::AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); } virtual float GetExLength() const override { nsDeviceContext* dc = mPresContext->DeviceContext(); nsFontMetrics::Params params; params.language = mFontLanguage; params.explicitLanguage = mExplicitLanguage; params.textPerf = mPresContext->GetTextPerfMetrics(); RefPtr<nsFontMetrics> fontMetrics = dc->GetMetricsFor(mFont, params); return NSAppUnitsToFloatPixels(fontMetrics->XHeight(), - nsPresContext::AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); } virtual gfx::Size GetSize() const override { return Size(mSize); } private: gfx::IntSize mSize; const nsFont& mFont; @@ -3736,17 +3736,17 @@ CanvasRenderingContext2D::SetFontInterna nsFont resizedFont(fontStyle->mFont); // Create a font group working in units of CSS pixels instead of the usual // device pixels, to avoid being affected by page zoom. nsFontMetrics will // convert nsFont size in app units to device pixels for the font group, so // here we first apply to the size the equivalent of a conversion from device // pixels to CSS pixels, to adjust for the difference in expectations from // other nsFontMetrics clients. resizedFont.size = - (fontStyle->mSize * c->AppUnitsPerDevPixel()) / nsPresContext::AppUnitsPerCSSPixel(); + (fontStyle->mSize * c->AppUnitsPerDevPixel()) / AppUnitsPerCSSPixel(); nsFontMetrics::Params params; params.language = fontStyle->mLanguage; params.explicitLanguage = fontStyle->mExplicitLanguage; params.userFontSet = c->GetUserFontSet(); params.textPerf = c->GetTextPerfMetrics(); RefPtr<nsFontMetrics> metrics = c->DeviceContext()->GetMetricsFor(resizedFont, params);
--- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -1176,17 +1176,17 @@ protected: nsIPresShell *ps = GetPresShell(); nsPresContext *pc; if (!ps) goto FINISH; pc = ps->GetPresContext(); if (!pc) goto FINISH; devPixel = pc->AppUnitsPerDevPixel(); - cssPixel = nsPresContext::AppUnitsPerCSSPixel(); + cssPixel = AppUnitsPerCSSPixel(); FINISH: if (aPerDevPixel) *aPerDevPixel = devPixel; if (aPerCSSPixel) *aPerCSSPixel = cssPixel; }
--- a/dom/events/WheelEvent.cpp +++ b/dom/events/WheelEvent.cpp @@ -70,37 +70,37 @@ WheelEvent::InitWheelEvent(const nsAStri double WheelEvent::DeltaX() { if (!mAppUnitsPerDevPixel) { return mEvent->AsWheelEvent()->mDeltaX; } return mEvent->AsWheelEvent()->mDeltaX * - mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel(); + mAppUnitsPerDevPixel / AppUnitsPerCSSPixel(); } double WheelEvent::DeltaY() { if (!mAppUnitsPerDevPixel) { return mEvent->AsWheelEvent()->mDeltaY; } return mEvent->AsWheelEvent()->mDeltaY * - mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel(); + mAppUnitsPerDevPixel / AppUnitsPerCSSPixel(); } double WheelEvent::DeltaZ() { if (!mAppUnitsPerDevPixel) { return mEvent->AsWheelEvent()->mDeltaZ; } return mEvent->AsWheelEvent()->mDeltaZ * - mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel(); + mAppUnitsPerDevPixel / AppUnitsPerCSSPixel(); } uint32_t WheelEvent::DeltaMode() { return mEvent->AsWheelEvent()->mDeltaMode; }
--- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -1102,17 +1102,17 @@ nsHTMLDocument::GetCookie(nsAString& aCo // If the document's sandboxed origin flag is set, access to read cookies // is prohibited. if (mSandboxFlags & SANDBOXED_ORIGIN) { rv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } if (nsContentUtils::StorageDisabledByAntiTracking(GetInnerWindow(), nullptr, - nullptr)) { + NodePrincipal(), nullptr)) { return; } // If the document is a cookie-averse Document... return the empty string. if (IsCookieAverse()) { return; } @@ -1157,17 +1157,17 @@ nsHTMLDocument::SetCookie(const nsAStrin // If the document's sandboxed origin flag is set, access to write cookies // is prohibited. if (mSandboxFlags & SANDBOXED_ORIGIN) { rv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } if (nsContentUtils::StorageDisabledByAntiTracking(GetInnerWindow(), nullptr, - nullptr)) { + NodePrincipal(), nullptr)) { return; } // If the document is a cookie-averse Document... do nothing. if (IsCookieAverse()) { return; }
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -142,17 +142,16 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsIMemoryInfoDumper.h" #include "nsIMemoryReporter.h" #include "nsIMozBrowserFrame.h" #include "nsIMutable.h" #include "nsIObserverService.h" #include "nsIParentChannel.h" #include "nsIPresShell.h" -#include "nsIPromptService.h" #include "nsIRemoteWindowContext.h" #include "nsIScriptError.h" #include "nsIScriptSecurityManager.h" #include "nsISiteSecurityService.h" #include "nsISound.h" #include "nsISpellChecker.h" #include "nsIStringBundle.h" #include "nsISupportsPrimitives.h" @@ -5231,28 +5230,16 @@ ContentParent::RecvGraphicsError(const n std::stringstream message; message << "CP+" << aError.get(); lf->UpdateStringsVector(message.str()); } return IPC_OK(); } mozilla::ipc::IPCResult -ContentParent::RecvRecordReplayFatalError(const nsCString& aError) -{ - nsCOMPtr<nsIPromptService> promptService(do_GetService(NS_PROMPTSERVICE_CONTRACTID)); - MOZ_RELEASE_ASSERT(promptService); - - nsAutoCString str(aError); - promptService->Alert(nullptr, u"Fatal Record/Replay Error", NS_ConvertUTF8toUTF16(str).get()); - - return IPC_OK(); -} - -mozilla::ipc::IPCResult ContentParent::RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed) { // Only one driver crash guard should be active at a time, per-process. MOZ_ASSERT(!mDriverCrashGuard); UniquePtr<gfx::DriverCrashGuard> guard; switch (gfx::CrashGuardType(aGuardType)) { case gfx::CrashGuardType::D3D11Layers:
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -1150,18 +1150,16 @@ public: const TabId& aTabId, layers::LayersId* aId) override; virtual mozilla::ipc::IPCResult RecvDeallocateLayerTreeId(const ContentParentId& aCpId, const layers::LayersId& aId) override; virtual mozilla::ipc::IPCResult RecvGraphicsError(const nsCString& aError) override; - virtual mozilla::ipc::IPCResult RecvRecordReplayFatalError(const nsCString& aError) override; - virtual mozilla::ipc::IPCResult RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed) override; virtual mozilla::ipc::IPCResult RecvEndDriverCrashGuard(const uint32_t& aGuardType) override; virtual mozilla::ipc::IPCResult RecvAddIdleObserver(const uint64_t& observerId, const uint32_t& aIdleTimeInS) override;
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -933,19 +933,16 @@ parent: async RecordingDeviceEvents(nsString recordingStatus, nsString pageURL, bool isAudio, bool isVideo); // Graphics errors async GraphicsError(nsCString aError); - // Record/replay errors. - async RecordReplayFatalError(nsCString aError); - // Driver crash guards. aGuardType must be a member of CrashGuardType. sync BeginDriverCrashGuard(uint32_t aGuardType) returns (bool crashDetected); sync EndDriverCrashGuard(uint32_t aGuardType); async AddIdleObserver(uint64_t observerId, uint32_t idleTimeInS); async RemoveIdleObserver(uint64_t observerId, uint32_t idleTimeInS); /**
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1178,17 +1178,17 @@ TabParent::SendRealMouseEvent(WidgetMous LayoutDeviceToCSSScale TabParent::GetLayoutDeviceToCSSScale() { nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement); nsIDocument* doc = (content ? content->OwnerDoc() : nullptr); nsPresContext* ctx = (doc ? doc->GetPresContext() : nullptr); return LayoutDeviceToCSSScale(ctx - ? (float)ctx->AppUnitsPerDevPixel() / nsPresContext::AppUnitsPerCSSPixel() + ? (float)ctx->AppUnitsPerDevPixel() / AppUnitsPerCSSPixel() : 0.0f); } bool TabParent::QueryDropLinksForVerification() { // Before sending the dragEvent, we query the links being dragged and // store them on the parent, to make sure the child can not modify links.
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -1025,17 +1025,17 @@ NPBool nsPluginInstanceOwner::ConvertPoi if (destY) { *destY = sourceY; } return true; } nsPresContext* presContext = pluginFrame->PresContext(); CSSToLayoutDeviceScale scaleFactor( - double(nsPresContext::AppUnitsPerCSSPixel()) / + double(AppUnitsPerCSSPixel()) / presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); PuppetWidget *puppetWidget = static_cast<PuppetWidget*>(widget); PuppetWidget *rootWidget = static_cast<PuppetWidget*>(widget->GetTopLevelWidget()); if (!rootWidget) { return false; } CSSIntPoint chromeSize = CSSIntPoint::Truncate( @@ -1134,17 +1134,17 @@ NPBool nsPluginInstanceOwner::ConvertPoi } if (destY) { *destY = sourceY; } return true; } nsPresContext* presContext = pluginFrame->PresContext(); - double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/ + double scaleFactor = double(AppUnitsPerCSSPixel())/ presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom(); nsCOMPtr<nsIScreen> screen = widget->GetWidgetScreen(); if (!screen) { return false; } int32_t screenX, screenY, screenWidth, screenHeight; @@ -1944,17 +1944,17 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent->mMessage == eMouseOver || anEvent->mMessage == eMouseOut) { nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(anEvent, aObjectFrame) - aObjectFrame->GetContentRectRelativeToSelf().TopLeft(); nsPresContext* presContext = aObjectFrame->PresContext(); // Plugin event coordinates need to be translated from device pixels // into "display pixels" in HiDPI modes. - double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/ + double scaleFactor = double(AppUnitsPerCSSPixel())/ aObjectFrame->PresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom(); size_t intScaleFactor = ceil(scaleFactor); nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor, presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor); cocoaEvent.data.mouse.pluginX = double(ptPx.x); cocoaEvent.data.mouse.pluginY = double(ptPx.y); } @@ -3295,17 +3295,17 @@ nsPluginInstanceOwner::GetContentsScaleF double scaleFactor = 1.0; // On Mac, device pixels need to be translated to (and from) "display pixels" // for plugins. On other platforms, plugin coordinates are always in device // pixels. #if defined(XP_MACOSX) || defined(XP_WIN) nsCOMPtr<nsIContent> content = do_QueryReferent(mContent); nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(content->OwnerDoc()); if (presShell) { - scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/ + scaleFactor = double(AppUnitsPerCSSPixel())/ presShell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom(); } #endif *result = scaleFactor; return NS_OK; } void
--- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -4,16 +4,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "RuntimeService.h" #include "nsAutoPtr.h" #include "nsIChannel.h" #include "nsIContentSecurityPolicy.h" +#include "nsICookieService.h" #include "nsIDocument.h" #include "nsIDOMChromeWindow.h" #include "nsIEffectiveTLDService.h" #include "nsIObserverService.h" #include "nsIPrincipal.h" #include "nsIScriptContext.h" #include "nsIScriptError.h" #include "nsIScriptSecurityManager.h" @@ -2263,17 +2264,18 @@ RuntimeService::ResumeWorkersForWindow(n } } void RuntimeService::PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow) { AssertIsOnMainThread(); MOZ_ASSERT(aWindow); - MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled()); + MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() == + nsICookieService::BEHAVIOR_REJECT_TRACKER); nsTArray<WorkerPrivate*> workers; GetWorkersForWindow(aWindow, workers); for (uint32_t index = 0; index < workers.Length(); index++) { workers[index]->PropagateFirstPartyStorageAccessGranted(); } } @@ -2876,17 +2878,18 @@ ResumeWorkersForWindow(nsPIDOMWindowInne runtime->ResumeWorkersForWindow(aWindow); } } void PropagateFirstPartyStorageAccessGrantedToWorkers(nsPIDOMWindowInner* aWindow) { AssertIsOnMainThread(); - MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled()); + MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() == + nsICookieService::BEHAVIOR_REJECT_TRACKER); RuntimeService* runtime = RuntimeService::GetService(); if (runtime) { runtime->PropagateFirstPartyStorageAccessGranted(aWindow); } } WorkerPrivate*
--- a/gfx/layers/AnimationHelper.cpp +++ b/gfx/layers/AnimationHelper.cpp @@ -67,17 +67,17 @@ CompositorAnimationStorage::GetOMTAValue // Undo the rebasing applied by // nsDisplayTransform::GetResultingTransformMatrixInternal transform.ChangeBasis(-transformOrigin); // Convert to CSS pixels (this undoes the operations performed by // nsStyleTransformMatrix::ProcessTranslatePart which is called from // nsDisplayTransform::GetResultingTransformMatrix) double devPerCss = - double(scale) / double(nsDeviceContext::AppUnitsPerCSSPixel()); + double(scale) / double(AppUnitsPerCSSPixel()); transform._41 *= devPerCss; transform._42 *= devPerCss; transform._43 *= devPerCss; omtaValue = transform; break; } case AnimatedValue::NONE: break;
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -254,18 +254,18 @@ SetDisplayPortMargins(nsIPresShell* aPre nsLayoutUtils::SetDisplayPortMargins(aContent, aPresShell, margins, 0); if (!hadDisplayPort) { nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors( aContent->GetPrimaryFrame(), nsLayoutUtils::RepaintMode::Repaint); } CSSSize baseSize = aMetrics.CalculateCompositedSizeInCssPixels(); nsRect base(0, 0, - baseSize.width * nsPresContext::AppUnitsPerCSSPixel(), - baseSize.height * nsPresContext::AppUnitsPerCSSPixel()); + baseSize.width * AppUnitsPerCSSPixel(), + baseSize.height * AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base); } static void SetPaintRequestTime(nsIContent* aContent, const TimeStamp& aPaintRequestTime) { aContent->SetProperty(nsGkAtoms::paintRequestTime, new TimeStamp(aPaintRequestTime),
--- a/gfx/src/AppUnits.h +++ b/gfx/src/AppUnits.h @@ -5,12 +5,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_AppUnits_h #define mozilla_AppUnits_h #include <stdint.h> namespace mozilla { -inline int32_t AppUnitsPerCSSPixel() { return 60; } -inline int32_t AppUnitsPerCSSInch() { return 96 * AppUnitsPerCSSPixel(); } +constexpr inline int32_t AppUnitsPerCSSPixel() { return 60; } +constexpr inline int32_t AppUnitsPerCSSInch() { return 96 * AppUnitsPerCSSPixel(); } } // namespace mozilla #endif /* _NS_APPUNITS_H_ */
--- a/gfx/src/nsDeviceContext.h +++ b/gfx/src/nsDeviceContext.h @@ -77,22 +77,16 @@ public: * Create a reference rendering context and initialize it. Only call this * method on device contexts that were initialized for printing. * * @return the new rendering context. */ already_AddRefed<gfxContext> CreateReferenceRenderingContext(); /** - * Gets the number of app units in one CSS pixel; this number is global, - * not unique to each device context. - */ - static int32_t AppUnitsPerCSSPixel() { return mozilla::AppUnitsPerCSSPixel(); } - - /** * Gets the number of app units in one device pixel; this number * is usually a factor of AppUnitsPerCSSPixel(), although that is * not guaranteed. */ int32_t AppUnitsPerDevPixel() const { return mAppUnitsPerDevPixel; } /** * Convert device pixels which is used for gfx/thebes to nearest @@ -110,22 +104,16 @@ public: /** * Gets the number of app units in one physical inch; this is the * device's DPI times AppUnitsPerDevPixel(). */ int32_t AppUnitsPerPhysicalInch() const { return mAppUnitsPerPhysicalInch; } /** - * Gets the number of app units in one CSS inch; this is - * 96 times AppUnitsPerCSSPixel. - */ - static int32_t AppUnitsPerCSSInch() { return mozilla::AppUnitsPerCSSInch(); } - - /** * Get the ratio of app units to dev pixels that would be used at unit * (100%) full zoom. */ int32_t AppUnitsPerDevPixelAtUnitFullZoom() const { return mAppUnitsPerDevPixelAtUnitFullZoom; } /** * Get the nsFontMetrics that describe the properties of
--- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -133,17 +133,17 @@ nsFontMetrics::nsFontMetrics(const nsFon aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT, aFont.synthesis & NS_FONT_SYNTHESIS_STYLE, aFont.languageOverride); aFont.AddFontFeaturesToStyle(&style, mOrientation == gfxFont::eVertical); aFont.AddFontVariationsToStyle(&style); gfxFloat devToCssSize = gfxFloat(mP2A) / - gfxFloat(nsDeviceContext::AppUnitsPerCSSPixel()); + gfxFloat(AppUnitsPerCSSPixel()); mFontGroup = gfxPlatform::GetPlatform()-> CreateFontGroup(aFont.fontlist, &style, aParams.textPerf, aParams.userFontSet, devToCssSize); } nsFontMetrics::~nsFontMetrics() { // Should not be dropped by stylo
--- a/gfx/src/nsRect.cpp +++ b/gfx/src/nsRect.cpp @@ -40,24 +40,24 @@ bool nsRect::Overflows() const { FILE* operator<<(FILE* out, const nsRect& rect) { nsAutoString tmp; // Output the coordinates in fractional pixels so they're easier to read tmp.Append('{'); tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.X(), - nsDeviceContext::AppUnitsPerCSSPixel())); + AppUnitsPerCSSPixel())); tmp.AppendLiteral(", "); tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.Y(), - nsDeviceContext::AppUnitsPerCSSPixel())); + AppUnitsPerCSSPixel())); tmp.AppendLiteral(", "); tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.Width(), - nsDeviceContext::AppUnitsPerCSSPixel())); + AppUnitsPerCSSPixel())); tmp.AppendLiteral(", "); tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.Height(), - nsDeviceContext::AppUnitsPerCSSPixel())); + AppUnitsPerCSSPixel())); tmp.Append('}'); fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out); return out; } #endif // DEBUG
--- a/gfx/thebes/gfxFontMissingGlyphs.cpp +++ b/gfx/thebes/gfxFontMissingGlyphs.cpp @@ -254,17 +254,17 @@ gfxFontMissingGlyphs::DrawMissingGlyph(u #ifndef MOZ_GFX_OPTIMIZE_MOBILE Point center = rect.Center(); Float halfGap = HEX_CHAR_GAP / 2.f; Float top = -(MINIFONT_HEIGHT + halfGap); // We always want integer scaling, otherwise the "bitmap" glyphs will look // even uglier than usual when zoomed int32_t devPixelsPerCSSPx = - std::max<int32_t>(1, nsDeviceContext::AppUnitsPerCSSPixel() / + std::max<int32_t>(1, AppUnitsPerCSSPixel() / aAppUnitsPerDevPixel); Matrix tempMat; if (aMat) { // If there is an orientation transform, since draw target transforms may // not be supported, scale and translate it so that it can be directly used // for rendering the mini font without changing the draw target transform. tempMat = Matrix(*aMat).PostScale(devPixelsPerCSSPx, devPixelsPerCSSPx) @@ -332,11 +332,11 @@ gfxFontMissingGlyphs::GetDesiredMinWidth * like this so you can see what goes where. */ Float width = BOX_HORIZONTAL_INSET + BOX_BORDER_WIDTH + HEX_CHAR_GAP + MINIFONT_WIDTH + HEX_CHAR_GAP + MINIFONT_WIDTH + ((aChar < 0x10000) ? 0 : HEX_CHAR_GAP + MINIFONT_WIDTH) + HEX_CHAR_GAP + BOX_BORDER_WIDTH + BOX_HORIZONTAL_INSET; // Note that this will give us floating-point division, so the width will // -not- be snapped to integer multiples of its basic pixel value - width *= Float(nsDeviceContext::AppUnitsPerCSSPixel()) / aAppUnitsPerDevPixel; + width *= Float(AppUnitsPerCSSPixel()) / aAppUnitsPerDevPixel; return width; }
--- a/image/ClippedImage.cpp +++ b/image/ClippedImage.cpp @@ -148,17 +148,17 @@ ClippedImage::ClippedImage(Image* aImage : ImageWrapper(aImage) , mClip(aClip) { MOZ_ASSERT(aImage != nullptr, "ClippedImage requires an existing Image"); MOZ_ASSERT_IF(aSVGViewportSize, aImage->GetType() == imgIContainer::TYPE_VECTOR); if (aSVGViewportSize) { mSVGViewportSize = Some(aSVGViewportSize->ToNearestPixels( - nsPresContext::AppUnitsPerCSSPixel())); + AppUnitsPerCSSPixel())); } } ClippedImage::~ClippedImage() { } bool ClippedImage::ShouldClip()
--- a/image/ImageCacheKey.cpp +++ b/image/ImageCacheKey.cpp @@ -3,23 +3,23 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ImageCacheKey.h" #include "mozilla/HashFunctions.h" #include "mozilla/Move.h" #include "nsContentUtils.h" +#include "nsICookieService.h" #include "nsLayoutUtils.h" #include "nsString.h" #include "mozilla/AntiTrackingCommon.h" #include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/File.h" #include "mozilla/dom/ServiceWorkerManager.h" -#include "mozilla/StaticPrefs.h" #include "nsIDocument.h" #include "nsPrintfCString.h" namespace mozilla { using namespace dom; namespace image { @@ -136,39 +136,33 @@ ImageCacheKey::GetSpecialCaseDocumentTok // For controlled documents, we cast the pointer into a void* to avoid // dereferencing it (since we only use it for comparisons). RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); if (swm && aDocument->GetController().isSome()) { return aDocument; } - // We want to have a unique image cache if the anti-tracking feature is - // enabled for 3rd party resources. - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled() || - !nsContentUtils::IsThirdPartyWindowOrChannel(aDocument->GetInnerWindow(), - nullptr, aURI)) { - return nullptr; - } - - // If the window is 3rd party resource, let's see if the first party storage - // access is granted for this image. - if (nsContentUtils::IsTrackingResourceWindow(aDocument->GetInnerWindow())) { - return nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(), - nullptr, aURI) - ? aDocument : nullptr; + // If we must disable the storage, we want to create a unique cache key for + // this image. + if (nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(), + nullptr, + aDocument->NodePrincipal(), + aURI)) { + return aDocument; } // Another scenario is if this image is a 3rd party resource loaded by a // first party context. In this case, we should check if the nsIChannel has // been marked as tracking resource, but we don't have the channel yet at // this point. The best approach here is to be conservative: if we are sure // that the permission is granted, let's return a nullptr. Otherwise, let's // make a unique image cache. - if (!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(), + if (!aDocument->IsCookieAverse() && + !AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(), aURI)) { return aDocument; } return nullptr; } } // namespace image
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -10173,15 +10173,19 @@ GeneralParser<ParseHandler, CharT>::expr PossibleError* possibleError /* = nullptr */) { MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lp)); return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked); } template class PerHandlerParser<FullParseHandler>; template class PerHandlerParser<SyntaxParseHandler>; +template class GeneralParser<FullParseHandler, Utf8Unit>; +template class GeneralParser<SyntaxParseHandler, Utf8Unit>; template class GeneralParser<FullParseHandler, char16_t>; template class GeneralParser<SyntaxParseHandler, char16_t>; +template class Parser<FullParseHandler, Utf8Unit>; +template class Parser<SyntaxParseHandler, Utf8Unit>; template class Parser<FullParseHandler, char16_t>; template class Parser<SyntaxParseHandler, char16_t>; } /* namespace frontend */ } /* namespace js */
--- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -1415,16 +1415,27 @@ if test -n "$MOZ_OPTIMIZE"; then [printf("Hello World\n");], _results=yes, _results=no) AC_MSG_RESULT([$_results]) if test "$_results" = "no"; then AC_MSG_ERROR([These compiler flags are invalid: $MOZ_OPTIMIZE_FLAGS]) fi CFLAGS=$_SAVE_CFLAGS + if test -n "$MOZ_LTO" -a -n "$CLANG_CC"; then + # When using llvm-based LTO, non numeric optimization levels are + # not supported by the linker, so force the linker to use -O2 ( + # which doesn't influence the level compilation units are actually + # compiled at). + case " $MOZ_OPTIMIZE_FLAGS " in + *\ -Os\ *|*\ -Oz\ *) + MOZ_OPTIMIZE_LDFLAGS="$MOZ_OPTIMIZE_LDFLAGS -O2" + ;; + esac + fi fi fi # COMPILE_ENVIRONMENT AC_SUBST_LIST(MOZ_FRAMEPTR_FLAGS) AC_SUBST_LIST(MOZ_OPTIMIZE_FLAGS) AC_SUBST_LIST(MOZ_OPTIMIZE_LDFLAGS) AC_SUBST_LIST(MOZ_PGO_OPTIMIZE_FLAGS)
--- a/layout/base/AccessibleCaretEventHub.cpp +++ b/layout/base/AccessibleCaretEventHub.cpp @@ -614,17 +614,17 @@ AccessibleCaretEventHub::HandleKeyboardE return nsEventStatus_eIgnore; } bool AccessibleCaretEventHub::MoveDistanceIsLarge(const nsPoint& aPoint) const { nsPoint delta = aPoint - mPressPoint; return NS_hypot(delta.x, delta.y) > - nsPresContext::AppUnitsPerCSSPixel() * kMoveStartToleranceInPixel; + AppUnitsPerCSSPixel() * kMoveStartToleranceInPixel; } void AccessibleCaretEventHub::LaunchLongTapInjector() { if (!mLongTapInjectorTimer) { return; }
--- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -4674,17 +4674,17 @@ PresShell::RenderDocument(const nsRect& MOZ_ASSERT(aThebesContext->CurrentOp() == CompositionOp::OP_OVER); aThebesContext->Clip(); nsDeviceContext* devCtx = mPresContext->DeviceContext(); gfxPoint offset(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x), -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y)); - gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel(); + gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/AppUnitsPerCSSPixel(); // Since canvas APIs use floats to set up their matrices, we may have some // slight rounding errors here. We use NudgeToIntegers() here to adjust // matrix components that are integers up to the accuracy of floats to be // those integers. gfxMatrix newTM = aThebesContext->CurrentMatrixDouble().PreTranslate(offset). PreScale(scale, scale). NudgeToIntegers(); @@ -5068,17 +5068,17 @@ PresShell::PaintRangePaintInfo(const nsT RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt); MOZ_ASSERT(ctx); // already checked the draw target above if (aRegion) { RefPtr<PathBuilder> builder = dt->CreatePathBuilder(FillRule::FILL_WINDING); // Convert aRegion from CSS pixels to dev pixels nsIntRegion region = - aRegion->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel()) + aRegion->ToAppUnits(AppUnitsPerCSSPixel()) .ToOutsidePixels(pc->AppUnitsPerDevPixel()); for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) { const IntRect& rect = iter.Get(); builder->MoveTo(rect.TopLeft()); builder->LineTo(rect.TopRight()); builder->LineTo(rect.BottomRight()); builder->LineTo(rect.BottomLeft()); @@ -5163,17 +5163,17 @@ PresShell::RenderNode(nsINode* aNode, return nullptr; } Maybe<CSSIntRegion> region = aRegion; if (region) { // combine the area with the supplied region CSSIntRect rrectPixels = region->GetBounds(); - nsRect rrect = ToAppUnits(rrectPixels, nsPresContext::AppUnitsPerCSSPixel()); + nsRect rrect = ToAppUnits(rrectPixels, AppUnitsPerCSSPixel()); area.IntersectRect(area, rrect); nsPresContext* pc = GetPresContext(); if (!pc) return nullptr; // move the region so that it is offset from the topleft corner of the surface region->MoveBy(-nsPresContext::AppUnitsToIntCSSPixels(area.x),
--- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -3923,17 +3923,17 @@ nsDocumentViewer::Print(nsIPrintSettings // Release()'d in Destroy(). Therefore, we need to grab the instance with // a local variable, so that it won't be deleted during its own method. RefPtr<nsPrintJob> printJob = mPrintJob; if (!printJob) { NS_ENSURE_STATE(mDeviceContext); printJob = new nsPrintJob(); rv = printJob->Initialize(this, mContainer, mDocument, - float(mDeviceContext->AppUnitsPerCSSInch()) / + float(AppUnitsPerCSSInch()) / float(mDeviceContext->AppUnitsPerDevPixel()) / mPageZoom); if (NS_FAILED(rv)) { printJob->Destroy(); return rv; } mPrintJob = printJob; } @@ -4007,17 +4007,17 @@ nsDocumentViewer::PrintPreview(nsIPrintS // Our call to nsPrintJob::PrintPreview() may cause mPrintJob to be // Release()'d in Destroy(). Therefore, we need to grab the instance with // a local variable, so that it won't be deleted during its own method. RefPtr<nsPrintJob> printJob = mPrintJob; if (!printJob) { printJob = new nsPrintJob(); rv = printJob->Initialize(this, mContainer, doc, - float(mDeviceContext->AppUnitsPerCSSInch()) / + float(AppUnitsPerCSSInch()) / float(mDeviceContext->AppUnitsPerDevPixel()) / mPageZoom); if (NS_FAILED(rv)) { printJob->Destroy(); return rv; } mPrintJob = printJob; }
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -6882,17 +6882,17 @@ nsLayoutUtils::DrawSingleImage(gfxContex const SamplingFilter aSamplingFilter, const nsRect& aDest, const nsRect& aDirty, const Maybe<SVGImageContext>& aSVGContext, uint32_t aImageFlags, const nsPoint* aAnchorPoint, const nsRect* aSourceArea) { - nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel(); + nscoord appUnitsPerCSSPixel = AppUnitsPerCSSPixel(); CSSIntSize pixelImageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size())); if (pixelImageSize.width < 1 || pixelImageSize.height < 1) { NS_ASSERTION(pixelImageSize.width >= 0 && pixelImageSize.height >= 0, "Image width or height is negative"); return ImgDrawResult::SUCCESS; // no point in drawing a zero size image } nsSize imageSize(CSSPixel::ToAppUnits(pixelImageSize)); @@ -9845,17 +9845,17 @@ ComputeSVGReferenceRect(nsIFrame* aFrame switch (aGeometryBox) { case StyleGeometryBox::StrokeBox: { // XXX Bug 1299876 // The size of srtoke-box is not correct if this graphic element has // specific stroke-linejoin or stroke-linecap. gfxRect bbox = nsSVGUtils::GetBBox(aFrame, nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeStroke); r = nsLayoutUtils::RoundGfxRectToAppRect(bbox, - nsPresContext::AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); break; } case StyleGeometryBox::ViewBox: { nsIContent* content = aFrame->GetContent(); nsSVGElement* element = static_cast<nsSVGElement*>(content); SVGViewportElement* svgElement = element->GetCtx(); MOZ_ASSERT(svgElement); @@ -9887,25 +9887,25 @@ ComputeSVGReferenceRect(nsIFrame* aFrame case StyleGeometryBox::BorderBox: case StyleGeometryBox::ContentBox: case StyleGeometryBox::PaddingBox: case StyleGeometryBox::MarginBox: case StyleGeometryBox::FillBox: { gfxRect bbox = nsSVGUtils::GetBBox(aFrame, nsSVGUtils::eBBoxIncludeFill); r = nsLayoutUtils::RoundGfxRectToAppRect(bbox, - nsPresContext::AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); break; } default:{ MOZ_ASSERT_UNREACHABLE("unknown StyleGeometryBox type"); gfxRect bbox = nsSVGUtils::GetBBox(aFrame, nsSVGUtils::eBBoxIncludeFill); r = nsLayoutUtils::RoundGfxRectToAppRect(bbox, - nsPresContext::AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); break; } } return r; } static nsRect @@ -10079,17 +10079,17 @@ nsLayoutUtils::ApplyMinFontSize(nsStyleF /* static */ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, LookAndFeel::FontID aFontID, const nsPresContext* aPresContext, const nsFont* aDefaultVariableFont) { gfxFontStyle fontStyle; float devPerCSS = - (float)nsPresContext::AppUnitsPerCSSPixel() / + (float)AppUnitsPerCSSPixel() / aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom(); nsAutoString systemFontName; if (LookAndFeel::GetFont(aFontID, systemFontName, fontStyle, devPerCSS)) { systemFontName.Trim("\"'"); aSystemFont->fontlist = FontFamilyList(systemFontName, eUnquotedName); aSystemFont->fontlist.SetDefaultFontType(eFamily_none); aSystemFont->style = fontStyle.style; aSystemFont->systemFont = fontStyle.systemFont;
--- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -653,39 +653,37 @@ public: * * If |aChanged| is non-null, then aChanged is filled in with whether * the screen size value has changed since either: * a. the last time the function was called with non-null aChanged, or * b. the first time the function was called. */ gfxSize ScreenSizeInchesForFontInflation(bool* aChanged = nullptr); - static int32_t AppUnitsPerCSSPixel() { return mozilla::AppUnitsPerCSSPixel(); } int32_t AppUnitsPerDevPixel() const; - static int32_t AppUnitsPerCSSInch() { return mozilla::AppUnitsPerCSSInch(); } static nscoord CSSPixelsToAppUnits(int32_t aPixels) { return NSToCoordRoundWithClamp(float(aPixels) * - float(AppUnitsPerCSSPixel())); } + float(mozilla::AppUnitsPerCSSPixel())); } static nscoord CSSPixelsToAppUnits(float aPixels) { return NSToCoordRoundWithClamp(aPixels * - float(AppUnitsPerCSSPixel())); } + float(mozilla::AppUnitsPerCSSPixel())); } static int32_t AppUnitsToIntCSSPixels(nscoord aAppUnits) { return NSAppUnitsToIntPixels(aAppUnits, - float(AppUnitsPerCSSPixel())); } + float(mozilla::AppUnitsPerCSSPixel())); } static float AppUnitsToFloatCSSPixels(nscoord aAppUnits) { return NSAppUnitsToFloatPixels(aAppUnits, - float(AppUnitsPerCSSPixel())); } + float(mozilla::AppUnitsPerCSSPixel())); } static double AppUnitsToDoubleCSSPixels(nscoord aAppUnits) { return NSAppUnitsToDoublePixels(aAppUnits, - double(AppUnitsPerCSSPixel())); } + double(mozilla::AppUnitsPerCSSPixel())); } nscoord DevPixelsToAppUnits(int32_t aPixels) const { return NSIntPixelsToAppUnits(aPixels, AppUnitsPerDevPixel()); } int32_t AppUnitsToDevPixels(nscoord aAppUnits) const { return NSAppUnitsToIntPixels(aAppUnits, float(AppUnitsPerDevPixel())); } @@ -705,17 +703,17 @@ public: { return AppUnitsToIntCSSPixels(DevPixelsToAppUnits(aPixels)); } float DevPixelsToFloatCSSPixels(int32_t aPixels) { return AppUnitsToFloatCSSPixels(DevPixelsToAppUnits(aPixels)); } mozilla::CSSToLayoutDeviceScale CSSToDevPixelScale() const { return mozilla::CSSToLayoutDeviceScale( - float(AppUnitsPerCSSPixel()) / float(AppUnitsPerDevPixel())); + float(mozilla::AppUnitsPerCSSPixel()) / float(AppUnitsPerDevPixel())); } // If there is a remainder, it is rounded to nearest app units. nscoord GfxUnitsToAppUnits(gfxFloat aGfxUnits) const; gfxFloat AppUnitsToGfxUnits(nscoord aAppUnits) const; gfxRect AppUnitsToGfxUnits(const nsRect& aAppRect) const
--- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -6827,17 +6827,17 @@ nsIFrame::GetTransformMatrix(const nsIFr * shift us to our parent. */ if (IsTransformed()) { /* Compute the delta to the parent, which we need because we are converting * coordinates to our parent. */ NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this), "Cannot transform the viewport frame!"); - int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? PresContext()->AppUnitsPerCSSPixel() + int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? AppUnitsPerCSSPixel() : PresContext()->AppUnitsPerDevPixel()); Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0,0), scaleFactor, nsDisplayTransform::INCLUDE_PERSPECTIVE|nsDisplayTransform::OFFSET_BY_ORIGIN, nullptr); *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this); nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor); @@ -6917,17 +6917,17 @@ nsIFrame::GetTransformMatrix(const nsIFr } NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?"); /* Translate from this frame to our ancestor, if it exists. That's the * entire transform, so we're done. */ nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor); - int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? PresContext()->AppUnitsPerCSSPixel() + int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? AppUnitsPerCSSPixel() : PresContext()->AppUnitsPerDevPixel()); return Matrix4x4::Translation(NSAppUnitsToFloatPixels(delta.x, scaleFactor), NSAppUnitsToFloatPixels(delta.y, scaleFactor), 0.0f); } static void InvalidateRenderingObservers(nsIFrame* aDisplayRoot, nsIFrame* aFrame, bool aFrameChanged = true) {
--- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -2857,19 +2857,19 @@ ScrollFrameHelper::ScrollToImpl(nsPoint } bool needFrameVisibilityUpdate = mLastUpdateFramesPos == nsPoint(-1,-1); nsPoint dist(std::abs(pt.x - mLastUpdateFramesPos.x), std::abs(pt.y - mLastUpdateFramesPos.y)); nsSize visualViewportSize = GetVisualViewportSize(); nscoord horzAllowance = std::max(visualViewportSize.width / std::max(sHorzScrollFraction, 1), - nsPresContext::AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); nscoord vertAllowance = std::max(visualViewportSize.height / std::max(sVertScrollFraction, 1), - nsPresContext::AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); if (dist.x >= horzAllowance || dist.y >= vertAllowance) { needFrameVisibilityUpdate = true; } // notify the listeners. for (uint32_t i = 0; i < mListeners.Length(); i++) { mListeners[i]->ScrollPositionWillChange(pt.x, pt.y); }
--- a/layout/painting/ActiveLayerTracker.cpp +++ b/layout/painting/ActiveLayerTracker.cpp @@ -258,17 +258,17 @@ IncrementScaleRestyleCountIfNeeded(nsIFr } // Compute the new scale due to the CSS transform property. bool dummyBool; nsStyleTransformMatrix::TransformReferenceBox refBox(aFrame); Matrix4x4 transform = nsStyleTransformMatrix::ReadTransforms(transformList->mHead, refBox, - nsPresContext::AppUnitsPerCSSPixel(), + AppUnitsPerCSSPixel(), &dummyBool); Matrix transform2D; if (!transform.Is2D(&transform2D)) { // We don't attempt to handle 3D transforms; just assume the scale changed. aActivity->mPreviousTransformScale = Nothing(); IncrementMutationCount(&aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]); return; }
--- a/layout/painting/nsCSSRenderingBorders.cpp +++ b/layout/painting/nsCSSRenderingBorders.cpp @@ -3648,17 +3648,17 @@ nsCSSBorderImageRenderer::DrawBorderImag fillStyleV = StyleBorderImageRepeat::Stretch; } nsRect destArea(borderX[i], borderY[j], borderWidth[i], borderHeight[j]); nsRect subArea(sliceX[i], sliceY[j], sliceWidth[i], sliceHeight[j]); if (subArea.IsEmpty()) continue; - nsIntRect intSubArea = subArea.ToOutsidePixels(nsPresContext::AppUnitsPerCSSPixel()); + nsIntRect intSubArea = subArea.ToOutsidePixels(AppUnitsPerCSSPixel()); result &= mImageRenderer.DrawBorderImageComponent(aPresContext, aRenderingContext, aDirtyRect, destArea, CSSIntRect(intSubArea.x, intSubArea.y, intSubArea.width, intSubArea.height), fillStyleH, fillStyleV,
--- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -7924,34 +7924,34 @@ nsDisplayTransform::GetResultingTransfor &parentsChildrenOnlyTransform); /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */ if (aProperties.mTransformList) { result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead, refBox, aAppUnitsPerPixel, &dummyBool); } else if (hasSVGTransforms) { // Correct the translation components for zoom: - float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() / + float pixelsPerCSSPx = AppUnitsPerCSSPixel() / aAppUnitsPerPixel; svgTransform._31 *= pixelsPerCSSPx; svgTransform._32 *= pixelsPerCSSPx; result = Matrix4x4::From2D(svgTransform); } // Apply any translation due to 'transform-origin' and/or 'transform-box': result.ChangeBasis(aProperties.mToTransformOrigin); // See the comment for nsSVGContainerFrame::HasChildrenOnlyTransform for // an explanation of what children-only transforms are. bool parentHasChildrenOnlyTransform = hasSVGTransforms && !parentsChildrenOnlyTransform.IsIdentity(); if (parentHasChildrenOnlyTransform) { float pixelsPerCSSPx = - frame->PresContext()->AppUnitsPerCSSPixel() / aAppUnitsPerPixel; + AppUnitsPerCSSPixel() / aAppUnitsPerPixel; parentsChildrenOnlyTransform._31 *= pixelsPerCSSPx; parentsChildrenOnlyTransform._32 *= pixelsPerCSSPx; Point3D frameOffset( NSAppUnitsToFloatPixels(-frame->GetPosition().x, aAppUnitsPerPixel), NSAppUnitsToFloatPixels(-frame->GetPosition().y, aAppUnitsPerPixel), 0); Matrix4x4 parentsChildrenOnlyTransform3D = @@ -8104,17 +8104,17 @@ nsDisplayTransform::ShouldPrerenderTrans *aDirtyRect = overflow; return FullPrerender; } else if (gfxPrefs::PartiallyPrerenderAnimatedContent()) { *aDirtyRect = nsLayoutUtils::ComputePartialPrerenderArea(*aDirtyRect, overflow, maxSize); return PartialPrerender; } if (frameArea > maxLimitArea) { - uint64_t appUnitsPerPixel = nsPresContext::AppUnitsPerCSSPixel(); + uint64_t appUnitsPerPixel = AppUnitsPerCSSPixel(); EffectCompositor::SetPerformanceWarning( aFrame, eCSSProperty_transform, AnimationPerformanceWarning( AnimationPerformanceWarning::Type::ContentTooLargeArea, { int(frameArea / (appUnitsPerPixel * appUnitsPerPixel)), int(maxLimitArea / (appUnitsPerPixel * appUnitsPerPixel)), }));
--- a/layout/painting/nsImageRenderer.cpp +++ b/layout/painting/nsImageRenderer.cpp @@ -378,23 +378,23 @@ nsImageRenderer::ComputeConstrainedSize( float scaleY = double(aConstrainingSize.height) / aIntrinsicRatio.height; nsSize size; if ((aFitType == CONTAIN) == (scaleX < scaleY)) { size.width = aConstrainingSize.width; size.height = NSCoordSaturatingNonnegativeMultiply( aIntrinsicRatio.height, scaleX); // If we're reducing the size by less than one css pixel, then just use the // constraining size. - if (aFitType == CONTAIN && aConstrainingSize.height - size.height < nsPresContext::AppUnitsPerCSSPixel()) { + if (aFitType == CONTAIN && aConstrainingSize.height - size.height < AppUnitsPerCSSPixel()) { size.height = aConstrainingSize.height; } } else { size.width = NSCoordSaturatingNonnegativeMultiply( aIntrinsicRatio.width, scaleY); - if (aFitType == CONTAIN && aConstrainingSize.width - size.width < nsPresContext::AppUnitsPerCSSPixel()) { + if (aFitType == CONTAIN && aConstrainingSize.width - size.width < AppUnitsPerCSSPixel()) { size.width = aConstrainingSize.width; } size.height = aConstrainingSize.height; } return size; } /**
--- a/layout/printing/nsPrintJob.cpp +++ b/layout/printing/nsPrintJob.cpp @@ -1694,17 +1694,17 @@ nsPrintJob::ReconstructAndReflow(bool do "mPresContext and mPresShell shouldn't be nullptr when the print object " "has been marked as \"print the document\""); UpdateZoomRatio(po, doSetPixelScale); po->mPresContext->SetPageScale(po->mZoomRatio); // Calculate scale factor from printer to screen - float printDPI = float(printData->mPrintDC->AppUnitsPerCSSInch()) / + float printDPI = float(AppUnitsPerCSSInch()) / float(printData->mPrintDC->AppUnitsPerDevPixel()); po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI); po->mPresShell->ReconstructFrames(); // If the printing was canceled or restarted with different data, // let's stop doing this printing. if (NS_WARN_IF(mPrt != printData)) { @@ -2383,17 +2383,17 @@ nsPrintJob::ReflowPrintObject(const Uniq aPO->mPresShell->BeginObservingDocument(); aPO->mPresContext->SetPageSize(adjSize); aPO->mPresContext->SetVisibleArea(nsRect(0, 0, adjSize.width, adjSize.height)); aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel); aPO->mPresContext->SetPageScale(aPO->mZoomRatio); // Calculate scale factor from printer to screen - float printDPI = float(printData->mPrintDC->AppUnitsPerCSSInch()) / + float printDPI = float(AppUnitsPerCSSInch()) / float(printData->mPrintDC->AppUnitsPerDevPixel()); aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI); if (mIsCreatingPrintPreview && documentIsTopLevel) { mDocViewerPrint->SetPrintPreviewPresentation(aPO->mViewManager, aPO->mPresContext, aPO->mPresShell); }
--- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -290,17 +290,17 @@ GetResolution(nsIDocument* aDocument, co float dppx = 1.; if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) { if (nsContentUtils::ShouldResistFingerprinting(aDocument)) { dppx = dx->GetFullZoom(); } else { // Get the actual device pixel ratio, which also takes zoom into account. dppx = - float(nsPresContext::AppUnitsPerCSSPixel()) / dx->AppUnitsPerDevPixel(); + float(AppUnitsPerCSSPixel()) / dx->AppUnitsPerDevPixel(); } } aResult.SetFloatValue(dppx, eCSSUnit_Pixel); } static void GetScan(nsIDocument* aDocument, const nsMediaFeature*,
--- a/layout/style/nsROCSSPrimitiveValue.cpp +++ b/layout/style/nsROCSSPrimitiveValue.cpp @@ -259,45 +259,41 @@ nsROCSSPrimitiveValue::GetFloatValue(uin case CSS_PX: if (mType == CSS_PX) { return nsPresContext::AppUnitsToFloatCSSPixels(mValue.mAppUnits); } break; case CSS_CM: if (mType == CSS_PX) { - return mValue.mAppUnits * CM_PER_INCH_FLOAT / - nsPresContext::AppUnitsPerCSSInch(); + return mValue.mAppUnits * CM_PER_INCH_FLOAT / AppUnitsPerCSSInch(); } break; case CSS_MM: if (mType == CSS_PX) { - return mValue.mAppUnits * MM_PER_INCH_FLOAT / - nsPresContext::AppUnitsPerCSSInch(); + return mValue.mAppUnits * MM_PER_INCH_FLOAT / AppUnitsPerCSSInch(); } break; case CSS_IN: if (mType == CSS_PX) { - return mValue.mAppUnits / nsPresContext::AppUnitsPerCSSInch(); + return mValue.mAppUnits / AppUnitsPerCSSInch(); } break; case CSS_PT: if (mType == CSS_PX) { - return mValue.mAppUnits * POINTS_PER_INCH_FLOAT / - nsPresContext::AppUnitsPerCSSInch(); + return mValue.mAppUnits * POINTS_PER_INCH_FLOAT / AppUnitsPerCSSInch(); } break; case CSS_PC: if (mType == CSS_PX) { - return mValue.mAppUnits * 6.0f / - nsPresContext::AppUnitsPerCSSInch(); + return mValue.mAppUnits * 6.0f / AppUnitsPerCSSInch(); } break; case CSS_PERCENTAGE: if (mType == CSS_PERCENTAGE) { return mValue.mFloat * 100; }
--- a/layout/style/nsStyleTransformMatrix.cpp +++ b/layout/style/nsStyleTransformMatrix.cpp @@ -168,23 +168,23 @@ ProcessTranslatePart(const nsCSSValue& a } else { // Note: The unit of nsCSSValue passed from Servo side would be number, // pixel, percent, or eCSSUnit_Calc, so it is impossible to go into // this branch. MOZ_CRASH("unexpected unit in ProcessTranslatePart"); } float translation = - NSAppUnitsToFloatPixels(offset, nsPresContext::AppUnitsPerCSSPixel()); + NSAppUnitsToFloatPixels(offset, AppUnitsPerCSSPixel()); // We want to avoid calling aDimensionGetter if there's no percentage to be // resolved (for performance reasons - see TransformReferenceBox). if (percent != 0.0f && aRefBox && !aRefBox->IsEmpty()) { translation += percent * NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(), - nsPresContext::AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); } return translation; } /** * Helper functions to process all the transformation function types. * * These take a matrix parameter to accumulate the current matrix. @@ -503,17 +503,17 @@ ProcessMatrixOperator(Matrix4x4& aMatrix list = nullptr; } Matrix4x4 matrix; if (!list) { return matrix; } - float appUnitPerCSSPixel = nsPresContext::AppUnitsPerCSSPixel(); + float appUnitPerCSSPixel = AppUnitsPerCSSPixel(); matrix = nsStyleTransformMatrix::ReadTransforms(list, aRefBox, appUnitPerCSSPixel, aContains3dTransform); return matrix; }; Matrix4x4 matrix1 = readTransform(aData->Item(1)); @@ -946,17 +946,17 @@ ReadTransforms(const nsCSSValueList* aLi NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1, "Incoming function is too short!"); /* Read in a single transform matrix. */ MatrixForTransformFunction(result, currElem.GetArrayValue(), aRefBox, aContains3dTransform); } - float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit; + float scale = float(AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit; result.PreScale(1/scale, 1/scale, 1/scale); result.PostScale(scale, scale, scale); return result; } Point Convert2DPosition(nsStyleCoord const (&aValue)[2],
--- a/layout/svg/SVGGeometryFrame.cpp +++ b/layout/svg/SVGGeometryFrame.cpp @@ -97,17 +97,17 @@ nsDisplaySVGGeometry::HitTest(nsDisplayL { SVGGeometryFrame *frame = static_cast<SVGGeometryFrame*>(mFrame); nsPoint pointRelativeToReferenceFrame = aRect.Center(); // ToReferenceFrame() includes frame->GetPosition(), our user space position. nsPoint userSpacePtInAppUnits = pointRelativeToReferenceFrame - (ToReferenceFrame() - frame->GetPosition()); gfxPoint userSpacePt = gfxPoint(userSpacePtInAppUnits.x, userSpacePtInAppUnits.y) / - frame->PresContext()->AppUnitsPerCSSPixel(); + AppUnitsPerCSSPixel(); if (frame->GetFrameForPoint(userSpacePt)) { aOutFrames->AppendElement(frame); } } void nsDisplaySVGGeometry::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) @@ -317,17 +317,17 @@ SVGGeometryFrame::GetFrameForPoint(const fillRule = nsSVGUtils::ToFillRule(StyleSVG()->mClipRule); } else { hitTestFlags = GetHitTestFlags(); if (!hitTestFlags) { return nullptr; } if (hitTestFlags & SVG_HIT_TEST_CHECK_MRECT) { gfxRect rect = - nsLayoutUtils::RectToGfxRect(mRect, PresContext()->AppUnitsPerCSSPixel()); + nsLayoutUtils::RectToGfxRect(mRect, AppUnitsPerCSSPixel()); if (!rect.Contains(aPoint)) { return nullptr; } } fillRule = nsSVGUtils::ToFillRule(StyleSVG()->mFillRule); } bool isHit = false; @@ -398,17 +398,17 @@ SVGGeometryFrame::ReflowSVG() flags |= nsSVGUtils::eBBoxIncludeFillGeometry; } if ((hitTestFlags & SVG_HIT_TEST_STROKE)) { flags |= nsSVGUtils::eBBoxIncludeStrokeGeometry; } gfxRect extent = GetBBoxContribution(Matrix(), flags).ToThebesRect(); mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, - PresContext()->AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); if (mState & NS_FRAME_FIRST_REFLOW) { // Make sure we have our filter property (if any) before calling // FinishAndStoreOverflow (subsequent filter changes are handled off // nsChangeHint_UpdateEffects): SVGObserverUtils::UpdateEffects(this); } @@ -473,17 +473,17 @@ SVGGeometryFrame::GetBBoxContribution(co if (aToBBoxUserspace.IsSingular()) { // XXX ReportToConsole return bbox; } if ((aFlags & nsSVGUtils::eForGetClientRects) && aToBBoxUserspace.PreservesAxisAlignedRectangles()) { - Rect rect = NSRectToRect(mRect, PresContext()->AppUnitsPerCSSPixel()); + Rect rect = NSRectToRect(mRect, AppUnitsPerCSSPixel()); bbox = aToBBoxUserspace.TransformBounds(rect); return bbox; } SVGGeometryElement* element = static_cast<SVGGeometryElement*>(GetContent()); bool getFill = (aFlags & nsSVGUtils::eBBoxIncludeFillGeometry) ||
--- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -345,17 +345,17 @@ GetBaselinePosition(nsTextFrame* aFrame, return writingMode.IsVerticalRL() ? metrics.mAscent + metrics.mDescent - aFrame->GetLogicalBaseline(writingMode) : aFrame->GetLogicalBaseline(writingMode); case NS_STYLE_DOMINANT_BASELINE_MIDDLE: return aFrame->GetLogicalBaseline(writingMode) - SVGContentUtils::GetFontXHeight(aFrame) / 2.0 * - aFrame->PresContext()->AppUnitsPerCSSPixel() * aFontSizeScaleFactor; + AppUnitsPerCSSPixel() * aFontSizeScaleFactor; case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE: case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC: return writingMode.IsVerticalLR() ? 0 : metrics.mAscent + metrics.mDescent; case NS_STYLE_DOMINANT_BASELINE_CENTRAL: case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL: @@ -883,17 +883,17 @@ TextRenderedRun::GetTransformFromRunUser return m; } nscoord start, end; GetClipEdges(start, end); // Translate by the horizontal distance into the text frame this // rendered run is. - gfxFloat appPerCssPx = nsPresContext::AppUnitsPerCSSPixel(); + gfxFloat appPerCssPx = AppUnitsPerCSSPixel(); gfxPoint t = IsVertical() ? gfxPoint(0, start / appPerCssPx) : gfxPoint(start / appPerCssPx, 0); return m.PreTranslate(t); } SVGBBox TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext, uint32_t aFlags) const @@ -3106,17 +3106,17 @@ nsDisplaySVGText::HitTest(nsDisplayListB SVGTextFrame *frame = static_cast<SVGTextFrame*>(mFrame); nsPoint pointRelativeToReferenceFrame = aRect.Center(); // ToReferenceFrame() includes frame->GetPosition(), our user space position. nsPoint userSpacePtInAppUnits = pointRelativeToReferenceFrame - (ToReferenceFrame() - frame->GetPosition()); gfxPoint userSpacePt = gfxPoint(userSpacePtInAppUnits.x, userSpacePtInAppUnits.y) / - frame->PresContext()->AppUnitsPerCSSPixel(); + AppUnitsPerCSSPixel(); nsIFrame* target = frame->GetFrameForPoint(userSpacePt); if (target) { aOutFrames->AppendElement(target); } } void @@ -3807,17 +3807,17 @@ SVGTextFrame::ReflowSVG() r.UnionEdges(run.GetUserSpaceRect(presContext, runFlags)); } } if (r.IsEmpty()) { mRect.SetEmpty(); } else { mRect = - nsLayoutUtils::RoundGfxRectToAppRect(r.ToThebesRect(), nsPresContext::AppUnitsPerCSSPixel()); + nsLayoutUtils::RoundGfxRectToAppRect(r.ToThebesRect(), AppUnitsPerCSSPixel()); // Due to rounding issues when we have a transform applied, we sometimes // don't include an additional row of pixels. For now, just inflate our // covered region. mRect.Inflate(presContext->AppUnitsPerDevPixel()); } if (mState & NS_FRAME_FIRST_REFLOW) { @@ -3868,17 +3868,17 @@ TextRenderedRunFlagsForBBoxContribution( SVGBBox SVGTextFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace, uint32_t aFlags) { NS_ASSERTION(PrincipalChildList().FirstChild(), "must have a child frame"); SVGBBox bbox; if (aFlags & nsSVGUtils::eForGetClientRects) { - Rect rect = NSRectToRect(mRect, PresContext()->AppUnitsPerCSSPixel()); + Rect rect = NSRectToRect(mRect, AppUnitsPerCSSPixel()); if (!rect.IsEmpty()) { bbox = aToBBoxUserspace.TransformBounds(rect); } return bbox; } nsIFrame* kid = PrincipalChildList().FirstChild(); if (kid && NS_SUBTREE_DIRTY(kid)) { @@ -5678,17 +5678,17 @@ SVGTextFrame::TransformFramePointToTextC UpdateGlyphPositioning(); nsPresContext* presContext = PresContext(); // Add in the mRect offset to aPoint, as that will have been taken into // account when transforming the point from the ancestor frame down // to this one. float cssPxPerDevPx = nsPresContext::AppUnitsToFloatCSSPixels(presContext->AppUnitsPerDevPixel()); - float factor = nsPresContext::AppUnitsPerCSSPixel(); + float factor = AppUnitsPerCSSPixel(); Point framePosition(NSAppUnitsToFloatPixels(mRect.x, factor), NSAppUnitsToFloatPixels(mRect.y, factor)); Point pointInUserSpace = aPoint * cssPxPerDevPx + framePosition; // Find the closest rendered run for the text frames beneath aChildFrame. TextRenderedRunIterator it(this, TextRenderedRunIterator::eAllFrames, aChildFrame); TextRenderedRun hit; @@ -5785,17 +5785,17 @@ SVGTextFrame::TransformFrameRectFromText // Union it into the result. result.UnionRect(result, rectInUserSpace); } } // Subtract the mRect offset from the result, as our user space for // this frame is relative to the top-left of mRect. - float factor = nsPresContext::AppUnitsPerCSSPixel(); + float factor = AppUnitsPerCSSPixel(); gfxPoint framePosition(NSAppUnitsToFloatPixels(mRect.x, factor), NSAppUnitsToFloatPixels(mRect.y, factor)); return result - framePosition; } void SVGTextFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
--- a/layout/svg/nsCSSClipPathInstance.cpp +++ b/layout/svg/nsCSSClipPathInstance.cpp @@ -58,17 +58,17 @@ nsCSSClipPathInstance::HitTestBasicShape return false; } nsCSSClipPathInstance instance(aFrame, clipPathStyle); RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); RefPtr<Path> path = instance.CreateClipPath(drawTarget); - float pixelRatio = float(nsPresContext::AppUnitsPerCSSPixel()) / + float pixelRatio = float(AppUnitsPerCSSPixel()) / aFrame->PresContext()->AppUnitsPerDevPixel(); return path->ContainsPoint(ToPoint(aPoint) * pixelRatio, Matrix()); } /* static */ Rect nsCSSClipPathInstance::GetBoundingRectForBasicShapeClip(nsIFrame* aFrame, const StyleShapeSource& aClipPathStyle) {
--- a/layout/svg/nsFilterInstance.cpp +++ b/layout/svg/nsFilterInstance.cpp @@ -571,17 +571,17 @@ nsIntRect nsFilterInstance::FrameSpaceToFilterSpace(const nsRect* aRect) const { nsIntRect rect = OutputFilterSpaceBounds(); if (aRect) { if (aRect->IsEmpty()) { return nsIntRect(); } gfxRect rectInCSSPx = - nsLayoutUtils::RectToGfxRect(*aRect, nsPresContext::AppUnitsPerCSSPixel()); + nsLayoutUtils::RectToGfxRect(*aRect, AppUnitsPerCSSPixel()); gfxRect rectInFilterSpace = mFrameSpaceInCSSPxToFilterSpaceTransform.TransformBounds(rectInCSSPx); rectInFilterSpace.RoundOut(); nsIntRect intRect; if (gfxUtils::GfxRectToIntRect(rectInFilterSpace, &intRect)) { rect = intRect; } } @@ -592,17 +592,17 @@ nsRect nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRect& aRect) const { if (aRect.IsEmpty()) { return nsRect(); } gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height); r = mFilterSpaceToFrameSpaceInCSSPxTransform.TransformBounds(r); // nsLayoutUtils::RoundGfxRectToAppRect rounds out. - return nsLayoutUtils::RoundGfxRectToAppRect(r, nsPresContext::AppUnitsPerCSSPixel()); + return nsLayoutUtils::RoundGfxRectToAppRect(r, AppUnitsPerCSSPixel()); } nsIntRegion nsFilterInstance::FrameSpaceToFilterSpace(const nsRegion* aRegion) const { if (!aRegion) { return OutputFilterSpaceBounds(); }
--- a/layout/svg/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/nsSVGForeignObjectFrame.cpp @@ -233,17 +233,17 @@ nsSVGForeignObjectFrame::PaintSVG(gfxCon NS_ASSERTION(ok, "inverse of non-singular matrix should be non-singular"); gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height); transDirtyRect = invmatrix.TransformBounds(transDirtyRect); kidDirtyRect.IntersectRect(kidDirtyRect, nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect, - PresContext()->AppUnitsPerCSSPixel())); + AppUnitsPerCSSPixel())); // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect, // not with kidDirtyRect. I.e. // int32_t appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect) if (kidDirtyRect.IsEmpty()) return; } @@ -308,17 +308,17 @@ nsSVGForeignObjectFrame::GetFrameForPoin if (!gfxRect(x, y, width, height).Contains(aPoint) || !nsSVGUtils::HitTestClip(this, aPoint)) { return nullptr; } // Convert the point to app units relative to the top-left corner of the // viewport that's established by the foreignObject element: - gfxPoint pt = (aPoint + gfxPoint(x, y)) * nsPresContext::AppUnitsPerCSSPixel(); + gfxPoint pt = (aPoint + gfxPoint(x, y)) * AppUnitsPerCSSPixel(); nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y)); return nsLayoutUtils::GetFrameForPoint(kid, point); } void nsSVGForeignObjectFrame::ReflowSVG() { @@ -340,17 +340,17 @@ nsSVGForeignObjectFrame::ReflowSVG() GetAnimatedLengthValues(&x, &y, &w, &h, nullptr); // If mRect's width or height are negative, reflow blows up! We must clamp! if (w < 0.0f) w = 0.0f; if (h < 0.0f) h = 0.0f; mRect = nsLayoutUtils::RoundGfxRectToAppRect( gfxRect(x, y, w, h), - PresContext()->AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); // Fully mark our kid dirty so that it gets resized if necessary // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case): nsIFrame* kid = PrincipalChildList().FirstChild(); kid->AddStateBits(NS_FRAME_IS_DIRTY); // Make sure to not allow interrupts if we're not being reflown as a root: nsPresContext::InterruptPreventer noInterrupts(PresContext()); @@ -558,17 +558,17 @@ nsRect nsSVGForeignObjectFrame::GetInvalidRegion() { MOZ_ASSERT(!NS_SVGDisplayListPaintingEnabled(), "Only called by nsDisplayOuterSVG code"); nsIFrame* kid = PrincipalChildList().FirstChild(); if (kid->HasInvalidFrameInSubtree()) { gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height); - r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel()); + r.Scale(1.0 / AppUnitsPerCSSPixel()); nsRect rect = nsSVGUtils::ToCanvasBounds(r, GetCanvasTM(), PresContext()); rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect); return rect; } return nsRect(); } void
--- a/layout/svg/nsSVGImageFrame.cpp +++ b/layout/svg/nsSVGImageFrame.cpp @@ -435,17 +435,17 @@ nsSVGImageFrame::ReflowSVG() float x, y, width, height; SVGImageElement *element = static_cast<SVGImageElement*>(GetContent()); element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); Rect extent(x, y, width, height); if (!extent.IsEmpty()) { mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, - PresContext()->AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); } else { mRect.SetEmpty(); } if (mState & NS_FRAME_FIRST_REFLOW) { // Make sure we have our filter property (if any) before calling // FinishAndStoreOverflow (subsequent filter changes are handled off // nsChangeHint_UpdateEffects):
--- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -233,17 +233,17 @@ nsSVGIntegrationUtils::GetSVGBBoxForNonS nsRect r = (aUnionContinuations) ? GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(), GetOffsetToBoundingBox(firstFrame), false) : GetPreEffectsVisualOverflow(firstFrame, aNonSVGFrame, GetOffsetToBoundingBox(firstFrame)); return nsLayoutUtils::RectToGfxRect(r, - aNonSVGFrame->PresContext()->AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); } // XXX Since we're called during reflow, this method is broken for frames with // continuations. When we're called for a frame with continuations, we're // called for each continuation in turn as it's reflowed. However, it isn't // until the last continuation is reflowed that this method's // GetOffsetToBoundingBox() and GetPreEffectsVisualOverflowUnion() calls will // obtain valid border boxes for all the continuations. As a result, we'll @@ -295,17 +295,17 @@ nsRect // XXX Why are we rounding out to pixel boundaries? We don't do that in // GetSVGBBoxForNonSVGFrame, and it doesn't appear to be necessary. gfxRect overrideBBox = nsLayoutUtils::RectToGfxRect( GetPreEffectsVisualOverflowUnion(firstFrame, aFrame, aPreEffectsOverflowRect, firstFrameToBoundingBox, true), - aFrame->PresContext()->AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); overrideBBox.RoundOut(); nsRect overflowRect = nsFilterInstance::GetPostFilterBounds(firstFrame, &overrideBBox); // Return overflowRect relative to aFrame, rather than "user space": return overflowRect - (aFrame->GetOffsetTo(firstFrame) + firstFrameToBoundingBox); } @@ -389,17 +389,17 @@ nsSVGIntegrationUtils::HitTestFrameForEf // XXXmstange Isn't this wrong for svg:use and innerSVG frames? toUserSpace = aFrame->GetPosition(); } else { toUserSpace = aFrame->GetOffsetTo(firstFrame) + GetOffsetToBoundingBox(firstFrame); } nsPoint pt = aPt + toUserSpace; gfxPoint userSpacePt = - gfxPoint(pt.x, pt.y) / aFrame->PresContext()->AppUnitsPerCSSPixel(); + gfxPoint(pt.x, pt.y) / AppUnitsPerCSSPixel(); return nsSVGUtils::HitTestClip(firstFrame, userSpacePt); } class RegularFramePaintCallback : public nsSVGFilterPaintCallback { public: RegularFramePaintCallback(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
--- a/layout/svg/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/nsSVGOuterSVGFrame.cpp @@ -580,17 +580,17 @@ nsDisplayOuterSVG::HitTest(nsDisplayList ToReferenceFrame() + outerSVGFrame->GetContentRectRelativeToSelf().TopLeft(); nsPoint pointRelativeToContentBox = nsPoint(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2) - refFrameToContentBox; gfxPoint svgViewportRelativePoint = gfxPoint(pointRelativeToContentBox.x, pointRelativeToContentBox.y) / - outerSVGFrame->PresContext()->AppUnitsPerCSSPixel(); + AppUnitsPerCSSPixel(); nsSVGOuterSVGAnonChildFrame *anonKid = static_cast<nsSVGOuterSVGAnonChildFrame*>( outerSVGFrame->PrincipalChildList().FirstChild()); nsIFrame* frame = nsSVGUtils::HitTestChildren(anonKid, svgViewportRelativePoint); if (frame) {
--- a/layout/svg/nsSVGUseFrame.cpp +++ b/layout/svg/nsSVGUseFrame.cpp @@ -106,17 +106,17 @@ nsSVGUseFrame::ReflowSVG() // We only handle x/y offset here, since any width/height that is in force is // handled by the nsSVGOuterSVGFrame for the anonymous <svg> that will be // created for that purpose. float x, y; static_cast<SVGUseElement*>(GetContent())-> GetAnimatedLengthValues(&x, &y, nullptr); mRect.MoveTo(nsLayoutUtils::RoundGfxRectToAppRect( gfxRect(x, y, 0.0, 0.0), - PresContext()->AppUnitsPerCSSPixel()).TopLeft()); + AppUnitsPerCSSPixel()).TopLeft()); // If we have a filter, we need to invalidate ourselves because filter // output can change even if none of our descendants need repainting. if (StyleEffects()->HasFilters()) { InvalidateFrame(); } nsSVGGFrame::ReflowSVG();
--- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -828,17 +828,17 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra } gfxMatrix deviceToUserSpace = userToDeviceSpace; deviceToUserSpace.Invert(); gfxRect dirtyBounds = deviceToUserSpace.TransformBounds( gfxRect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height)); tmpDirtyRegion = nsLayoutUtils::RoundGfxRectToAppRect( - dirtyBounds, aFrame->PresContext()->AppUnitsPerCSSPixel()) - + dirtyBounds, AppUnitsPerCSSPixel()) - aFrame->GetPosition(); dirtyRegion = &tmpDirtyRegion; } gfxContextMatrixAutoSaveRestore autoSR(target); // 'target' is currently scaled such that its user space units are CSS // pixels (SVG user space units). But PaintFilteredFrame expects it to be @@ -957,17 +957,17 @@ nsSVGUtils::HitTestChildren(nsSVGDisplay } nsRect nsSVGUtils::TransformFrameRectToOuterSVG(const nsRect& aRect, const gfxMatrix& aMatrix, nsPresContext* aPresContext) { gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height); - r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel()); + r.Scale(1.0 / AppUnitsPerCSSPixel()); return nsLayoutUtils::RoundGfxRectToAppRect( aMatrix.TransformBounds(r), aPresContext->AppUnitsPerDevPixel()); } IntSize nsSVGUtils::ConvertToSurfaceSize(const gfxSize& aSize, bool *aResultOverflows) { @@ -1213,17 +1213,17 @@ nsSVGUtils::FrameSpaceInCSSPxToUserSpace // frame's border-box rects over all continuations. return gfxPoint(); } // Leaf frames apply their own offset inside their user space. if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) || nsSVGUtils::IsInSVGTextSubtree(aFrame)) { return nsLayoutUtils::RectToGfxRect(aFrame->GetRect(), - nsPresContext::AppUnitsPerCSSPixel()).TopLeft(); + AppUnitsPerCSSPixel()).TopLeft(); } // For foreignObject frames, nsSVGUtils::GetBBox applies their local // transform, so we need to do the same here. if (aFrame->IsSVGForeignObjectFrame()) { gfxMatrix transform = static_cast<nsSVGElement*>(aFrame->GetContent())-> PrependLocalTransformsTo(gfxMatrix(), eChildToUserSpace); NS_ASSERTION(!transform.HasNonTranslation(), "we're relying on this being an offset-only transform");
--- a/layout/svg/nsSVGViewportFrame.cpp +++ b/layout/svg/nsSVGViewportFrame.cpp @@ -61,17 +61,17 @@ nsSVGViewportFrame::ReflowSVG() { // mRect must be set before FinishAndStoreOverflow is called in order // for our overflow areas to be clipped correctly. float x, y, width, height; static_cast<SVGViewportElement*>(GetContent())-> GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); mRect = nsLayoutUtils::RoundGfxRectToAppRect( gfxRect(x, y, width, height), - PresContext()->AppUnitsPerCSSPixel()); + AppUnitsPerCSSPixel()); // If we have a filter, we need to invalidate ourselves because filter // output can change even if none of our descendants need repainting. if (StyleEffects()->HasFilters()) { InvalidateFrame(); } nsSVGDisplayContainerFrame::ReflowSVG();
--- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -446,13 +446,13 @@ nsTableRowFrame::GetContinuousBCBorderWi aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(d2a, mBStartContBorderWidth); aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(d2a, mIEndContBorderWidth); } inline nscoord nsTableRowFrame::GetOuterBStartContBCBorderWidth() { - int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel(); + int32_t aPixelsToTwips = mozilla::AppUnitsPerCSSPixel(); return BC_BORDER_START_HALF_COORD(aPixelsToTwips, mBStartContBorderWidth); } #endif
--- a/layout/xul/nsMenuPopupFrame.cpp +++ b/layout/xul/nsMenuPopupFrame.cpp @@ -1377,17 +1377,17 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr // If we can't reach a root pres context, don't bother continuing: if (!rootPresContext) { return NS_OK; } // If anchored to a rectangle, use that rectangle. Otherwise, determine the // rectangle from the anchor. if (mAnchorType == MenuPopupAnchorType_Rect) { - anchorRect = ToAppUnits(mScreenRect, nsPresContext::AppUnitsPerCSSPixel()); + anchorRect = ToAppUnits(mScreenRect, AppUnitsPerCSSPixel()); } else { // if the frame is not specified, use the anchor node passed to OpenPopup. If // that wasn't specified either, use the root frame. Note that mAnchorContent // might be a different document so its presshell must be used. if (!aAnchorFrame) { if (mAnchorContent) { aAnchorFrame = mAnchorContent->GetPrimaryFrame();
--- a/layout/xul/nsMenuPopupFrame.h +++ b/layout/xul/nsMenuPopupFrame.h @@ -368,17 +368,17 @@ public: bool aAttributesOverride); bool GetAutoPosition(); void SetAutoPosition(bool aShouldAutoPosition); nsIScrollableFrame* GetScrollFrame(nsIFrame* aStart); void SetOverrideConstraintRect(mozilla::LayoutDeviceIntRect aRect) { - mOverrideConstraintRect = ToAppUnits(aRect, PresContext()->AppUnitsPerCSSPixel()); + mOverrideConstraintRect = ToAppUnits(aRect, mozilla::AppUnitsPerCSSPixel()); } // For a popup that should appear anchored at the given rect, determine // the screen area that it is constrained by. This will be the available // area of the screen the popup should be displayed on. Content popups, // however, will also be constrained by the content area, given by // aRootScreenRect. All coordinates are in app units. // For non-toplevel popups (which will always be panels), we will also
--- a/layout/xul/nsResizerFrame.cpp +++ b/layout/xul/nsResizerFrame.cpp @@ -239,17 +239,17 @@ nsResizerFrame::HandleEvent(nsPresContex // direction, don't allow the new size to be less that the resizer's // size. This ensures that content isn't resized too small as to make // the resizer invisible. nsRect appUnitsRect = ToAppUnits(rect.ToUnknownRect(), aPresContext->AppUnitsPerDevPixel()); if (appUnitsRect.width < mRect.width && mouseMove.x) appUnitsRect.width = mRect.width; if (appUnitsRect.height < mRect.height && mouseMove.y) appUnitsRect.height = mRect.height; - nsIntRect cssRect = appUnitsRect.ToInsidePixels(nsPresContext::AppUnitsPerCSSPixel()); + nsIntRect cssRect = appUnitsRect.ToInsidePixels(AppUnitsPerCSSPixel()); LayoutDeviceIntRect oldRect; AutoWeakFrame weakFrame(menuPopupFrame); if (menuPopupFrame) { nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget(); if (widget) oldRect = widget->GetScreenBounds();
--- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -573,17 +573,17 @@ nsTreeBodyFrame::GetSelectionRegion() nsCOMPtr<nsITreeSelection> selection; mView->GetSelection(getter_AddRefs(selection)); if (!selection) { return Nothing(); } RefPtr<nsPresContext> presContext = PresContext(); - nsIntRect rect = mRect.ToOutsidePixels(presContext->AppUnitsPerCSSPixel()); + nsIntRect rect = mRect.ToOutsidePixels(AppUnitsPerCSSPixel()); nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame(); nsPoint origin = GetOffsetTo(rootFrame); CSSIntRegion region; // iterate through the visible rows and add the selected ones to the // drag region
--- a/mfbt/Utf8.h +++ b/mfbt/Utf8.h @@ -258,17 +258,17 @@ inline bool IsTrailingUnit(Utf8Unit aUnit) { return (aUnit.toUint8() & 0b1100'0000) == 0b1000'0000; } /** * Given |aLeadUnit| that is a non-ASCII code unit, a pointer to an |Iter aIter| * that (initially) itself points one unit past |aLeadUnit|, and - * |const EndIter aEnd| that denotes the end of the UTF-8 data when compared + * |const EndIter& aEnd| that denotes the end of the UTF-8 data when compared * against |*aIter| using |aEnd - *aIter|: * * If |aLeadUnit| and subsequent code units computed using |*aIter| (up to * |aEnd|) encode a valid code point -- not exceeding Unicode's range, not a * surrogate, in shortest form -- then return Some(that code point) and advance * |*aIter| past those code units. * * Otherwise decrement |*aIter| (so that it points at |aLeadUnit|) and return @@ -294,17 +294,17 @@ template<typename Iter, typename EndIter, class OnBadLeadUnit, class OnNotEnoughUnits, class OnBadTrailingUnit, class OnBadCodePoint, class OnNotShortestForm> MOZ_ALWAYS_INLINE Maybe<char32_t> DecodeOneUtf8CodePointInline(const Utf8Unit aLeadUnit, - Iter* aIter, const EndIter aEnd, + Iter* aIter, const EndIter& aEnd, OnBadLeadUnit aOnBadLeadUnit, OnNotEnoughUnits aOnNotEnoughUnits, OnBadTrailingUnit aOnBadTrailingUnit, OnBadCodePoint aOnBadCodePoint, OnNotShortestForm aOnNotShortestForm) { MOZ_ASSERT(Utf8Unit((*aIter)[-1]) == aLeadUnit); @@ -386,17 +386,17 @@ template<typename Iter, typename EndIter, class OnBadLeadUnit, class OnNotEnoughUnits, class OnBadTrailingUnit, class OnBadCodePoint, class OnNotShortestForm> inline Maybe<char32_t> DecodeOneUtf8CodePoint(const Utf8Unit aLeadUnit, - Iter* aIter, const EndIter aEnd, + Iter* aIter, const EndIter& aEnd, OnBadLeadUnit aOnBadLeadUnit, OnNotEnoughUnits aOnNotEnoughUnits, OnBadTrailingUnit aOnBadTrailingUnit, OnBadCodePoint aOnBadCodePoint, OnNotShortestForm aOnNotShortestForm) { return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd, aOnBadLeadUnit, aOnNotEnoughUnits, @@ -409,17 +409,17 @@ DecodeOneUtf8CodePoint(const Utf8Unit aL * trailing if-invalid notifier functors. * * This function is MOZ_ALWAYS_INLINE: if you don't need that, use the version * of this function without the "Inline" suffix on the name. */ template<typename Iter, typename EndIter> MOZ_ALWAYS_INLINE Maybe<char32_t> DecodeOneUtf8CodePointInline(const Utf8Unit aLeadUnit, - Iter* aIter, const EndIter aEnd) + Iter* aIter, const EndIter& aEnd) { // aOnBadLeadUnit is called when |aLeadUnit| itself is an invalid lead unit in // a multi-unit code point. It is passed no arguments: the caller already has // |aLeadUnit| on hand, so no need to provide it again. auto onBadLeadUnit = []() {}; // aOnNotEnoughUnits is called when |aLeadUnit| properly indicates a code // point length, but there aren't enough units from |*aIter| to |aEnd| to @@ -461,16 +461,16 @@ DecodeOneUtf8CodePointInline(const Utf8U /** * Identical to the above function, but not forced to be instantiated inline -- * the compiler/linker are allowed to common up separate invocations. */ template<typename Iter, typename EndIter> inline Maybe<char32_t> DecodeOneUtf8CodePoint(const Utf8Unit aLeadUnit, - Iter* aIter, const EndIter aEnd) + Iter* aIter, const EndIter& aEnd) { return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd); } } // namespace mozilla #endif /* mozilla_Utf8_h */
--- a/mobile/android/config/mozconfigs/android-aarch64/nightly +++ b/mobile/android/config/mozconfigs/android-aarch64/nightly @@ -1,13 +1,19 @@ . "$topsrcdir/mobile/android/config/mozconfigs/common" # Android ac_add_options --with-android-min-sdk=21 ac_add_options --target=aarch64-linux-android ac_add_options --with-branding=mobile/android/branding/nightly +export AR="$topsrcdir/clang/bin/llvm-ar" +export NM="$topsrcdir/clang/bin/llvm-nm" +export RANLIB="$topsrcdir/clang/bin/llvm-ranlib" + +ac_add_options --enable-lto + export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 export MOZ_ANDROID_POCKET=1 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-api-16/nightly +++ b/mobile/android/config/mozconfigs/android-api-16/nightly @@ -11,9 +11,15 @@ ac_add_options --target=arm-linux-androi ac_add_options --with-branding=mobile/android/branding/nightly export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 export MOZ_ANDROID_MMA=1 export MOZ_ANDROID_POCKET=1 +export AR="$topsrcdir/clang/bin/llvm-ar" +export NM="$topsrcdir/clang/bin/llvm-nm" +export RANLIB="$topsrcdir/clang/bin/llvm-ranlib" + +ac_add_options --enable-lto + . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-x86/nightly +++ b/mobile/android/config/mozconfigs/android-x86/nightly @@ -9,9 +9,15 @@ ac_add_options --target=i686-linux-andro ac_add_options --with-android-min-sdk=16 ac_add_options --with-branding=mobile/android/branding/nightly export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 export MOZ_ANDROID_POCKET=1 +export AR="$topsrcdir/clang/bin/llvm-ar" +export NM="$topsrcdir/clang/bin/llvm-nm" +export RANLIB="$topsrcdir/clang/bin/llvm-ranlib" + +ac_add_options --enable-lto + . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -1086,22 +1086,23 @@ VARCACHE_PREF( // - true: They are allow to present http auth. dialog // - false: They are not allow to present http auth. dialog. VARCACHE_PREF( "network.auth.non-web-content-triggered-resources-http-auth-allow", network_auth_non_web_content_triggered_resources_http_auth_allow, bool, false ) -// 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign +// 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign, +// 4-rejectTracker // Keep the old default of accepting all cookies VARCACHE_PREF( "network.cookie.cookieBehavior", network_cookie_cookieBehavior, - int32_t, 0 + RelaxedAtomicInt32, 0 ) // Enables the predictive service. VARCACHE_PREF( "network.predictor.enabled", network_predictor_enabled, bool, true ) @@ -1227,22 +1228,16 @@ VARCACHE_PREF( PREF("preferences.allow.omt-write", bool, true) //--------------------------------------------------------------------------- // Privacy prefs //--------------------------------------------------------------------------- VARCACHE_PREF( - "privacy.restrict3rdpartystorage.enabled", - privacy_restrict3rdpartystorage_enabled, - RelaxedAtomicBool, false -) - -VARCACHE_PREF( "privacy.restrict3rdpartystorage.ui.enabled", privacy_restrict3rdpartystorage_ui_enabled, RelaxedAtomicBool, false ) // Anti-tracking permission expiration VARCACHE_PREF( "privacy.restrict3rdpartystorage.expiration",
--- a/netwerk/base/nsChannelClassifier.cpp +++ b/netwerk/base/nsChannelClassifier.cpp @@ -7,16 +7,17 @@ #include "nsChannelClassifier.h" #include "mozIThirdPartyUtil.h" #include "nsCharSeparatedTokenizer.h" #include "nsContentUtils.h" #include "nsIAddonPolicyService.h" #include "nsICacheEntry.h" #include "nsICachingChannel.h" +#include "nsICookieService.h" #include "nsIChannel.h" #include "nsIClassOfService.h" #include "nsIDocShell.h" #include "nsIDocument.h" #include "nsIHttpChannel.h" #include "nsIHttpChannelInternal.h" #include "nsIIOService.h" #include "nsIParentChannel.h" @@ -946,17 +947,18 @@ TrackingURICallback::OnClassifyComplete( const nsACString& aFullHash) { MOZ_ASSERT(aErrorCode == NS_OK); const bool shouldEnableTrackingProtection = mChannelClassifier->ShouldEnableTrackingProtection(); const bool shouldEnableTrackingAnnotation = mChannelClassifier->ShouldEnableTrackingAnnotation() || - StaticPrefs::privacy_restrict3rdpartystorage_enabled(); + StaticPrefs::network_cookie_cookieBehavior() == + nsICookieService::BEHAVIOR_REJECT_TRACKER; MOZ_ASSERT(shouldEnableTrackingProtection || shouldEnableTrackingAnnotation); LOG(("TrackingURICallback[%p]:OnClassifyComplete " "shouldEnableTrackingProtection=%d, shouldEnableTrackingAnnnotation=%d", mChannelClassifier.get(), shouldEnableTrackingProtection, shouldEnableTrackingAnnotation)); // Figure out whether we are receiving the results of a blacklist or @@ -1194,17 +1196,18 @@ TrackingURICallback::OnTrackerFound(nsre mChannelClassifier->SetBlockedContent(channel, aErrorCode, mList, mProvider, mFullHash); LOG(("TrackingURICallback[%p]::OnTrackerFound, cancelling channel[%p]", mChannelClassifier.get(), channel.get())); channel->Cancel(aErrorCode); } else { MOZ_ASSERT(aErrorCode == NS_ERROR_TRACKING_ANNOTATION_URI); MOZ_ASSERT(mChannelClassifier->ShouldEnableTrackingAnnotation() || - StaticPrefs::privacy_restrict3rdpartystorage_enabled()); + StaticPrefs::network_cookie_cookieBehavior() == + nsICookieService::BEHAVIOR_REJECT_TRACKER); LOG(("TrackingURICallback[%p]::OnTrackerFound, annotating channel[%p]", mChannelClassifier.get(), channel.get())); // Even with TP disabled, we still want to show the user that there // are unblocked trackers on the site, so notify the UI that we loaded // tracking content. UI code can treat this notification differently // depending on whether TP is enabled or disabled. @@ -1416,17 +1419,18 @@ nsChannelClassifier::CheckIsTrackerWithL nsCOMPtr<nsIURIClassifier> uriClassifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } const bool shouldEnableTrackingProtection = ShouldEnableTrackingProtection(); - const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation() || StaticPrefs::privacy_restrict3rdpartystorage_enabled(); + const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation() || + StaticPrefs::network_cookie_cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER; if (!shouldEnableTrackingProtection && !shouldEnableTrackingAnnotation) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIURI> uri; rv = mChannel->GetURI(getter_AddRefs(uri)); if (NS_FAILED(rv) || !uri) { return rv;
--- a/netwerk/cookie/nsCookieService.cpp +++ b/netwerk/cookie/nsCookieService.cpp @@ -2405,17 +2405,17 @@ nsCookieService::RunInTransaction(nsICoo * pref observer impl ******************************************************************************/ void nsCookieService::PrefChanged(nsIPrefBranch *aPrefBranch) { int32_t val; if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val))) - mCookieBehavior = (uint8_t) LIMIT(val, 0, 3, 0); + mCookieBehavior = (uint8_t) LIMIT(val, 0, nsICookieService::BEHAVIOR_LAST, 0); if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxNumberOfCookies, &val))) mMaxNumberOfCookies = (uint16_t) LIMIT(val, 1, 0xFFFF, kMaxNumberOfCookies); if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxCookiesPerHost, &val))) mMaxCookiesPerHost = (uint16_t) LIMIT(val, 1, 0xFFFF, kMaxCookiesPerHost); if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookiePurgeAge, &val))) { @@ -4194,24 +4194,16 @@ nsCookieService::CheckPrefs(nsICookiePer nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateCodebasePrincipal(aHostURI, aOriginAttrs); if (!principal) { COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "non-codebase principals cannot get/set cookies"); return STATUS_REJECTED_WITH_ERROR; } - // No cookies allowed if this request comes from a tracker, in a 3rd party - // context, when anti-tracking protection is enabled and when we don't have - // access to the first-party cookie jar. - if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted && - StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { - return STATUS_REJECTED; - } - // check the permission list first; if we find an entry, it overrides // default prefs. see bug 184059. if (aPermissionService) { nsCookieAccess access; // Not passing an nsIChannel here is probably OK; our implementation // doesn't do anything with it anyway. rv = aPermissionService->CanAccess(principal, &access); @@ -4245,16 +4237,25 @@ nsCookieService::CheckPrefs(nsICookiePer "for this site"); return STATUS_REJECTED; } return STATUS_ACCEPTED; } } } + // No cookies allowed if this request comes from a tracker, in a 3rd party + // context, when anti-tracking protection is enabled and when we don't have + // access to the first-party cookie jar. + if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted && + aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) { + COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled in trackers"); + return STATUS_REJECTED; + } + // check default prefs if (aCookieBehavior == nsICookieService::BEHAVIOR_REJECT) { COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled"); return STATUS_REJECTED; } // check if cookie is foreign if (aIsForeign) { @@ -4266,17 +4267,19 @@ nsCookieService::CheckPrefs(nsICookiePer if (aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) { if (aNumOfCookies == 0) { COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party"); return STATUS_REJECTED; } } MOZ_ASSERT(aCookieBehavior == nsICookieService::BEHAVIOR_ACCEPT || - aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN); + aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN || + // But with permission granted. + aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER); if (aThirdPartySession) return STATUS_ACCEPT_SESSION; if (aThirdPartyNonsecureSession) { bool isHTTPS = false; aHostURI->SchemeIs("https", &isHTTPS); if (!isHTTPS)
--- a/netwerk/cookie/nsICookiePermission.idl +++ b/netwerk/cookie/nsICookiePermission.idl @@ -47,17 +47,17 @@ interface nsICookiePermission : nsISuppo * the new cookie access for the URI. */ void setAccess(in nsIURI aURI, in nsCookieAccess aAccess); /** * canAccess * - * this method is called to test whether or not the given URI/channel may + * this method is called to test whether or not the given principal may * access the cookie database, either to set or get cookies. * * @param aPrincipal * the principal trying to access cookies. * * @return one of the following nsCookieAccess values: * ACCESS_DEFAULT, ACCESS_ALLOW, ACCESS_DENY, or * ACCESS_ALLOW_FIRST_PARTY_ONLY
--- a/netwerk/cookie/nsICookieService.idl +++ b/netwerk/cookie/nsICookieService.idl @@ -84,16 +84,19 @@ interface nsICookieService : nsISupports /* * Possible values for the "network.cookie.cookieBehavior" preference. */ const uint32_t BEHAVIOR_ACCEPT = 0; // allow all cookies const uint32_t BEHAVIOR_REJECT_FOREIGN = 1; // reject all third-party cookies const uint32_t BEHAVIOR_REJECT = 2; // reject all cookies const uint32_t BEHAVIOR_LIMIT_FOREIGN = 3; // reject third-party cookies unless the // eTLD already has at least one cookie + const uint32_t BEHAVIOR_REJECT_TRACKER = 4; // reject trackers + // When adding a new cookie behavior, please increase this value! + const uint32_t BEHAVIOR_LAST = 4; /* * Possible values for the "network.cookie.lifetimePolicy" preference. */ const uint32_t ACCEPT_NORMALLY = 0; // accept normally // Value = 1 is considered the same as 0 (See Bug 606655). const uint32_t ACCEPT_SESSION = 2; // downgrade to session // Value = 3 is considered the same as 0
--- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -17,16 +17,17 @@ #include "nsHttpChannel.h" #include "nsHttpHandler.h" #include "nsIApplicationCacheService.h" #include "nsIApplicationCacheContainer.h" #include "nsICacheStorageService.h" #include "nsICacheStorage.h" #include "nsICacheEntry.h" #include "nsICaptivePortalService.h" +#include "nsICookieService.h" #include "nsICryptoHash.h" #include "nsINetworkInterceptController.h" #include "nsINSSErrorsService.h" #include "nsISecurityReporter.h" #include "nsIStringBundle.h" #include "nsIStreamListenerTee.h" #include "nsISeekableStream.h" #include "nsILoadGroupChild.h" @@ -50,16 +51,17 @@ #include "mozilla/TimeStamp.h" #include "nsError.h" #include "nsPrintfCString.h" #include "nsAlgorithm.h" #include "nsQueryObject.h" #include "nsThreadUtils.h" #include "GeckoProfiler.h" #include "nsIConsoleService.h" +#include "mozilla/AntiTrackingCommon.h" #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsISSLSocketControl.h" #include "sslt.h" #include "nsContentUtils.h" #include "nsContentSecurityManager.h" @@ -98,17 +100,16 @@ #include "nsIDocument.h" #include "nsICompressConvStats.h" #include "nsCORSListenerProxy.h" #include "nsISocketProvider.h" #include "mozilla/extensions/StreamFilterParent.h" #include "mozilla/net/Predictor.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/NullPrincipal.h" -#include "mozilla/StaticPrefs.h" #include "CacheControlParser.h" #include "nsMixedContentBlocker.h" #include "CacheStorageService.h" #include "HttpChannelParent.h" #include "InterceptedHttpChannel.h" #include "nsIBufferedStreams.h" #include "nsIFileStreams.h" #include "nsIMIMEInputStream.h" @@ -433,20 +434,80 @@ nsHttpChannel::LogBlockedCORSRequest(con return NS_ERROR_UNEXPECTED; } //----------------------------------------------------------------------------- // nsHttpChannel <private> //----------------------------------------------------------------------------- nsresult +nsHttpChannel::PrepareToConnect() +{ + LOG(("nsHttpChannel::PrepareToConnect [this=%p]\n", this)); + + AddCookiesToRequest(); + + // notify "http-on-modify-request" observers + CallOnModifyRequestObservers(); + + SetLoadGroupUserAgentOverride(); + + // Check if request was cancelled during on-modify-request or on-useragent. + if (mCanceled) { + return mStatus; + } + + if (mSuspendCount) { + // We abandon the connection here if there was one. + LOG(("Waiting until resume OnBeforeConnect [this=%p]\n", this)); + MOZ_ASSERT(!mCallOnResume); + mCallOnResume = &nsHttpChannel::HandleOnBeforeConnect; + return NS_OK; + } + + return OnBeforeConnect(); +} + +void +nsHttpChannel::HandleOnBeforeConnect() +{ + MOZ_ASSERT(!mCallOnResume, "How did that happen?"); + nsresult rv; + + if (mSuspendCount) { + LOG(("Waiting until resume OnBeforeConnect [this=%p]\n", this)); + mCallOnResume = &nsHttpChannel::HandleOnBeforeConnect; + return; + } + + LOG(("nsHttpChannel::HandleOnBeforeConnect [this=%p]\n", this)); + rv = OnBeforeConnect(); + if (NS_FAILED(rv)) { + CloseCacheEntry(false); + Unused << AsyncAbort(rv); + } +} + +nsresult nsHttpChannel::OnBeforeConnect() { nsresult rv; + // Check if request was cancelled during suspend AFTER on-modify-request or + // on-useragent. + if (mCanceled) { + return mStatus; + } + + // Check to see if we should redirect this channel elsewhere by + // nsIHttpChannel.redirectTo API request + if (mAPIRedirectToURI) { + return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect); + } + // Note that we are only setting the "Upgrade-Insecure-Requests" request // header for *all* navigational requests instead of all requests as // defined in the spec, see: // https://www.w3.org/TR/upgrade-insecure-requests/#preference nsContentPolicyType type = mLoadInfo ? mLoadInfo->GetExternalContentPolicyType() : nsIContentPolicy::TYPE_OTHER; @@ -3824,38 +3885,36 @@ nsHttpChannel::OpenCacheEntryInternal(bo if (mPostID) { extension.Append(nsPrintfCString("%d", mPostID)); } if (mTRR) { extension.Append("TRR"); } - if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() && - mIsTrackingResource) { - nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = - services::GetThirdPartyUtil(); - if (thirdPartyUtil) { - bool thirdParty = false; - Unused << thirdPartyUtil->IsThirdPartyChannel(this, - nullptr, - &thirdParty); - if (thirdParty) { - nsCOMPtr<nsIURI> topWindowURI; - rv = GetTopWindowURI(getter_AddRefs(topWindowURI)); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString topWindowOrigin; - rv = nsContentUtils::GetUTFOrigin(topWindowURI, topWindowOrigin); - NS_ENSURE_SUCCESS(rv, rv); - - extension.Append("-trackerFor:"); - extension.Append(NS_ConvertUTF16toUTF8(topWindowOrigin)); - } - } + if (!AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(this, mURI)) { + nsCOMPtr<nsIURI> topWindowURI; + rv = GetTopWindowURI(getter_AddRefs(topWindowURI)); + bool isDocument = false; + if (NS_FAILED(rv) && + NS_SUCCEEDED(GetIsMainDocumentChannel(&isDocument)) && + isDocument) { + // For top-level documents, use the document channel's origin to compute + // the unique storage space identifier instead of the top Window URI. + rv = NS_GetFinalChannelURI(this, getter_AddRefs(topWindowURI)); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsAutoString topWindowOrigin; + rv = nsContentUtils::GetUTFOrigin(topWindowURI ? topWindowURI : mURI, + topWindowOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + extension.Append("-unique:"); + extension.Append(NS_ConvertUTF16toUTF8(topWindowOrigin)); } mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY; mCacheQueueSizeWhenOpen = CacheStorageService::CacheQueueSize(mCacheOpenWithPriority); if (sRCWNEnabled && maybeRCWN && !mApplicationCacheForWrite) { bool hasAltData = false; uint32_t sizeInKb = 0; @@ -6115,18 +6174,16 @@ nsHttpChannel::AsyncOpen(nsIStreamListen } // Remember the cookie header that was set, if any nsAutoCString cookieHeader; if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Cookie, cookieHeader))) { mUserSetCookieHeader = cookieHeader; } - AddCookiesToRequest(); - // Set user agent override, do so before OnOpeningRequest notification // since we want to allow consumers of that notification change or remove // the User-Agent request header. HttpBaseChannel::SetDocshellUserAgentOverride(); // After we notify any observers (on-opening-request, loadGroup, etc) we // must return NS_OK and return any errors asynchronously via // OnStart/OnStopRequest. Observers may add a reference to the channel @@ -6329,73 +6386,16 @@ nsHttpChannel::BeginConnect() // check to see if authorization headers should be included // mCustomAuthHeader is set in AsyncOpen if we find Authorization header rv = mAuthProvider->AddAuthorizationHeaders(mCustomAuthHeader); if (NS_FAILED(rv)) { LOG(("nsHttpChannel %p AddAuthorizationHeaders failed (%08x)", this, static_cast<uint32_t>(rv))); } - // notify "http-on-modify-request" observers - CallOnModifyRequestObservers(); - - SetLoadGroupUserAgentOverride(); - - // Check if request was cancelled during on-modify-request or on-useragent. - if (mCanceled) { - return mStatus; - } - - if (mSuspendCount) { - LOG(("Waiting until resume BeginConnect [this=%p]\n", this)); - MOZ_ASSERT(!mCallOnResume); - mCallOnResume = &nsHttpChannel::HandleBeginConnectContinue; - return NS_OK; - } - - return BeginConnectContinue(); -} - -void -nsHttpChannel::HandleBeginConnectContinue() -{ - MOZ_ASSERT(!mCallOnResume, "How did that happen?"); - nsresult rv; - - if (mSuspendCount) { - LOG(("Waiting until resume BeginConnect [this=%p]\n", this)); - mCallOnResume = &nsHttpChannel::HandleBeginConnectContinue; - return; - } - - LOG(("nsHttpChannel::HandleBeginConnectContinue [this=%p]\n", this)); - rv = BeginConnectContinue(); - if (NS_FAILED(rv)) { - CloseCacheEntry(false); - Unused << AsyncAbort(rv); - } -} - -nsresult -nsHttpChannel::BeginConnectContinue() -{ - nsresult rv; - - // Check if request was cancelled during suspend AFTER on-modify-request or - // on-useragent. - if (mCanceled) { - return mStatus; - } - - // Check to see if we should redirect this channel elsewhere by - // nsIHttpChannel.redirectTo API request - if (mAPIRedirectToURI) { - return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect); - } - // If mTimingEnabled flag is not set after OnModifyRequest() then // clear the already recorded AsyncOpen value for consistency. if (!mTimingEnabled) mAsyncOpenTime = TimeStamp(); // if this somehow fails we can go on without it Unused << gHttpHandler->AddConnectionHeader(&mRequestHead, mCaps); @@ -6657,17 +6657,17 @@ nsHttpChannel::ContinueBeginConnectWithR LOG(("Waiting until resume to do async connect [this=%p]\n", this)); mCallOnResume = &nsHttpChannel::ContinueBeginConnect; rv = NS_OK; } else if (mCanceled) { // We may have been cancelled already, by nsChannelClassifier in that // case, we should not send the request to the server rv = mStatus; } else { - rv = OnBeforeConnect(); + rv = PrepareToConnect(); } LOG(("nsHttpChannel::ContinueBeginConnectWithResult result [this=%p rv=%" PRIx32 " mCanceled=%u]\n", this, static_cast<uint32_t>(rv), static_cast<bool>(mCanceled))); return rv; }
--- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -290,20 +290,20 @@ private: nsresult BeginConnectActual(); // We might synchronously or asynchronously call BeginConnectActual, // which includes DNS prefetch and speculative connection, according to // whether an async tracker lookup is required. If the tracker lookup // is required, this funciton will just return NS_OK and BeginConnectActual() // will be called when callback. See Bug 1325054 for more information. nsresult BeginConnect(); - void HandleBeginConnectContinue(); - MOZ_MUST_USE nsresult BeginConnectContinue(); MOZ_MUST_USE nsresult ContinueBeginConnectWithResult(); void ContinueBeginConnect(); + MOZ_MUST_USE nsresult PrepareToConnect(); + void HandleOnBeforeConnect(); MOZ_MUST_USE nsresult OnBeforeConnect(); void OnBeforeConnectContinue(); MOZ_MUST_USE nsresult Connect(); void SpeculativeConnect(); MOZ_MUST_USE nsresult SetupTransaction(); MOZ_MUST_USE nsresult CallOnStartRequest(); MOZ_MUST_USE nsresult ProcessResponse(); void AsyncContinueProcessResponse();
--- a/netwerk/protocol/http/nsIHttpChannel.idl +++ b/netwerk/protocol/http/nsIHttpChannel.idl @@ -474,17 +474,17 @@ interface nsIHttpChannel : nsIChannel */ [must_use] attribute uint64_t topLevelContentWindowId; /** * Returns true if the channel has loaded a resource that is on the tracking * protection list. This is only available if the * privacy.trackingprotection.annotate_channels pref is set and its value * should only be relied on after the channel has established a connection. - * Note that, if privacy.restrict3rdpartystorage.enabled pref is set, also + * Note that, if the privacy.trackingprotection.annotate_channels pref is set, also * top-level channels could be marked as tracking resource. */ [infallible] readonly attribute boolean isTrackingResource; /** * This method is used in order to override the tracking status of an HTTP * channel. This should only be called by Gecko under certain circumstances * when Gecko can guarantee that the channel classifier service will not be
--- a/old-configure.in +++ b/old-configure.in @@ -3464,16 +3464,27 @@ if test -n "$MOZ_OPTIMIZE"; then [printf("Hello World\n");], _results=yes, _results=no) AC_MSG_RESULT([$_results]) if test "$_results" = "no"; then AC_MSG_ERROR([These compiler flags for C are invalid: $MOZ_OPTIMIZE_FLAGS]) fi CFLAGS=$_SAVE_CFLAGS + if test -n "$MOZ_LTO" -a -n "$CLANG_CC"; then + # When using llvm-based LTO, non numeric optimization levels are + # not supported by the linker, so force the linker to use -O2 ( + # which doesn't influence the level compilation units are actually + # compiled at). + case " $MOZ_OPTIMIZE_FLAGS " in + *\ -Os\ *|*\ -Oz\ *) + MOZ_OPTIMIZE_LDFLAGS="$MOZ_OPTIMIZE_LDFLAGS -O2" + ;; + esac + fi fi fi # COMPILE_ENVIRONMENT AC_SUBST_LIST(MOZ_FRAMEPTR_FLAGS) AC_SUBST_LIST(MOZ_OPTIMIZE_FLAGS) AC_SUBST_LIST(MOZ_OPTIMIZE_LDFLAGS) AC_SUBST_LIST(MOZ_PGO_OPTIMIZE_FLAGS)
--- a/taskcluster/ci/packages/kind.yml +++ b/taskcluster/ci/packages/kind.yml @@ -133,22 +133,35 @@ jobs: dsc: url: http://snapshot.debian.org/archive/debian/20160317T100542Z/pool/main/g/git/git_2.8.0%7Erc3-1.dsc sha256: 6e81a318fb4eb5cca0333b7b6ff0c70dd0097e9fe711b159d5eac4b9f47c6c27 deb7-valgrind: description: "Valgrind for Debian Wheezy" treeherder: symbol: Deb7(valgrind) + worker: + env: + VERSION: 3.14.0.git20180806 + COMMIT: 2eb2df759f51b15702934dee108f4c20c3db5fef run: using: debian-package dsc: url: http://snapshot.debian.org/archive/debian/20170725T040438Z/pool/main/v/valgrind/valgrind_3.13.0-1.dsc sha256: ab84e017d1660efd30e9e0593a4c8b976aeda013cefb8c416dd284cc7222c11c + packages: + - deb7-git patch: valgrind-wheezy.diff + pre-build-command: >- + git clone -n git://sourceware.org/git/valgrind.git ../valgrind-git && + git -C ../valgrind-git archive --format=tar --prefix=valgrind-$VERSION/ $COMMIT | bzip2 > ../valgrind_$VERSION.orig.tar.bz2 && + tar -C .. -jxf ../valgrind_$VERSION.orig.tar.bz2 && + cp -r debian ../valgrind-$VERSION && + cd ../valgrind-$VERSION && + debchange -v 1:$VERSION-1.deb7moz1 --distribution wheezy "Mozilla backport of git master as of 2018-08-06." < /dev/null deb7-dh-python: description: "dh-python for Debian wheezy" treeherder: symbol: Deb7(dh-python) run: using: debian-package dsc:
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp +++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp @@ -8,20 +8,23 @@ #include "mozilla/dom/ContentChild.h" #include "mozilla/ipc/MessageChannel.h" #include "mozilla/AbstractThread.h" #include "mozilla/StaticPrefs.h" #include "mozIThirdPartyUtil.h" #include "nsContentUtils.h" #include "nsGlobalWindowInner.h" +#include "nsICookiePermission.h" +#include "nsICookieService.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" #include "nsIURI.h" #include "nsPIDOMWindow.h" +#include "nsScriptSecurityManager.h" #include "prtime.h" #define ANTITRACKING_PERM_KEY "3rdPartyStorage" using namespace mozilla; using mozilla::dom::ContentChild; namespace { @@ -66,25 +69,63 @@ CreatePermissionKey(const nsCString& aTr return; } aPermissionKey = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s^%s", aTrackingOrigin.get(), aGrantedOrigin.get()); } +// This internal method returns ACCESS_DENY if the access is denied, +// ACCESS_DEFAULT if unknown, some other access code if granted. +nsCookieAccess +CheckCookiePermissionForPrincipal(nsIPrincipal* aPrincipal) +{ + nsCookieAccess access = nsICookiePermission::ACCESS_DEFAULT; + if (!aPrincipal->GetIsCodebasePrincipal()) { + return access; + } + + nsCOMPtr<nsICookiePermission> cps = + do_GetService(NS_COOKIEPERMISSION_CONTRACTID); + if (NS_WARN_IF(!cps)) { + return access; + } + + nsresult rv = cps->CanAccess(aPrincipal, &access); + if (NS_WARN_IF(NS_FAILED(rv))) { + return access; + } + + // If we have a custom cookie permission, let's use it. + return access; +} + +int32_t +CookiesBehavior(nsIPrincipal* aPrincipal) +{ + // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior + // (See Bug 1406675 for rationale). + if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) { + return nsICookieService::BEHAVIOR_ACCEPT; + } + + return StaticPrefs::network_cookie_cookieBehavior(); +} + } // anonymous /* static */ RefPtr<AntiTrackingCommon::StorageAccessGrantPromise> AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin, nsPIDOMWindowInner* aParentWindow) { MOZ_ASSERT(aParentWindow); - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { + if (StaticPrefs::network_cookie_cookieBehavior() != + nsICookieService::BEHAVIOR_REJECT_TRACKER) { return StorageAccessGrantPromise::CreateAndResolve(true, __func__); } nsCOMPtr<nsIPrincipal> topLevelStoragePrincipal; nsAutoCString trackingOrigin; nsGlobalWindowInner* parentWindow = nsGlobalWindowInner::Cast(aParentWindow); nsGlobalWindowOuter* outerParentWindow = @@ -170,35 +211,70 @@ AntiTrackingCommon::SaveFirstPartyStorag nsresult rv = pm->AddFromPrincipal(aParentPrincipal, type.get(), nsIPermissionManager::ALLOW_ACTION, nsIPermissionManager::EXPIRE_TIME, when); Unused << NS_WARN_IF(NS_FAILED(rv)); aResolver(NS_SUCCEEDED(rv)); } bool -AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow, +AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aWindow, nsIURI* aURI) { - MOZ_ASSERT(a3rdPartyTrackingWindow); + MOZ_ASSERT(aWindow); MOZ_ASSERT(aURI); - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { + nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow); + nsIPrincipal* toplevelPrincipal = innerWindow->GetTopLevelPrincipal(); + if (!toplevelPrincipal) { + // We are already the top-level principal. Let's use the window's principal. + toplevelPrincipal = innerWindow->GetPrincipal(); + } + + if (!toplevelPrincipal) { + // This should not be possible, right? + return false; + } + + nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal); + if (access != nsICookiePermission::ACCESS_DEFAULT) { + return access != nsICookiePermission::ACCESS_DENY; + } + + int32_t behavior = CookiesBehavior(toplevelPrincipal); + if (behavior == nsICookieService::BEHAVIOR_ACCEPT) { return true; } - if (!nsContentUtils::IsThirdPartyWindowOrChannel(a3rdPartyTrackingWindow, - nullptr, aURI) || - !nsContentUtils::IsTrackingResourceWindow(a3rdPartyTrackingWindow)) { + if (behavior == nsICookieService::BEHAVIOR_REJECT) { + return false; + } + + // Let's check if this is a 3rd party context. + if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, nullptr, aURI)) { + return true; + } + + if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN || + behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) { + // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by + // simply rejecting the request to use the storage. In the future, if we + // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense + // for non-cookie storage types, this may change. + return false; + } + + MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER); + if (!nsContentUtils::IsTrackingResourceWindow(aWindow)) { return true; } nsCOMPtr<nsIPrincipal> parentPrincipal; nsAutoCString trackingOrigin; - if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(a3rdPartyTrackingWindow), + if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(aWindow), getter_AddRefs(parentPrincipal), trackingOrigin)) { return false; } nsAutoString origin; nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -223,40 +299,124 @@ AntiTrackingCommon::IsFirstPartyStorageA } bool AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel, nsIURI* aURI) { MOZ_ASSERT(aURI); MOZ_ASSERT(aChannel); - MOZ_ASSERT(aChannel->GetIsTrackingResource()); nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); if (!loadInfo) { return true; } + // We need to find the correct principal to check the cookie permission. For + // third-party contexts, we want to check if the top-level window has a custom + // cookie permission. + nsIPrincipal* toplevelPrincipal = loadInfo->TopLevelPrincipal(); + + // If this is already the top-level window, we should use the loading + // principal. + if (!toplevelPrincipal) { + toplevelPrincipal = loadInfo->LoadingPrincipal(); + } + + nsCOMPtr<nsIPrincipal> channelPrincipal; + nsIScriptSecurityManager* ssm = nsScriptSecurityManager::GetScriptSecurityManager(); + nsresult rv = ssm->GetChannelResultPrincipal(aChannel, + getter_AddRefs(channelPrincipal)); + + // If we don't have a loading principal and this is a document channel, we are + // a top-level window! + if (!toplevelPrincipal) { + bool isDocument = false; + nsresult rv2 = aChannel->GetIsMainDocumentChannel(&isDocument); + if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && isDocument) { + toplevelPrincipal = channelPrincipal; + } + } + + // Let's use the triggering principal then. + if (!toplevelPrincipal) { + toplevelPrincipal = loadInfo->TriggeringPrincipal(); + } + + if (NS_WARN_IF(!toplevelPrincipal)) { + return false; + } + + nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal); + if (access != nsICookiePermission::ACCESS_DEFAULT) { + return access != nsICookiePermission::ACCESS_DENY; + } + + if (NS_WARN_IF(NS_FAILED(rv) || !channelPrincipal)) { + return false; + } + + int32_t behavior = CookiesBehavior(channelPrincipal); + if (behavior == nsICookieService::BEHAVIOR_ACCEPT) { + return true; + } + + if (behavior == nsICookieService::BEHAVIOR_REJECT) { + return false; + } + + nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil(); + if (!thirdPartyUtil) { + return true; + } + + bool thirdParty = false; + Unused << thirdPartyUtil->IsThirdPartyChannel(aChannel, + nullptr, + &thirdParty); + // Grant if it's not a 3rd party. + if (!thirdParty) { + return true; + } + + if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN || + behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) { + // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by + // simply rejecting the request to use the storage. In the future, if we + // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense + // for non-cookie storage types, this may change. + return false; + } + + MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER); + nsIPrincipal* parentPrincipal = loadInfo->TopLevelStorageAreaPrincipal(); if (!parentPrincipal) { // parentPrincipal can be null if the parent window is not the top-level // window. if (loadInfo->TopLevelPrincipal()) { return false; } parentPrincipal = loadInfo->TriggeringPrincipal(); if (NS_WARN_IF(!parentPrincipal)) { // Why we are here?!? return true; } } + // Not a tracker. + if (!aChannel->GetIsTrackingResource()) { + return true; + } + + // Let's see if we have to grant the access for this particular channel. + nsCOMPtr<nsIURI> trackingURI; - nsresult rv = aChannel->GetURI(getter_AddRefs(trackingURI)); + rv = aChannel->GetURI(getter_AddRefs(trackingURI)); if (NS_WARN_IF(NS_FAILED(rv))) { return true; } nsAutoString trackingOrigin; rv = nsContentUtils::GetUTFOrigin(trackingURI, trackingOrigin); if (NS_WARN_IF(NS_FAILED(rv))) { return false; @@ -281,39 +441,59 @@ AntiTrackingCommon::IsFirstPartyStorageA rv = pm->TestPermissionFromPrincipal(parentPrincipal, type.get(), &result); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } return result == nsIPermissionManager::ALLOW_ACTION; } +bool +AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal) +{ + MOZ_ASSERT(aPrincipal); + + nsCookieAccess access = CheckCookiePermissionForPrincipal(aPrincipal); + if (access != nsICookiePermission::ACCESS_DEFAULT) { + return access != nsICookiePermission::ACCESS_DENY; + } + + int32_t behavior = CookiesBehavior(aPrincipal); + return behavior != nsICookieService::BEHAVIOR_REJECT; +} + /* static */ bool AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI) { MOZ_ASSERT(aFirstPartyWindow); MOZ_ASSERT(!nsContentUtils::IsTrackingResourceWindow(aFirstPartyWindow)); MOZ_ASSERT(aURI); - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { + if (StaticPrefs::network_cookie_cookieBehavior() != + nsICookieService::BEHAVIOR_REJECT_TRACKER) { return true; } if (!nsContentUtils::IsThirdPartyWindowOrChannel(aFirstPartyWindow, nullptr, aURI)) { return true; } nsCOMPtr<nsIPrincipal> parentPrincipal = nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetPrincipal(); if (NS_WARN_IF(!parentPrincipal)) { return false; } + nsCookieAccess access = CheckCookiePermissionForPrincipal(parentPrincipal); + if (access != nsICookiePermission::ACCESS_DEFAULT) { + return access != nsICookiePermission::ACCESS_DENY; + } + nsAutoString origin; nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } NS_ConvertUTF16toUTF8 utf8Origin(origin);
--- a/toolkit/components/antitracking/AntiTrackingCommon.h +++ b/toolkit/components/antitracking/AntiTrackingCommon.h @@ -41,22 +41,25 @@ public: // For first party window, it's impossible to know if the aURI is a tracking // resource synchronously, so here we return the best guest: if we are sure // that the permission is granted for the origin of aURI, this method returns // true, otherwise false. static bool MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI); - // This can be called only if the a3rdPartyTrackingChannel is _really_ a 3rd - // party context and marked as tracking resource. // It returns true if the URI has access to the first party storage. + // aChannel can be a 3rd party channel, or not. static bool - IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* a3rdPartyTrackingChannel, - nsIURI* aURI); + IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel, nsIURI* aURI); + + // This method checks if the principal has the permission to access to the + // first party storage. + static bool + IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal); // Grant the permission for aOrigin to have access to the first party storage. // This method can handle 2 different scenarios: // - aParentWindow is a 3rd party context, it opens an aOrigin window and the // user interacts with it. We want to grant the permission at the // combination: top-level + aParentWindow + aOrigin. // Ex: example.net loads an iframe tracker.com, which opens a popup // tracker.prg and the user interacts with it. tracker.org is allowed if
--- a/toolkit/components/antitracking/test/browser/3rdParty.html +++ b/toolkit/components/antitracking/test/browser/3rdParty.html @@ -16,16 +16,16 @@ function ok(what, msg) { function is(a, b, msg) { ok(a === b, msg); } onmessage = function(e) { let runnableStr = `(() => {return (${e.data});})();`; let runnable = eval(runnableStr); // eslint-disable-line no-eval - runnable.call(this).then(_ => { + runnable.call(this, /* Phase */ 1).then(_ => { parent.postMessage({ type: "finish" }, "*"); }); }; </script> </body> </html>
--- a/toolkit/components/antitracking/test/browser/3rdPartyOpen.html +++ b/toolkit/components/antitracking/test/browser/3rdPartyOpen.html @@ -1,15 +1,17 @@ <html> <head> <title>A popup!</title> </head> <body> <h1>hi!</h1> <script> -opener.postMessage("hello!", "*"); +if (opener) { + opener.postMessage("hello!", "*"); +} window.close(); </script> </body> </html>
--- a/toolkit/components/antitracking/test/browser/3rdPartyUI.html +++ b/toolkit/components/antitracking/test/browser/3rdPartyUI.html @@ -16,16 +16,16 @@ function ok(what, msg) { function is(a, b, msg) { ok(a === b, msg); } onmessage = function(e) { let runnableStr = `(() => {return (${e.data.callback});})();`; let runnable = eval(runnableStr); // eslint-disable-line no-eval - runnable.call(this).then(_ => { + runnable.call(this, /* Phase */ 3).then(_ => { parent.postMessage({ type: "finish" }, "*"); }); }; </script> </body> </html>
--- a/toolkit/components/antitracking/test/browser/3rdPartyWO.html +++ b/toolkit/components/antitracking/test/browser/3rdPartyWO.html @@ -16,27 +16,36 @@ function ok(what, msg) { function is(a, b, msg) { ok(a === b, msg); } onmessage = function(e) { let runnableStr = `(() => {return (${e.data.blockingCallback});})();`; let runnable = eval(runnableStr); // eslint-disable-line no-eval - runnable.call(this).then(_ => { + runnable.call(this, /* Phase */ 2).then(_ => { info("Let's do a window.open()"); return new Promise(resolve => { - onmessage = resolve; - window.open("3rdPartyOpen.html"); + + if (location.search == "?noopener") { + let features = "noopener"; + + window.open("3rdPartyOpen.html", undefined, features); + setTimeout(resolve, 1000); + } else { + onmessage = resolve; + + window.open("3rdPartyOpen.html"); + } }); }).then(_ => { info("The popup has been dismissed!"); let runnableStr = `(() => {return (${e.data.nonBlockingCallback});})();`; let runnable = eval(runnableStr); // eslint-disable-line no-eval - return runnable.call(this); + return runnable.call(this, /* Phase */ 2); }).then(_ => { parent.postMessage({ type: "finish" }, "*"); }); }; </script> </body> </html>
--- a/toolkit/components/antitracking/test/browser/browser.ini +++ b/toolkit/components/antitracking/test/browser/browser.ini @@ -11,14 +11,16 @@ support-files = popup.html [browser_blockingCookies.js] support-files = server.sjs [browser_blockingIndexedDb.js] [browser_blockingStorage.js] [browser_blockingWorkers.js] [browser_blockingMessaging.js] +[browser_blockingNoOpener.js] +[browser_existingCookiesForSubresources.js] [browser_imageCache.js] support-files = image.sjs [browser_subResources.js] support-files = subResources.sjs [browser_script.js] support-files = tracker.js
new file mode 100644 --- /dev/null +++ b/toolkit/components/antitracking/test/browser/browser_blockingNoOpener.js @@ -0,0 +1,35 @@ +gFeatures = "noopener"; + +AntiTracking.runTest("Blocking in the case of noopener windows", + async _ => { + try { + localStorage.foo = 42; + ok(false, "LocalStorage cannot be used!"); + } catch (e) { + ok(true, "LocalStorage cannot be used!"); + is(e.name, "SecurityError", "We want a security error message."); + } + }, + async phase => { + switch (phase) { + case 1: + localStorage.foo = 42; + ok(true, "LocalStorage is allowed"); + break; + case 2: + try { + localStorage.foo = 42; + ok(false, "LocalStorage cannot be used!"); + } catch (e) { + ok(true, "LocalStorage cannot be used!"); + is(e.name, "SecurityError", "We want a security error message."); + } + break; + } + }, + async _ => { + await new Promise(resolve => { + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve()); + }); + }, + null, true, false);
new file mode 100644 --- /dev/null +++ b/toolkit/components/antitracking/test/browser/browser_existingCookiesForSubresources.js @@ -0,0 +1,183 @@ +ChromeUtils.import("resource://gre/modules/Services.jsm"); + +add_task(async function() { + info("Starting subResources test"); + + await SpecialPowers.flushPrefEnv(); + await SpecialPowers.pushPrefEnv({"set": [ + ["privacy.trackingprotection.enabled", false], + ["privacy.trackingprotection.pbmode.enabled", false], + ["privacy.trackingprotection.annotate_channels", true], + ]}); + + await UrlClassifierTestUtils.addTestTrackers(); + + info("Creating a new tab"); + let tab = BrowserTestUtils.addTab(gBrowser, TEST_3RD_PARTY_PAGE); + gBrowser.selectedTab = tab; + + let browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + info("Loading tracking scripts and tracking images before restricting 3rd party cookies"); + await ContentTask.spawn(browser, null, async function() { + // Let's load the script twice here. + { + let src = content.document.createElement("script"); + let p = new content.Promise(resolve => { src.onload = resolve; }); + content.document.body.appendChild(src); + src.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=script"; + await p; + } + { + let src = content.document.createElement("script"); + let p = new content.Promise(resolve => { src.onload = resolve; }); + content.document.body.appendChild(src); + src.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=script"; + await p; + } + + // Let's load an image twice here. + { + let img = content.document.createElement("img"); + let p = new content.Promise(resolve => { img.onload = resolve; }); + content.document.body.appendChild(img); + img.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=image"; + await p; + } + { + let img = content.document.createElement("img"); + let p = new content.Promise(resolve => { img.onload = resolve; }); + content.document.body.appendChild(img); + img.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=image"; + await p; + } + }); + + await fetch("https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?result&what=image") + .then(r => r.text()) + .then(text => { + is(text, 1, "Cookies received for images"); + }); + + await fetch("https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?result&what=script") + .then(r => r.text()) + .then(text => { + is(text, 1, "Cookies received for scripts"); + }); + + info("Removing the tab"); + BrowserTestUtils.removeTab(tab); + + Services.perms.removeAll(); + + // Now set up our prefs + await SpecialPowers.pushPrefEnv({"set": [ + ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER], + ]}); + + info("Creating a new tab"); + tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE); + gBrowser.selectedTab = tab; + + browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + info("Creating a 3rd party content"); + await ContentTask.spawn(browser, + { page: TEST_3RD_PARTY_PAGE, + callback: (async _ => {}).toString(), + }, + async function(obj) { + await new content.Promise(resolve => { + let ifr = content.document.createElement("iframe"); + ifr.onload = function() { + info("Sending code to the 3rd party content"); + ifr.contentWindow.postMessage(obj.callback, "*"); + }; + + content.addEventListener("message", function msg(event) { + if (event.data.type == "finish") { + content.removeEventListener("message", msg); + resolve(); + return; + } + + if (event.data.type == "ok") { + ok(event.data.what, event.data.msg); + return; + } + + if (event.data.type == "info") { + info(event.data.msg); + return; + } + + ok(false, "Unknown message"); + }); + + content.document.body.appendChild(ifr); + ifr.src = obj.page; + }); + }); + + info("Loading tracking scripts and tracking images again"); + await ContentTask.spawn(browser, null, async function() { + // Let's load the script twice here. + { + let src = content.document.createElement("script"); + let p = new content.Promise(resolve => { src.onload = resolve; }); + content.document.body.appendChild(src); + src.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=script"; + await p; + } + { + let src = content.document.createElement("script"); + let p = new content.Promise(resolve => { src.onload = resolve; }); + content.document.body.appendChild(src); + src.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=script"; + await p; + } + + // Let's load an image twice here. + { + let img = content.document.createElement("img"); + let p = new content.Promise(resolve => { img.onload = resolve; }); + content.document.body.appendChild(img); + img.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=image"; + await p; + } + { + let img = content.document.createElement("img"); + let p = new content.Promise(resolve => { img.onload = resolve; }); + content.document.body.appendChild(img); + img.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=image"; + await p; + } + }); + + await fetch("https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?result&what=image") + .then(r => r.text()) + .then(text => { + is(text, 0, "No cookie received for images."); + }); + + await fetch("https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?result&what=script") + .then(r => r.text()) + .then(text => { + is(text, 0, "No cookie received received for scripts."); + }); + + info("Removing the tab"); + BrowserTestUtils.removeTab(tab); + + UrlClassifierTestUtils.cleanupTestTrackers(); +}); + +add_task(async function() { + info("Cleaning up."); + await new Promise(resolve => { + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve()); + }); +}); +
--- a/toolkit/components/antitracking/test/browser/browser_script.js +++ b/toolkit/components/antitracking/test/browser/browser_script.js @@ -1,16 +1,16 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); add_task(async function() { info("Starting subResources test"); await SpecialPowers.flushPrefEnv(); await SpecialPowers.pushPrefEnv({"set": [ - ["privacy.restrict3rdpartystorage.enabled", true], + ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER], ["privacy.trackingprotection.enabled", false], ["privacy.trackingprotection.pbmode.enabled", false], ["privacy.trackingprotection.annotate_channels", true], ]}); await UrlClassifierTestUtils.addTestTrackers(); info("Creating a new tab");
--- a/toolkit/components/antitracking/test/browser/browser_subResources.js +++ b/toolkit/components/antitracking/test/browser/browser_subResources.js @@ -1,16 +1,16 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); add_task(async function() { info("Starting subResources test"); await SpecialPowers.flushPrefEnv(); await SpecialPowers.pushPrefEnv({"set": [ - ["privacy.restrict3rdpartystorage.enabled", true], + ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER], ["privacy.trackingprotection.enabled", false], ["privacy.trackingprotection.pbmode.enabled", false], ["privacy.trackingprotection.annotate_channels", true], ]}); await UrlClassifierTestUtils.addTestTrackers(); info("Creating a new tab");
--- a/toolkit/components/antitracking/test/browser/head.js +++ b/toolkit/components/antitracking/test/browser/head.js @@ -4,47 +4,51 @@ const TEST_3RD_PARTY_DOMAIN = "https://t const TEST_PATH = "browser/toolkit/components/antitracking/test/browser/"; const TEST_TOP_PAGE = TEST_DOMAIN + TEST_PATH + "page.html"; const TEST_POPUP_PAGE = TEST_DOMAIN + TEST_PATH + "popup.html"; const TEST_3RD_PARTY_PAGE = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdParty.html"; const TEST_3RD_PARTY_PAGE_WO = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartyWO.html"; const TEST_3RD_PARTY_PAGE_UI = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartyUI.html"; +var gFeatures = undefined; + let {UrlClassifierTestUtils} = ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm", {}); this.AntiTracking = { runTest(name, callbackTracking, callbackNonTracking, cleanupFunction, extraPrefs, windowOpenTest = true, userInteractionTest = true) { // Here we want to test that a 3rd party context is simply blocked. this._createTask(name, true, callbackTracking, extraPrefs); this._createCleanupTask(cleanupFunction); if (callbackNonTracking) { - // Here we want to test that a 3rd party context is not blocked if pref is off. + // Phase 1: Here we want to test that a 3rd party context is not blocked if pref is off. this._createTask(name, false, callbackNonTracking); this._createCleanupTask(cleanupFunction); - // Permission granted when there is a window.open() + // Phase 2: Here we want to test that a third-party context doesn't + // get blocked with when the same origin is opened through window.open(). if (windowOpenTest) { this._createWindowOpenTask(name, callbackTracking, callbackNonTracking, extraPrefs); this._createCleanupTask(cleanupFunction); } - // Permission granted when there is user-interaction. + // Phase 3: Here we want to test that a third-party context doesn't + // get blocked with user interaction present if (userInteractionTest) { this._createUserInteractionTask(name, callbackTracking, callbackNonTracking, extraPrefs); this._createCleanupTask(cleanupFunction); } } }, async _setupTest(blocking, extraPrefs) { await SpecialPowers.flushPrefEnv(); await SpecialPowers.pushPrefEnv({"set": [ - ["privacy.restrict3rdpartystorage.enabled", blocking], + ["network.cookie.cookieBehavior", blocking ? Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER : Ci.nsICookieService.BEHAVIOR_ACCEPT], ["privacy.trackingprotection.enabled", false], ["privacy.trackingprotection.pbmode.enabled", false], ["privacy.trackingprotection.annotate_channels", blocking], ]}); if (extraPrefs && Array.isArray(extraPrefs) && extraPrefs.length) { await SpecialPowers.pushPrefEnv({"set": extraPrefs }); } @@ -125,19 +129,24 @@ this.AntiTracking = { info("Creating a new tab"); let tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE); gBrowser.selectedTab = tab; let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); + let pageURL = TEST_3RD_PARTY_PAGE_WO; + if (gFeatures == "noopener") { + pageURL += "?noopener"; + } + info("Creating a 3rd party content"); await ContentTask.spawn(browser, - { page: TEST_3RD_PARTY_PAGE_WO, + { page: pageURL, blockingCallback: blockingCallback.toString(), nonBlockingCallback: nonBlockingCallback.toString(), }, async function(obj) { await new content.Promise(resolve => { let ifr = content.document.createElement("iframe"); ifr.onload = function() { info("Sending code to the 3rd party content");
--- a/toolkit/crashreporter/CrashAnnotations.yaml +++ b/toolkit/crashreporter/CrashAnnotations.yaml @@ -573,16 +573,21 @@ ProxyStreamUnmarshalStatus: the various value this annotation can take. type: string ProxyStreamValid: description: > Set to "false" when encountering an invalid IPC proxy stream. type: string +RecordReplayError: + description: > + Any fatal error that occurred while recording/replaying a tab. + type: string + ReleaseChannel: description: > Application release channel (e.g. default, beta, ...) type: string ping: true RemoteType: description: >
--- a/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.cc +++ b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.cc @@ -27,16 +27,18 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "mac/crash_generation/crash_generation_client.h" #include "mac/crash_generation/crash_generation_server.h" #include "common/mac/MachIPC.h" +#include "mozilla/recordreplay/ChildIPC.h" + namespace google_breakpad { bool CrashGenerationClient::RequestDumpForException( int exception_type, int exception_code, int exception_subcode, mach_port_t crashing_thread) { // The server will send a message to this port indicating that it @@ -48,16 +50,24 @@ bool CrashGenerationClient::RequestDumpF message.AddDescriptor(crashing_thread); // crashing thread message.AddDescriptor(MACH_PORT_NULL); // handler thread message.AddDescriptor(acknowledge_port.GetPort()); // message receive port