Merge inbound to mozilla-central. a=merge
authorBogdan Tara <btara@mozilla.com>
Fri, 20 Jul 2018 00:49:06 +0300
changeset 427378 690cb3015db6645b335ac4835a50073cb6a3e23c
parent 427377 d67618d9ba00e9384114989daddbbdc86daf1ad7 (current diff)
parent 427332 a2ecff8f25c842188469ec713f3942f0abea6d6c (diff)
child 427379 345ecb7b1895c6535145c279e44d44aea090ff55
child 427387 4aa8eb6e5ca75109e97e0c3f64c5529fd74c94eb
child 427433 bb9c6d756b8b3cefefb00625ffab37d71e5bc3ae
push id105450
push userbtara@mozilla.com
push dateThu, 19 Jul 2018 21:56:22 +0000
treeherdermozilla-inbound@345ecb7b1895 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
690cb3015db6 / 63.0a1 / 20180719220047 / files
nightly linux64
690cb3015db6 / 63.0a1 / 20180719220047 / files
nightly mac
690cb3015db6 / 63.0a1 / 20180719220047 / files
nightly win32
690cb3015db6 / 63.0a1 / 20180719220047 / files
nightly win64
690cb3015db6 / 63.0a1 / 20180719220047 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
testing/web-platform/meta/css/css-backgrounds/border-image-018.xht.ini
testing/web-platform/meta/css/css-scoping-1/__dir__.ini
testing/web-platform/meta/css/selectors4/__dir__.ini
toolkit/components/telemetry/CombinedStacks.cpp
tools/profiler/core/platform.cpp
--- a/browser/config/mozconfigs/linux64/code-coverage
+++ b/browser/config/mozconfigs/linux64/code-coverage
@@ -8,9 +8,11 @@ ac_add_options --disable-install-strip
 ac_add_options --disable-elf-hack
 ac_add_options --disable-sandbox
 ac_add_options --disable-profiling
 ac_add_options --disable-warnings-as-errors
 ac_add_options --enable-coverage
 
 export CFLAGS="--coverage"
 export CXXFLAGS="--coverage"
-export LDFLAGS="--coverage -L$TOOLTOOL_DIR/gtk3/usr/local/lib"
+export LDFLAGS="--coverage -L$topsrcdir/clang/lib/clang/7.0.0/lib/linux/"
+export RUSTFLAGS="-Ccodegen-units=1 -Zprofile -Zno-landing-pads"
+export LIBS="-lclang_rt.profile-x86_64"
new file mode 100644
--- /dev/null
+++ b/build/build-clang/clang-7-pre-linux64.json
@@ -0,0 +1,22 @@
+{
+    "llvm_revision": "336407",
+    "stages": "3",
+    "build_libcxx": true,
+    "build_type": "Release",
+    "assertions": false,
+    "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
+    "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
+    "lld_repo": "https://llvm.org/svn/llvm-project/lld/trunk",
+    "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
+    "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
+    "libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/trunk",
+    "python_path": "/usr/bin/python2.7",
+    "gcc_dir": "/builds/worker/workspace/build/src/gcc",
+    "cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
+    "cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
+    "as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
+    "patches": [
+      "find_symbolizer_linux.patch",
+      "rename_gcov_flush.patch"
+    ]
+}
new file mode 100644
--- /dev/null
+++ b/build/build-clang/rename_gcov_flush.patch
@@ -0,0 +1,14 @@
+Index: compiler-rt/lib/profile/GCDAProfiling.c
+===================================================================
+diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
+--- a/compiler-rt/lib/profile/GCDAProfiling.c	(revisione 336380)
++++ b/compiler-rt/lib/profile/GCDAProfiling.c	(copia locale)
+@@ -555,7 +555,7 @@
+   fn_list_insert(&flush_fn_list, fn);
+ }
+ 
+-void __gcov_flush() {
++void __llvm_gcov_flush() {
+   struct fn_node* curr = flush_fn_list.head;
+ 
+   while (curr) {
--- a/js/src/doc/Debugger/Debugger.md
+++ b/js/src/doc/Debugger/Debugger.md
@@ -112,16 +112,24 @@ function or `undefined`; otherwise a `Ty
 Handler functions run in the same thread in which the event occurred.
 They run in the compartment to which they belong, not in a debuggee
 compartment.
 
 <code>onNewScript(<i>script</i>, <i>global</i>)</code>
 :   New code, represented by the [`Debugger.Script`][script] instance
     <i>script</i>, has been loaded in the scope of the debuggees.
 
+    Since each function has its own [`Debugger.Script`][script], separate from
+    the top-level code or function that encloses it, loading JavaScript code
+    typically introduces not just a single script, but a tree of scripts
+    representing the top-level code and any functions it includes. The
+    `onNewScript` hook reports only the root script of such a tree. If
+    necessary, the handler function can use the scripts' `getChildScripts`
+    method to walk the tree and obtain all the newly introduced scripts.
+
     This method's return value is ignored.
 
 <code>onNewPromise(<i>promise</i>)</code>
 :   A new Promise object, referenced by the [`Debugger.Object`][object] instance
     *promise*, has been allocated in the scope of the debuggees. The Promise's
     allocation stack can be obtained using the *promiseAllocationStack*
     accessor property of the [`Debugger.Object`][object] instance *promise*.
 
--- a/js/src/gc/GC-inl.h
+++ b/js/src/gc/GC-inl.h
@@ -224,18 +224,20 @@ class ZoneCellIter<TenuredCell> {
 
         // We have a single-threaded runtime, so there's no need to protect
         // against other threads iterating or allocating. However, we do have
         // background finalization; we may have to wait for this to finish if
         // it's currently active.
         if (IsBackgroundFinalized(kind) && zone->arenas.needBackgroundFinalizeWait(kind))
             rt->gc.waitBackgroundSweepEnd();
         arenaIter.init(zone, kind);
-        if (!arenaIter.done())
+        if (!arenaIter.done()) {
             cellIter.init(arenaIter.get(), CellIterMayNeedBarrier);
+            settle();
+        }
     }
 
   public:
     ZoneCellIter(JS::Zone* zone, AllocKind kind) {
         // If we are iterating a nursery-allocated kind then we need to
         // evict first so that we can see all things.
         if (IsNurseryAllocable(kind))
             zone->runtimeFromMainThread()->gc.evictNursery();
@@ -259,26 +261,29 @@ class ZoneCellIter<TenuredCell> {
         return cellIter.get<T>();
     }
 
     TenuredCell* getCell() const {
         MOZ_ASSERT(!done());
         return cellIter.getCell();
     }
 
-    void next() {
-        MOZ_ASSERT(!done());
-        cellIter.next();
-        if (cellIter.done()) {
-            MOZ_ASSERT(!arenaIter.done());
+    void settle() {
+        while (cellIter.done() && !arenaIter.done()) {
             arenaIter.next();
             if (!arenaIter.done())
                 cellIter.reset(arenaIter.get());
         }
     }
+
+    void next() {
+        MOZ_ASSERT(!done());
+        cellIter.next();
+        settle();
+    }
 };
 
 // Iterator over the cells in a Zone, where the GC type (JSString, JSObject) is
 // known, for a single AllocKind. Example usages:
 //
 //   for (auto obj = zone->cellIter<JSObject>(AllocKind::OBJECT0); !obj.done(); obj.next())
 //       ...
 //
--- a/taskcluster/ci/build/linux.yml
+++ b/taskcluster/ci/build/linux.yml
@@ -965,18 +965,18 @@ linux64-ccov/debug:
             - builds/releng_base_firefox.py
             - builds/releng_base_linux_64_builds.py
         script: "mozharness/scripts/fx_desktop_build.py"
         secrets: true
         custom-build-variant-cfg: code-coverage-debug
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
-        - linux64-clang
-        - linux64-rust
+        - linux64-clang-7
+        - linux64-rust-nightly
         - linux64-gcc
         - linux64-sccache
 
 linux64-ccov/opt:
     description: "Linux64-CCov Opt"
     index:
         product: firefox
         job-name: linux64-ccov-opt
--- a/taskcluster/ci/test/test-platforms.yml
+++ b/taskcluster/ci/test/test-platforms.yml
@@ -78,16 +78,17 @@ linux64-pgo/opt:
         - web-platform-tests
         - talos
         - raptor
 
 linux64-asan/opt:
     build-platform: linux64-asan/opt
     test-sets:
         - common-tests
+        - web-platform-tests
 
 # Stylo sequential runs check memory and performance when using a single thread.
 linux64-stylo-sequential/opt:
     build-platform: linux64/opt
     test-sets:
         - awsy-stylo-sequential
 
 # QR builds just run a subset right now.
--- a/taskcluster/ci/test/web-platform.yml
+++ b/taskcluster/ci/test/web-platform.yml
@@ -33,16 +33,17 @@ web-platform-tests:
             linux32/debug: both
             default: true
     run-on-projects:
         by-test-platform:
             linux64-qr/.*: ['release', 'try']  # skip on integration branches due to high load
             default: built-projects
     tier:
         by-test-platform:
+            linux64-asan/opt: 2
             linux64-qr/.*: 2  # can't be tier-1 if it's not running on integration branches
             default: default
     mozharness:
         chunked: true
         extra-options:
             - --test-type=testharness
 
 web-platform-tests-headless:
@@ -87,16 +88,17 @@ web-platform-tests-reftests:
             linux32/debug: both
             default: true
     run-on-projects:
         by-test-platform:
             linux64-qr/.*: ['release', 'try']  # skip on integration branches due to high load
             default: built-projects
     tier:
         by-test-platform:
+            linux64-asan/opt: 2
             linux64-qr/.*: 2  # can't be tier-1 if it's not running on integration branches
             default: default
     mozharness:
         extra-options:
             - --test-type=reftest
 
 web-platform-tests-reftests-headless:
     description: "Web platform reftest headless run"
@@ -131,16 +133,17 @@ web-platform-tests-wdspec:
         extra-options:
             - --test-type=wdspec
     run-on-projects:
         by-test-platform:
             linux64-qr/.*: ['release', 'try']  # skip on integration branches due to high load
             default: built-projects
     tier:
         by-test-platform:
+            linux64-asan/opt: 2
             linux64-qr/.*: 2  # can't be tier-1 if it's not running on integration branches
             default: default
 
 web-platform-tests-wdspec-headless:
     description: "Web platform webdriver-spec headless run"
     suite: web-platform-tests-wdspec
     treeherder-symbol: W(WdH)
     run-on-projects: []  # disabled pending releng approval
--- a/taskcluster/ci/toolchain/linux.yml
+++ b/taskcluster/ci/toolchain/linux.yml
@@ -65,16 +65,37 @@ linux64-clang-6:
             - 'build/build-clang/build-clang.py'
             - 'build/build-clang/clang-6-linux64.json'
             - 'taskcluster/scripts/misc/tooltool-download.sh'
         toolchain-alias: linux64-clang
         toolchain-artifact: public/build/clang.tar.xz
     toolchains:
         - linux64-gcc-4.9
 
+linux64-clang-7:
+    description: "Clang 7 toolchain build"
+    treeherder:
+        kind: build
+        platform: toolchains/opt
+        symbol: TL(clang7)
+        tier: 1
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux-xlarge
+    worker:
+        max-run-time: 7200
+    run:
+        using: toolchain-script
+        script: build-clang-7-linux.sh
+        resources:
+            - 'build/build-clang/build-clang.py'
+            - 'build/build-clang/clang-7-pre-linux64.json'
+            - 'taskcluster/scripts/misc/tooltool-download.sh'
+        toolchain-artifact: public/build/clang.tar.xz
+    toolchains:
+        - linux64-gcc-4.9
+
 linux64-clang-6-macosx-cross:
     description: "Clang 6 toolchain build with MacOS Compiler RT libs"
     treeherder:
         kind: build
         platform: toolchains/opt
         symbol: TL(clang6-macosx-cross)
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-linux
@@ -454,17 +475,17 @@ linux64-rust-nightly:
     worker:
         max-run-time: 7200
         env:
             UPLOAD_DIR: artifacts
     run:
         using: toolchain-script
         script: repack_rust.py
         arguments: [
-            '--channel', 'nightly-2018-06-20',
+            '--channel', 'nightly-2018-07-18',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
             '--target', 'i686-unknown-linux-gnu',
         ]
         toolchain-artifact: public/build/rustc.tar.xz
 
 linux64-rust-macos-1.28:
     description: "rust repack with macos-cross support"
new file mode 100755
--- /dev/null
+++ b/taskcluster/scripts/misc/build-clang-7-linux.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+set -x -e -v
+
+# This script is for building clang for Linux.
+
+WORKSPACE=$HOME/workspace
+HOME_DIR=$WORKSPACE/build
+UPLOAD_DIR=$HOME/artifacts
+
+cd $HOME_DIR/src
+
+. taskcluster/scripts/misc/tooltool-download.sh
+
+# gets a bit too verbose here
+set +x
+
+cd build/build-clang
+# |mach python| sets up a virtualenv for us!
+../../mach python ./build-clang.py -c clang-7-pre-linux64.json
+
+set -x
+
+# Put a tarball in the artifacts dir
+mkdir -p $UPLOAD_DIR
+cp clang.tar.* $UPLOAD_DIR
--- a/testing/mozbase/mozleak/mozleak/__init__.py
+++ b/testing/mozbase/mozleak/mozleak/__init__.py
@@ -4,10 +4,11 @@
 
 """
 mozleak is a library for extracting memory leaks from leak logs files.
 """
 
 from __future__ import absolute_import
 
 from .leaklog import process_leak_log
+from .lsan import LSANLeaks
 
-__all__ = ['process_leak_log']
+__all__ = ['process_leak_log', 'LSANLeaks']
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozleak/mozleak/lsan.py
@@ -0,0 +1,171 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# 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/.
+
+from __future__ import absolute_import
+import re
+
+
+class LSANLeaks(object):
+
+    """
+    Parses the log when running an LSAN build, looking for interesting stack frames
+    in allocation stacks
+    """
+
+    def __init__(self, logger, scope=None, allowed=None):
+        self.logger = logger
+        self.inReport = False
+        self.fatalError = False
+        self.symbolizerError = False
+        self.foundFrames = set()
+        self.recordMoreFrames = None
+        self.currStack = None
+        self.maxNumRecordedFrames = 4
+        self.summaryData = None
+        self.scope = scope
+        self.allowedMatch = None
+        self.sawError = False
+
+        # Don't various allocation-related stack frames, as they do not help much to
+        # distinguish different leaks.
+        unescapedSkipList = [
+            "malloc", "js_malloc", "malloc_", "__interceptor_malloc", "moz_xmalloc",
+            "calloc", "js_calloc", "calloc_", "__interceptor_calloc", "moz_xcalloc",
+            "realloc", "js_realloc", "realloc_", "__interceptor_realloc", "moz_xrealloc",
+            "new",
+            "js::MallocProvider",
+        ]
+        self.skipListRegExp = re.compile(
+            "^" + "|".join([re.escape(f) for f in unescapedSkipList]) + "$")
+
+        self.startRegExp = re.compile(
+            "==\d+==ERROR: LeakSanitizer: detected memory leaks")
+        self.fatalErrorRegExp = re.compile(
+            "==\d+==LeakSanitizer has encountered a fatal error.")
+        self.symbolizerOomRegExp = re.compile(
+            "LLVMSymbolizer: error reading file: Cannot allocate memory")
+        self.stackFrameRegExp = re.compile("    #\d+ 0x[0-9a-f]+ in ([^(</]+)")
+        self.sysLibStackFrameRegExp = re.compile(
+            "    #\d+ 0x[0-9a-f]+ \(([^+]+)\+0x[0-9a-f]+\)")
+        self.summaryRegexp = re.compile(
+            "SUMMARY: AddressSanitizer: (\d+) byte\(s\) leaked in (\d+) allocation\(s\).")
+        self.setAllowed(allowed)
+
+    def setAllowed(self, allowedLines):
+        if not allowedLines:
+            self.allowedRegexp = None
+        else:
+            self.allowedRegexp = re.compile(
+                "^" + "|".join([re.escape(f) for f in allowedLines]))
+
+    def log(self, line):
+        if re.match(self.startRegExp, line):
+            self.inReport = True
+            # Downgrade this from an ERROR
+            self.sawError = True
+            return "LeakSanitizer: detected memory leaks"
+
+        if re.match(self.fatalErrorRegExp, line):
+            self.fatalError = True
+            return line
+
+        if re.match(self.symbolizerOomRegExp, line):
+            self.symbolizerError = True
+            return line
+
+        if not self.inReport:
+            return line
+
+        if line.startswith("Direct leak") or line.startswith("Indirect leak"):
+            self._finishStack()
+            self.recordMoreFrames = True
+            self.currStack = []
+            return line
+
+        summaryData = self.summaryRegexp.match(line)
+        if summaryData:
+            assert self.summaryData is None
+            self._finishStack()
+            self.inReport = False
+            self.summaryData = (int(item) for item in summaryData.groups())
+            # We don't return the line here because we want to control whether the
+            # leak is seen as an expected failure later
+            return
+
+        if not self.recordMoreFrames:
+            return line
+
+        stackFrame = re.match(self.stackFrameRegExp, line)
+        if stackFrame:
+            # Split the frame to remove any return types.
+            frame = stackFrame.group(1).split()[-1]
+            if not re.match(self.skipListRegExp, frame):
+                self._recordFrame(frame)
+            return line
+
+        sysLibStackFrame = re.match(self.sysLibStackFrameRegExp, line)
+        if sysLibStackFrame:
+            # System library stack frames will never match the skip list,
+            # so don't bother checking if they do.
+            self._recordFrame(sysLibStackFrame.group(1))
+
+        # If we don't match either of these, just ignore the frame.
+        # We'll end up with "unknown stack" if everything is ignored.
+        return line
+
+    def process(self):
+        failures = 0
+
+        if self.summaryData:
+            allowed = all(allowed for _, allowed in self.foundFrames)
+            self.logger.lsan_summary(*self.summaryData, allowed=allowed)
+            self.summaryData = None
+
+        if self.fatalError:
+            self.logger.error("LeakSanitizer | LeakSanitizer has encountered a fatal error.")
+            failures += 1
+
+        if self.symbolizerError:
+            self.logger.error("LeakSanitizer | LLVMSymbolizer was unable to allocate memory.\n"
+                              "This will cause leaks that "
+                              "should be ignored to instead be reported as an error")
+            failures += 1
+
+        if self.foundFrames:
+            self.logger.info("LeakSanitizer | To show the "
+                             "addresses of leaked objects add report_objects=1 to LSAN_OPTIONS\n"
+                             "This can be done in testing/mozbase/mozrunner/mozrunner/utils.py")
+
+            for frames, allowed in self.foundFrames:
+                self.logger.lsan_leak(frames, scope=self.scope, allowed_match=allowed)
+                if not allowed:
+                    failures += 1
+
+        if self.sawError and not (self.summaryData or
+                                  self.foundFrames or
+                                  self.fatalError or
+                                  self.symbolizerError):
+            self.logger.error("LeakSanitizer | Memory leaks detected but no leak report generated")
+
+        self.sawError = False
+
+        return failures
+
+    def _finishStack(self):
+        if self.recordMoreFrames and len(self.currStack) == 0:
+            self.currStack = {"unknown stack"}
+        if self.currStack:
+            self.foundFrames.add((tuple(self.currStack), self.allowedMatch))
+            self.currStack = None
+            self.allowedMatch = None
+        self.recordMoreFrames = False
+        self.numRecordedFrames = 0
+
+    def _recordFrame(self, frame):
+        if self.allowedMatch is None and self.allowedRegexp is not None:
+            self.allowedMatch = frame if self.allowedRegexp.match(frame) else None
+        self.currStack.append(frame)
+        self.numRecordedFrames += 1
+        if self.numRecordedFrames >= self.maxNumRecordedFrames:
+            self.recordMoreFrames = False
--- a/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
@@ -219,16 +219,36 @@ class MachFormatter(base.BaseFormatter):
 
     def valgrind_error(self, data):
         rv = " " + data['primary'] + "\n"
         for line in data['secondary']:
             rv = rv + line + "\n"
 
         return rv
 
+    def lsan_leak(self, data):
+        allowed = data.get("allowed_match")
+        if allowed:
+            prefix = self.term.yellow("FAIL")
+        else:
+            prefix = self.term.red("UNEXPECTED-FAIL")
+
+        return "%s LeakSanitizer: leak at %s" % (prefix, ", ".join(data["frames"]))
+
+    def lsan_summary(self, data):
+        allowed = data.get("allowed", False)
+        if allowed:
+            prefix = self.term.yellow("WARNING")
+        else:
+            prefix = self.term.red("ERROR")
+
+        return ("%s | LeakSanitizer | "
+                "SUMMARY: AddressSanitizer: %d byte(s) leaked in %d allocation(s)." %
+                (prefix, data["bytes"], data["allocations"]))
+
     def test_status(self, data):
         test = self._get_test_id(data)
         if test not in self.status_buffer:
             self.status_buffer[test] = {"count": 0, "unexpected": 0, "pass": 0}
         self.status_buffer[test]["count"] += 1
 
         if data["status"] == "PASS":
             self.status_buffer[test]["pass"] += 1
--- a/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py
@@ -272,16 +272,31 @@ class TbplFormatter(BaseFormatter):
         return rv
 
     def lint(self, data):
         fmt = "TEST-UNEXPECTED-{level} | {path}:{lineno}{column} | {message} ({rule})"
         data["column"] = ":%s" % data["column"] if data["column"] else ""
         data['rule'] = data['rule'] or data['linter'] or ""
         return fmt.append(fmt.format(**data))
 
+    def lsan_leak(self, data):
+        frames = data.get("frames")
+        allowed_match = data.get("allowed_match")
+        frame_list = ", ".join(frames)
+        prefix = "TEST-UNEXPECTED-FAIL" if not allowed_match else "TEST-FAIL"
+        suffix = ("" if not allowed_match
+                  else "INFO | LeakSanitizer | Frame %s matched a expected leak\n" % allowed_match)
+        return "%s | LeakSanitizer | leak at %s\n%s" % (prefix, frame_list, suffix)
+
+    def lsan_summary(self, data):
+        level = "INFO" if data.get("allowed", False) else "ERROR"
+        return ("%s | LeakSanitizer | "
+                "SUMMARY: AddressSanitizer: %d byte(s) leaked in %d allocation(s)." %
+                (level, data["bytes"], data["allocations"]))
+
     def _format_suite_summary(self, suite, summary):
         counts = summary['counts']
         logs = summary['unexpected_logs']
 
         total = sum(self.summary.aggregate('count', counts).values())
         expected = sum(self.summary.aggregate('expected', counts).values())
         status_str = "{}/{}".format(expected, total)
         rv = ["{}: {}".format(suite, status_str)]
--- a/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
@@ -54,15 +54,23 @@ class StatusHandler(object):
                 self.unexpected_statuses["PASS"] += 1
             elif data["count"] > data["max_expected"]:
                 self.unexpected_statuses["FAIL"] += 1
             elif data["count"]:
                 self.expected_statuses["FAIL"] += 1
             else:
                 self.expected_statuses["PASS"] += 1
 
+        if action == "lsan_leak":
+            if not data.get("allowed_match"):
+                self.unexpected_statuses["FAIL"] += 1
+
+        if action == "lsan_summary":
+            if not data.get("allowed", False):
+                self.unexpected_statuses["FAIL"] += 1
+
     def summarize(self):
         return RunSummary(
             dict(self.unexpected_statuses),
             dict(self.expected_statuses),
             dict(self.log_level_counts),
             dict(self.action_counts),
         )
--- a/testing/mozbase/mozlog/mozlog/logtypes.py
+++ b/testing/mozbase/mozlog/mozlog/logtypes.py
@@ -240,16 +240,22 @@ class Int(DataType):
 
 
 class Any(DataType):
 
     def convert(self, data):
         return data
 
 
+class Boolean(DataType):
+
+    def convert(self, data):
+        return bool(data)
+
+
 class Tuple(ContainerType):
 
     def _format_item_type(self, item_type):
         superfmt = super(Tuple, self)._format_item_type
 
         if isinstance(item_type, (tuple, list)):
             return [superfmt(t) for t in item_type]
         return (superfmt(item_type),)
--- a/testing/mozbase/mozlog/mozlog/structuredlog.py
+++ b/testing/mozbase/mozlog/mozlog/structuredlog.py
@@ -6,17 +6,18 @@ from __future__ import absolute_import, 
 
 from multiprocessing import current_process
 from threading import current_thread, Lock
 import json
 import sys
 import time
 import traceback
 
-from .logtypes import Unicode, TestId, TestList, Status, SubStatus, Dict, List, Int, Any, Tuple
+from .logtypes import (Unicode, TestId, TestList, Status, SubStatus, Dict, List, Int, Any, Tuple,
+                       Boolean)
 from .logtypes import log_action, convertor_registry
 import six
 
 """Structured Logging for recording test results.
 
 Allowed actions, and subfields:
   suite_start
       tests  - List of test names
@@ -48,16 +49,28 @@ Allowed actions, and subfields:
       command - Command line of the process
       data - Output data from the process
 
   assertion_count
       count - Number of assertions produced
       min_expected - Minimum expected number of assertions
       max_expected - Maximum expected number of assertions
 
+  lsan_leak
+      frames - List of stack frames from the leak report
+      scope - An identifier for the set of tests run during the browser session
+              (e.g. a directory name)
+      allowed_match - A stack frame in the list that matched a rule meaning the
+                      leak is expected
+
+  lsan_summary
+      bytes - Number of bytes leaked
+      allocations - Number of allocations
+      allowed - Boolean indicating whether all detected leaks matched allow rules
+
   log
       level [CRITICAL | ERROR | WARNING |
              INFO | DEBUG] - level of the logging message
       message - Message to log
 
 Subfields for all messages:
       action - the action type of the current message
       time - the timestamp in ms since the epoch of the log message
@@ -459,16 +472,28 @@ class StructuredLogger(object):
         """Log count of assertions produced when running a test.
 
         :param count: - Number of assertions produced
         :param min_expected: - Minimum expected number of assertions
         :param max_expected: - Maximum expected number of assertions
         """
         self._log_data("assertion_count", data)
 
+    @log_action(List(Unicode, "frames"),
+                Unicode("scope", optional=True, default=None),
+                Unicode("allowed_match", optional=True, default=None))
+    def lsan_leak(self, data):
+        self._log_data("lsan_leak", data)
+
+    @log_action(Int("bytes"),
+                Int("allocations"),
+                Boolean("allowed", optional=True, default=False))
+    def lsan_summary(self, data):
+        self._log_data("lsan_summary", data)
+
     @log_action()
     def shutdown(self, data):
         """Shutdown the logger.
 
         This logs a 'shutdown' action after which any further attempts to use
         the logger will raise a :exc:`LoggerShutdownError`.
 
         This is also called implicitly from the destructor or
--- a/testing/mozharness/scripts/web_platform_tests.py
+++ b/testing/mozharness/scripts/web_platform_tests.py
@@ -8,16 +8,18 @@ import copy
 import os
 import sys
 
 from datetime import datetime, timedelta
 
 # load modules from parent dir
 sys.path.insert(1, os.path.dirname(sys.path[0]))
 
+import mozinfo
+
 from mozharness.base.errors import BaseErrorList
 from mozharness.base.script import PreScriptAction
 from mozharness.base.vcs.vcsbase import MercurialScript
 from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
 from mozharness.mozilla.testing.codecoverage import (
     CodeCoverageMixin,
     code_coverage_config_options
 )
@@ -176,28 +178,30 @@ class WebPlatformTest(TestingMixin, Merc
         cmd = [self.query_python_path('python'), '-u']
         cmd.append(os.path.join(dirs["abs_wpttest_dir"], run_file_name))
 
         # Make sure that the logging directory exists
         if self.mkdir_p(dirs["abs_blob_upload_dir"]) == -1:
             self.fatal("Could not create blobber upload directory")
             # Exit
 
+        mozinfo.find_and_update_from_json(dirs['abs_test_install_dir'])
+
         cmd += ["--log-raw=-",
                 "--log-raw=%s" % os.path.join(dirs["abs_blob_upload_dir"],
                                               "wpt_raw.log"),
                 "--log-wptreport=%s" % os.path.join(dirs["abs_blob_upload_dir"],
                                                     "wptreport.json"),
                 "--log-errorsummary=%s" % os.path.join(dirs["abs_blob_upload_dir"],
                                                        "wpt_errorsummary.log"),
                 "--binary=%s" % self.binary_path,
                 "--symbols-path=%s" % self.query_symbols_url(),
                 "--stackwalk-binary=%s" % self.query_minidump_stackwalk(),
                 "--stackfix-dir=%s" % os.path.join(dirs["abs_test_install_dir"], "bin"),
-                "--run-by-dir=3",
+                "--run-by-dir=%i" % (3 if not mozinfo.info["asan"] else 0),
                 "--no-pause-after-test"]
 
         if not sys.platform.startswith("linux"):
             cmd += ["--exclude=css"]
 
         for test_type in test_types:
             cmd.append("--test-type=%s" % test_type)
 
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/building-paths/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/compositing/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/drawing-images-to-the-canvas/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/drawing-paths-to-the-canvas/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/drawing-rectangles-to-the-canvas/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/fill-and-stroke-styles/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/imagebitmap/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/path-objects/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/shadows/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, PORT_Alloc_Util, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/text-styles/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/the-canvas-state/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/2dcontext/transformations/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/FileAPI/FileReader/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, EntrySlotOrCreate, Init, MakeNotNull, MakeUnique, Malloc, NS_NewCStringInputStream, NewEmptyScopeData, NewPage, ProtoAndIfaceCache, _GetAddrInfo_Portable, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BackgroundHangThread::ReportHang, mozilla::NonBlockingAsyncInputStream::AsyncWait, mozilla::NonBlockingAsyncInputStream::Create, mozilla::dom::Blob::Constructor, mozilla::dom::Blob::Create, mozilla::dom::FileReader::Constructor, mozilla::dom::StringBlobImpl::Create, mozilla::dom::WorkerPrivate::GetOrCreateGlobalScope, mozilla::dom::WorkerPrivate::WorkerPrivate, mozilla::dom::WorkerThread::Create, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost, nsThread::nsThread]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/FileAPI/file/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/IndexedDB/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/WebCryptoAPI/derive_bits_keys/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/WebCryptoAPI/generateKey/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [PORT_Alloc_Util]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost,  js_pod_malloc, js_pod_calloc, js_pod_realloc, js_arena_calloc,js_pod_arena_calloc, maybe_pod_calloc, pod_calloc, make_zeroed_pod_array, js_arena_malloc]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/content-security-policy/frame-ancestors/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/content-security-policy/img-src/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/content-security-policy/navigate-to/__dir__.ini
+++ b/testing/web-platform/meta/content-security-policy/navigate-to/__dir__.ini
@@ -1,2 +1,2 @@
 disabled:
-  if os == "win": https://bugzilla.mozilla.org/show_bug.cgi?id=1450635
\ No newline at end of file
+  if os == "win": https://bugzilla.mozilla.org/show_bug.cgi?id=1450635
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/content-security-policy/reporting/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/content-security-policy/script-src/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/content-security-policy/style-src/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/cookies/samesite/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/CSS2/normal-flow/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/CSS2/selectors/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html.ini
+++ b/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html.ini
@@ -1,3 +1,3 @@
 [mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html]
-  expected: 
+  expected:
     if os == "linux" and not webrender: FAIL
--- a/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html.ini
+++ b/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html.ini
@@ -1,3 +1,3 @@
 [mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html]
-  expected: 
+  expected:
     if os == "linux" and not webrender: FAIL
--- a/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-border-radius.html.ini
+++ b/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-border-radius.html.ini
@@ -1,3 +1,3 @@
 [mix-blend-mode-parent-with-border-radius.html]
-  expected: 
+  expected:
     if os == "linux" and not webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-backgrounds/border-image-018.xht.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[border-image-018.xht]
-  expected:
-    if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-grid/alignment/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scoping-1/__dir__.ini
+++ /dev/null
@@ -1,1 +0,0 @@
-prefs: [dom.webcomponents.shadowdom.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/i18n/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/css/css-timing/__dir__.ini
+++ b/testing/web-platform/meta/css/css-timing/__dir__.ini
@@ -1,2 +1,1 @@
-prefs: [dom.animations-api.core.enabled:true,
-        layout.css.frames-timing.enabled:true]
+prefs: [dom.animations-api.core.enabled:true, layout.css.frames-timing.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-typed-om/the-stylepropertymap/properties/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-variables/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-writing-modes/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/cssom-view/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/css/selectors/__dir__.ini
+++ b/testing/web-platform/meta/css/selectors/__dir__.ini
@@ -1,2 +1,1 @@
 prefs: [dom.webcomponents.shadowdom.enabled:true]
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/selectors4/__dir__.ini
+++ /dev/null
@@ -1,1 +0,0 @@
-prefs: [dom.webcomponents.shadowdom.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/custom-elements/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [EntrySlotOrCreate, Malloc, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BackgroundHangThread::ReportHang]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/custom-elements/reactions/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [EntrySlotOrCreate, Malloc, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BackgroundHangThread::ReportHang]
--- a/testing/web-platform/meta/dom/events/__dir__.ini
+++ b/testing/web-platform/meta/dom/events/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [privacy.reduceTimerPrecision:false]
\ No newline at end of file
+prefs: [privacy.reduceTimerPrecision:false]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/dom/nodes/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/dom/ranges/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/editing/run/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/encoding/legacy-mb-japanese/euc-jp/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/encoding/legacy-mb-japanese/iso-2022-jp/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/encoding/legacy-mb-japanese/shift_jis/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/encoding/legacy-mb-korean/euc-kr/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/encoding/legacy-mb-tchinese/big5/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/encrypted-media/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, MakeUnique, Malloc, NewPage, Realloc, mozilla::EMEDecryptor::EMEDecryptor, mozilla::SchedulerGroup::CreateEventTargetFor, mozilla::dom::MediaKeys::CreateCDMProxy, mozilla::dom::nsIContentChild::GetConstructedEventTarget]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/feature-policy/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/fetch/api/abort/__dir__.ini
+++ b/testing/web-platform/meta/fetch/api/abort/__dir__.ini
@@ -1,2 +1,2 @@
-prefs: [javascript.options.streams:true,
-        dom.streams.enabled:true]
+prefs: [javascript.options.streams:true, dom.streams.enabled:true]
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::DOMException::Create, mozilla::dom::FetchStream::Create, mozilla::dom::Performance::CreateForMainThread]
--- a/testing/web-platform/meta/fetch/api/basic/__dir__.ini
+++ b/testing/web-platform/meta/fetch/api/basic/__dir__.ini
@@ -1,2 +1,2 @@
-prefs: [javascript.options.streams:true,
-        dom.streams.enabled:true]
+prefs: [javascript.options.streams:true, dom.streams.enabled:true]
+lsan-allowed: [mozilla::dom::FetchStream::Create, mozilla::dom::WorkerPrivate::WorkerPrivate, nsSegmentedBuffer::AppendNewSegment]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/fetch/api/request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
--- a/testing/web-platform/meta/fetch/api/response/__dir__.ini
+++ b/testing/web-platform/meta/fetch/api/response/__dir__.ini
@@ -1,2 +1,1 @@
-prefs: [javascript.options.streams:true,
-        dom.streams.enabled:true]
+prefs: [javascript.options.streams:true, dom.streams.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/fetch/range/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, Create, CreateInner, FetchDriverObserver, Malloc, NewPage, PLDHashTable::Add, Realloc, allocate, mozilla::ThrottledEventQueue::Create, mozilla::dom::InternalRequest::GetRequestConstructorCopy, mozilla::dom::PerformanceStorageWorker::Create, mozilla::dom::PromiseWorkerProxy::Create, mozilla::dom::WorkerFetchResolver::Create, mozilla::dom::WorkerLoadInfo::InterfaceRequestor::InterfaceRequestor, nsSegmentedBuffer::AppendNewSegment, nsSupportsWeakReference::GetWeakReference]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/fetch/security/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/geolocation-API/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/hr-time/__dir__.ini
+++ b/testing/web-platform/meta/hr-time/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [privacy.reduceTimerPrecision:false]
\ No newline at end of file
+prefs: [privacy.reduceTimerPrecision:false]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/browsers/browsing-the-web/history-traversal/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/browsers/history/the-history-interface/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/browsers/history/the-location-interface/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/dom/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/embedded-content/media-elements/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/embedded-content/media-elements/loading-the-media-resource/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/embedded-content/media-elements/track/track-element/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/embedded-content/the-iframe-element/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, _GetAddrInfo_Portable, mozilla::net::AddrInfo::AddrInfo, nsHostResolver::ResolveHost]
--- a/testing/web-platform/meta/html/semantics/forms/__dir__.ini
+++ b/testing/web-platform/meta/html/semantics/forms/__dir__.ini
@@ -1,1 +1,1 @@
-max-asserts: 3
\ No newline at end of file
+max-asserts: 3
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/forms/constraints/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/forms/form-submission-0/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
--- a/testing/web-platform/meta/html/semantics/forms/the-form-element/__dir__.ini
+++ b/testing/web-platform/meta/html/semantics/forms/the-form-element/__dir__.ini
@@ -1,1 +1,1 @@
-max-asserts: 2
\ No newline at end of file
+max-asserts: 2
--- a/testing/web-platform/meta/html/semantics/forms/the-input-element/__dir__.ini
+++ b/testing/web-platform/meta/html/semantics/forms/the-input-element/__dir__.ini
@@ -1,2 +1,1 @@
 max-asserts: 2
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/execution-timing/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/syntax/parsing/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/the-xhtml-syntax/parsing-xhtml-documents/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/infrastructure/assumptions/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/infrastructure/server/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, CreateInner, MakeUnique, PLDHashTable::ChangeTable, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::SchedulerGroup::CreateEventTargetFor, mozilla::WeakPtr, mozilla::dom::WebSocket::ConstructorCommon, mozilla::dom::WebSocket::WebSocket, mozilla::net::BaseWebSocketChannel::InitLoadInfo, mozilla::net::WebSocketChannelChild::AsyncOpen, mozilla::net::WebSocketEventService::GetOrCreate, nsSupportsWeakReference::GetWeakReference]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/js/builtins/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/keyboard-lock/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/longtask-timing/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/mathml/relations/css-styling/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/media-capabilities/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/media-capabilities/idlharness.html.ini
@@ -0,0 +1,2 @@
+[idlharness.html]
+  prefs: [media.media-capabilities.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/media-source/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
--- a/testing/web-platform/meta/mediacapture-streams/__dir__.ini
+++ b/testing/web-platform/meta/mediacapture-streams/__dir__.ini
@@ -1,2 +1,2 @@
-prefs: [media.navigator.permission.disabled:true,
-        media.navigator.streams.fake:true]
+prefs: [media.navigator.permission.disabled:true, media.navigator.streams.fake:true]
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/mimesniff/mime-types/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/mixed-content/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/mixed-content/audio-tag/no-opt-in/cross-origin-http/top-level/no-redirect/optionally-blockable/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/offscreen-canvas/fill-and-stroke-styles/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/offscreen-canvas/path-objects/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/offscreen-canvas/the-offscreen-canvas/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/paint-timing/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/performance-timeline/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread, mozilla::dom::PerformanceObserver::Constructor, xpc::CreateSandboxObject]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/picture-in-picture/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/attr-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/attr-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/attr-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [AllocateProtoAndIfaceCache, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc, Alloc, AllocateProtoAndIfaceCache, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/attr-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/attr-referrer/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/http-rp/cross-origin/http-http/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/http-rp/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/http-rp/same-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/http-rp/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/meta-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/meta-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/meta-referrer/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/meta-referrer/cross-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/meta-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/meta-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/meta-referrer/same-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer-when-downgrade/meta-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/attr-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/attr-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/attr-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/attr-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/attr-referrer/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, js_pod_calloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, mozilla::BasePrincipal::CreateCodebasePrincipal, Alloc, XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/meta-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/meta-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/no-referrer/meta-referrer/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/attr-referrer/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/attr-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, js_pod_calloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/meta-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/meta-referrer/cross-origin/http-http/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/meta-referrer/cross-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/meta-referrer/cross-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/meta-referrer/cross-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/attr-referrer/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/attr-referrer/cross-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/attr-referrer/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/http-rp/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/http-rp/cross-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/http-rp/same-origin/http-http/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/http-rp/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/http-rp/same-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/http-rp/same-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/http-rp/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/http-rp/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/meta-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/meta-referrer/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/meta-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/meta-referrer/same-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/meta-referrer/same-origin/http-http/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/origin/meta-referrer/same-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/attr-referrer/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/attr-referrer/cross-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/attr-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/attr-referrer/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/attr-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/attr-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/http-rp/cross-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/http-rp/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/http-rp/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/http-rp/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/meta-referrer/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/meta-referrer/cross-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/meta-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/meta-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/same-origin/meta-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/attr-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/attr-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, mozilla::BasePrincipal::CreateCodebasePrincipal, Alloc, XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/attr-referrer/cross-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/attr-referrer/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/attr-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/http-rp/cross-origin/http-http/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/http-rp/cross-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/http-rp/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/http-rp/cross-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/http-rp/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/http-rp/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/http-rp/same-origin/http-http/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/cross-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/cross-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/same-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/attr-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/attr-referrer/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/attr-referrer/cross-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/attr-referrer/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/attr-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, js_pod_calloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/attr-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/attr-referrer/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/attr-referrer/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/http-rp/cross-origin/http-http/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/http-rp/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/http-rp/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/http-rp/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/http-rp/same-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/http-rp/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/http-rp/same-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/meta-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/meta-referrer/cross-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/meta-referrer/cross-origin/http-http/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/meta-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/meta-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/strict-origin/meta-referrer/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/attr-referrer/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/attr-referrer/cross-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/attr-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/attr-referrer/cross-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/attr-referrer/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/cross-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/cross-origin/http-http/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/cross-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/same-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, js_pod_calloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/http-rp/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/meta-referrer/cross-origin/http-http/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/meta-referrer/cross-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/meta-referrer/cross-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/meta-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [XPCWrappedNative::GetNewOrUsed, js_pod_calloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/meta-referrer/same-origin/http-http/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/meta-referrer/same-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, nsStringBuffer::Alloc, Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unsafe-url/meta-referrer/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/attr-referrer/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/attr-referrer/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/attr-referrer/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/attr-referrer/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/http-rp/cross-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/http-rp/cross-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/http-rp/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/http-rp/same-origin/http-http/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/http-rp/same-origin/http-https/img-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/meta-referrer/cross-origin/http-http/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/meta-referrer/cross-origin/http-https/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, NewEmptyScopeData, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/meta-referrer/same-origin/http-http/iframe-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, js_new, mozilla::dom::ChromeUtils::GenerateQI, Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/meta-referrer/same-origin/http-https/fetch-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/meta-referrer/same-origin/http-https/script-tag/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/referrer-policy/unset-referrer-policy/meta-referrer/same-origin/http-https/xhr-request/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, XPCWrappedNative::GetNewOrUsed, js_new, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::dom::ChromeUtils::GenerateQI, nsStringBuffer::Alloc]
--- a/testing/web-platform/meta/resource-timing/__dir__.ini
+++ b/testing/web-platform/meta/resource-timing/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [privacy.reduceTimerPrecision:false]
\ No newline at end of file
+prefs: [privacy.reduceTimerPrecision:false]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/screen-orientation/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/selection/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/server-timing/__dir__.ini
+++ b/testing/web-platform/meta/server-timing/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [privacy.reduceTimerPrecision:false]
\ No newline at end of file
+prefs: [privacy.reduceTimerPrecision:false]
--- a/testing/web-platform/meta/service-workers/__dir__.ini
+++ b/testing/web-platform/meta/service-workers/__dir__.ini
@@ -1,2 +1,1 @@
-prefs: [javascript.options.streams:true,
-        dom.streams.enabled:true]
+prefs: [javascript.options.streams:true, dom.streams.enabled:true]
--- a/testing/web-platform/meta/service-workers/service-worker/__dir__.ini
+++ b/testing/web-platform/meta/service-workers/service-worker/__dir__.ini
@@ -1,1 +1,2 @@
 prefs: [dom.serviceWorkers.enabled:true]
+lsan-allowed: [Alloc, Create, CreateInner, MakeUnique, NewEmptyScopeData, NewPage, OrInsert, Realloc, SharedMutex, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::ThrottledEventQueue::Create, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread, mozilla::dom::PerformanceStorageWorker::Create, mozilla::dom::WorkerPrivate::WorkerPrivate, mozilla::net::HttpBaseChannel::HttpBaseChannel, mozilla::net::HttpChannelChild::HttpChannelChild, mozilla::net::nsHttpHandler::NewProxiedChannel2]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/service-workers/service-worker/navigation-preload/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/user-timing/__dir__.ini
+++ b/testing/web-platform/meta/user-timing/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [privacy.reduceTimerPrecision:false]
\ No newline at end of file
+prefs: [privacy.reduceTimerPrecision:false]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/visual-viewport/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/web-animations/timing-model/animations/__dir__.ini
+++ b/testing/web-platform/meta/web-animations/timing-model/animations/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [privacy.reduceTimerPrecision:false]
\ No newline at end of file
+prefs: [privacy.reduceTimerPrecision:false]
--- a/testing/web-platform/meta/web-animations/timing-model/timelines/__dir__.ini
+++ b/testing/web-platform/meta/web-animations/timing-model/timelines/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [privacy.reduceTimerPrecision:false]
\ No newline at end of file
+prefs: [privacy.reduceTimerPrecision:false]
--- a/testing/web-platform/meta/webaudio/the-audio-api/__dir__.ini
+++ b/testing/web-platform/meta/webaudio/the-audio-api/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [privacy.reduceTimerPrecision:false]
\ No newline at end of file
+prefs: [privacy.reduceTimerPrecision:false]
--- a/testing/web-platform/meta/webgl/__dir__.ini
+++ b/testing/web-platform/meta/webgl/__dir__.ini
@@ -1,1 +1,1 @@
-disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1241943
\ No newline at end of file
+disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1241943
--- a/testing/web-platform/meta/webrtc/__dir__.ini
+++ b/testing/web-platform/meta/webrtc/__dir__.ini
@@ -1,2 +1,1 @@
-prefs: [media.navigator.permission.disabled:true,
-        media.navigator.streams.fake:true]
+prefs: [media.navigator.permission.disabled:true, media.navigator.streams.fake:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/websockets/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Alloc, Create, Malloc, NewPage, PLDHashTable::Add, PLDHashTable::ChangeTable, Realloc, RecvOnAcknowledge, RecvOnStop, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::SchedulerGroup::CreateEventTargetFor, mozilla::ThrottledEventQueue::Create, mozilla::WeakPtr, mozilla::dom::WebSocket::WebSocket, mozilla::dom::WorkerCSPEventListener::Create, mozilla::dom::nsIContentChild::GetConstructedEventTarget, mozilla::net::WebSocketChannelChild::RecvOnServerClose, nsAtomTable::Atomize]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/websockets/keeping-connection-open/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/workers/modules/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: []
--- a/testing/web-platform/meta/xhr/__dir__.ini
+++ b/testing/web-platform/meta/xhr/__dir__.ini
@@ -1,2 +1,1 @@
-prefs: [dom.xhr.lowercase_header.enabled:true,
-        javascript.options.streams:true]
+prefs: [dom.xhr.lowercase_header.enabled:true, javascript.options.streams:true]
--- a/testing/web-platform/moz.build
+++ b/testing/web-platform/moz.build
@@ -9,25 +9,29 @@ WEB_PLATFORM_TESTS_MANIFESTS += [
     ('mozilla/meta/MANIFEST.json', 'mozilla/tests/')
 ]
 
 TEST_HARNESS_FILES['web-platform'] += [
     'mach_commands_base.py',
     'mach_test_package_commands.py',
     'outbound/**',
     'runtests.py',
-    'wptrunner.ini'
+    'wptrunner.ini',
 ]
 
-TEST_HARNESS_FILES['web-platform'].certs = [
+TEST_HARNESS_FILES['web-platform'].certs += [
     'certs/cacert.pem',
     'certs/web-platform.test.key',
     'certs/web-platform.test.pem',
 ]
 
+TEST_HARNESS_FILES['web-platform'].prefs += [
+    '/build/sanitizers/lsan_suppressions.txt',
+]
+
 with Files("**"):
     SCHEDULES.exclusive = [
         'web-platform-tests',
         'web-platform-tests-reftests',
         'web-platform-tests-wdspec',
     ]
 
 with Files("moz.build"):
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, nsHostResolver::ResolveHost]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/meta/_mozilla/wasm/__dir__.ini
@@ -0,0 +1,1 @@
+lsan-allowed: [Init, nsHostResolver::ResolveHost]
--- a/testing/web-platform/mozilla/meta/binast/large.https.html.ini
+++ b/testing/web-platform/mozilla/meta/binast/large.https.html.ini
@@ -1,4 +1,5 @@
 [large.https.html]
   [Check we can load BinAST over HTTPS]
     expected:
-      if release_or_beta or os == "android" or (os == "win" and processor == "x86"): FAIL
+      if release_or_beta or (os == "android") or ((os == "win") and (processor == "x86")): FAIL
+
--- a/testing/web-platform/mozilla/meta/binast/small.https.html.ini
+++ b/testing/web-platform/mozilla/meta/binast/small.https.html.ini
@@ -1,4 +1,5 @@
 [small.https.html]
   [Check we can load BinAST over HTTPS]
     expected:
-      if release_or_beta or os == "android" or (os == "win" and processor == "x86"): FAIL
+      if release_or_beta or (os == "android") or ((os == "win") and (processor == "x86")): FAIL
+
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py
@@ -82,17 +82,17 @@ class Browser(object):
     def setup(self):
         """Used for browser-specific setup that happens at the start of a test run"""
         pass
 
     def settings(self, test):
         return {}
 
     @abstractmethod
-    def start(self, **kwargs):
+    def start(self, group_metadata, **kwargs):
         """Launch the browser object and get it into a state where is is ready to run tests"""
         pass
 
     @abstractmethod
     def stop(self, force=False):
         """Stop the running browser process."""
         pass
 
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -5,17 +5,17 @@ import signal
 import subprocess
 import sys
 
 import mozinfo
 import mozleak
 from mozprocess import ProcessHandler
 from mozprofile import FirefoxProfile, Preferences
 from mozrunner import FirefoxRunner
-from mozrunner.utils import get_stack_fixer_function
+from mozrunner.utils import test_environment, get_stack_fixer_function
 from mozcrash import mozcrash
 
 from .base import (get_free_port,
                    Browser,
                    ExecutorBrowser,
                    require_arg,
                    cmd_arg,
                    browser_command)
@@ -75,16 +75,17 @@ def browser_kwargs(test_type, run_info_d
             "ca_certificate_path": kwargs["ssl_env"].ca_cert_path(),
             "e10s": kwargs["gecko_e10s"],
             "stackfix_dir": kwargs["stackfix_dir"],
             "binary_args": kwargs["binary_args"],
             "timeout_multiplier": get_timeout_multiplier(test_type,
                                                          run_info_data,
                                                          **kwargs),
             "leak_check": kwargs["leak_check"],
+            "asan": run_info_data.get("asan"),
             "stylo_threads": kwargs["stylo_threads"],
             "chaos_mode_flags": kwargs["chaos_mode_flags"],
             "config": kwargs["config"]}
 
 
 def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
                     **kwargs):
     executor_kwargs = base_executor_kwargs(test_type, server_config,
@@ -146,18 +147,18 @@ def update_properties():
 class FirefoxBrowser(Browser):
     used_ports = set()
     init_timeout = 60
     shutdown_timeout = 60
 
     def __init__(self, logger, binary, prefs_root, test_type, extra_prefs=None, debug_info=None,
                  symbols_path=None, stackwalk_binary=None, certutil_binary=None,
                  ca_certificate_path=None, e10s=False, stackfix_dir=None,
-                 binary_args=None, timeout_multiplier=None, leak_check=False, stylo_threads=1,
-                 chaos_mode_flags=None, config=None):
+                 binary_args=None, timeout_multiplier=None, leak_check=False, asan=False,
+                 stylo_threads=1, chaos_mode_flags=None, config=None):
         Browser.__init__(self, logger)
         self.binary = binary
         self.prefs_root = prefs_root
         self.test_type = test_type
         self.extra_prefs = extra_prefs
         self.marionette_port = None
         self.runner = None
         self.debug_info = debug_info
@@ -173,33 +174,48 @@ class FirefoxBrowser(Browser):
             self.stack_fixer = get_stack_fixer_function(stackfix_dir,
                                                         self.symbols_path)
         else:
             self.stack_fixer = None
 
         if timeout_multiplier:
             self.init_timeout = self.init_timeout * timeout_multiplier
 
+        self.asan = asan
+        self.lsan_allowed = None
+        self.leak_check = leak_check
         self.leak_report_file = None
-        self.leak_check = leak_check
+        self.lsan_handler = None
         self.stylo_threads = stylo_threads
         self.chaos_mode_flags = chaos_mode_flags
 
     def settings(self, test):
-        return {"check_leaks": self.leak_check and not test.leaks}
+        self.lsan_allowed = test.lsan_allowed
+        return {"check_leaks": self.leak_check and not test.leaks,
+                "lsan_allowed": test.lsan_allowed}
 
-    def start(self, **kwargs):
+    def start(self, group_metadata=None, **kwargs):
+        if group_metadata is None:
+            group_metadata = {}
+
         if self.marionette_port is None:
             self.marionette_port = get_free_port(2828, exclude=self.used_ports)
             self.used_ports.add(self.marionette_port)
 
-        env = os.environ.copy()
-        env["MOZ_CRASHREPORTER"] = "1"
-        env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
-        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
+        if self.asan:
+            print "Setting up LSAN"
+            self.lsan_handler = mozleak.LSANLeaks(self.logger,
+                                                  scope=group_metadata.get("scope", "/"),
+                                                  allowed=self.lsan_allowed)
+
+        env = test_environment(xrePath=os.path.dirname(self.binary),
+                               debugger=self.debug_info is not None,
+                               log=self.logger,
+                               lsanPath=self.prefs_root)
+
         env["STYLO_THREADS"] = str(self.stylo_threads)
         if self.chaos_mode_flags is not None:
             env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)
 
         preferences = self.load_prefs()
 
         self.profile = FirefoxProfile(preferences=preferences)
         self.profile.set_preferences({"marionette.port": self.marionette_port,
@@ -210,18 +226,18 @@ class FirefoxBrowser(Browser):
                                       "dom.send_after_paint_to_content": True,
                                       "network.preload": True})
         if self.e10s:
             self.profile.set_preferences({"browser.tabs.remote.autostart": True})
 
         if self.test_type == "reftest":
             self.profile.set_preferences({"layout.interruptible-reflow.enabled": False})
 
-        if self.leak_check and kwargs.get("check_leaks", True):
-            self.leak_report_file = os.path.join(self.profile.profile, "runtests_leaks.log")
+        if self.leak_check:
+            self.leak_report_file = os.path.join(self.profile.profile, "runtests_leaks_%s.log" % os.getpid())
             if os.path.exists(self.leak_report_file):
                 os.remove(self.leak_report_file)
             env["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
         else:
             self.leak_report_file = None
 
         # Bug 1262954: winxp + e10s, disable hwaccel
         if (self.e10s and platform.system() in ("Windows", "Microsoft") and
@@ -290,34 +306,36 @@ class FirefoxBrowser(Browser):
                     if not force or not clean:
                         retcode = stop_f()
                         if retcode is not None:
                             self.logger.info("Browser exited with return code %s" % retcode)
                             break
             except OSError:
                 # This can happen on Windows if the process is already dead
                 pass
+        self.process_leaks()
         self.logger.debug("stopped")
 
     def process_leaks(self):
         self.logger.debug("PROCESS LEAKS %s" % self.leak_report_file)
-        if self.leak_report_file is None:
-            return
-        mozleak.process_leak_log(
-            self.leak_report_file,
-            leak_thresholds={
-                "default": 0,
-                "tab": 10000,  # See dependencies of bug 1051230.
-                # GMP rarely gets a log, but when it does, it leaks a little.
-                "geckomediaplugin": 20000,
-            },
-            ignore_missing_leaks=["geckomediaplugin"],
-            log=self.logger,
-            stack_fixer=self.stack_fixer
-        )
+        if self.lsan_handler:
+            self.lsan_handler.process()
+        if self.leak_report_file is not None:
+            mozleak.process_leak_log(
+                self.leak_report_file,
+                leak_thresholds={
+                    "default": 0,
+                    "tab": 10000,  # See dependencies of bug 1051230.
+                    # GMP rarely gets a log, but when it does, it leaks a little.
+                    "geckomediaplugin": 20000,
+                },
+                ignore_missing_leaks=["geckomediaplugin"],
+                log=self.logger,
+                stack_fixer=self.stack_fixer
+            )
 
     def pid(self):
         if self.runner.process_handler is None:
             return None
 
         try:
             return self.runner.process_handler.pid
         except AttributeError:
@@ -326,28 +344,30 @@ class FirefoxBrowser(Browser):
     def on_output(self, line):
         """Write a line of output from the firefox process to the log"""
         if "GLib-GObject-CRITICAL" in line:
             return
         if line:
             data = line.decode("utf8", "replace")
             if self.stack_fixer:
                 data = self.stack_fixer(data)
-            self.logger.process_output(self.pid(),
-                                      data,
-                                      command=" ".join(self.runner.command))
+            if self.lsan_handler:
+                data = self.lsan_handler.log(data)
+            if data is not None:
+                self.logger.process_output(self.pid(),
+                                           data,
+                                           command=" ".join(self.runner.command))
 
     def is_alive(self):
         if self.runner:
             return self.runner.is_running()
         return False
 
-    def cleanup(self):
-        self.stop()
-        self.process_leaks()
+    def cleanup(self, force=False):
+        self.stop(force)
 
     def executor_browser(self):
         assert self.marionette_port is not None
         return ExecutorBrowser, {"marionette_port": self.marionette_port}
 
     def check_for_crashes(self):
         dump_dir = os.path.join(self.profile.profile, "minidumps")
 
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestexpected.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestexpected.py
@@ -56,22 +56,37 @@ def prefs(node):
     def value(ini_value):
         if isinstance(ini_value, (str, unicode)):
             return tuple(ini_value.split(":", 1))
         else:
             return (ini_value, None)
 
     try:
         node_prefs = node.get("prefs")
-        rv = dict(value(item) for item in node_prefs)
+        if type(node_prefs) in (str, unicode):
+            rv = dict(value(node_prefs))
+        else:
+            rv = dict(value(item) for item in node_prefs)
     except KeyError:
         rv = {}
     return rv
 
 
+def lsan_allowed(node):
+    try:
+        node_items = node.get("lsan-allowed")
+        if isinstance(node_items, (str, unicode)):
+            rv = {node_items}
+        else:
+            rv = set(node_items)
+    except KeyError:
+        rv = set()
+    return rv
+
+
 class ExpectedManifest(ManifestItem):
     def __init__(self, name, test_path, url_base):
         """Object representing all the tests in a particular manifest
 
         :param name: Name of the AST Node associated with this object.
                      Should always be None since this should always be associated with
                      the root node of the AST.
         :param test_path: Path of the test file associated with this manifest.
@@ -132,16 +147,20 @@ class ExpectedManifest(ManifestItem):
     @property
     def tags(self):
         return tags(self)
 
     @property
     def prefs(self):
         return prefs(self)
 
+    @property
+    def lsan_allowed(self):
+        return lsan_allowed(self)
+
 
 class DirectoryManifest(ManifestItem):
     @property
     def disabled(self):
         return bool_prop("disabled", self)
 
     @property
     def restart_after(self):
@@ -162,16 +181,20 @@ class DirectoryManifest(ManifestItem):
     @property
     def tags(self):
         return tags(self)
 
     @property
     def prefs(self):
         return prefs(self)
 
+    @property
+    def lsan_allowed(self):
+        return lsan_allowed(self)
+
 
 class TestNode(ManifestItem):
     def __init__(self, name):
         """Tree node associated with a particular test in a manifest
 
         :param name: name of the test"""
         assert name is not None
         ManifestItem.__init__(self, name)
@@ -219,16 +242,20 @@ class TestNode(ManifestItem):
     @property
     def tags(self):
         return tags(self)
 
     @property
     def prefs(self):
         return prefs(self)
 
+    @property
+    def lsan_allowed(self):
+        return lsan_allowed(self)
+
     def append(self, node):
         """Add a subtest to the current test
 
         :param node: AST Node associated with the subtest"""
         child = ManifestItem.append(self, node)
         self.subtests[child.name] = child
 
     def get_subtest(self, name):
@@ -270,16 +297,17 @@ def get_manifest(metadata_root, test_pat
             return static.compile(f,
                                   run_info,
                                   data_cls_getter=data_cls_getter,
                                   test_path=test_path,
                                   url_base=url_base)
     except IOError:
         return None
 
+
 def get_dir_manifest(path, run_info):
     """Get the ExpectedManifest for a particular test path, or None if there is no
     metadata stored for that test path.
 
     :param path: Full path to the ini file
     :param run_info: Dictionary of properties of the test run for which the expectation
                      values should be computed.
     """
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py
@@ -31,16 +31,20 @@ is updated with the changes, and the res
 """
 
 
 class ConditionError(Exception):
     def __init__(self, cond=None):
         self.cond = cond
 
 
+class UpdateError(Exception):
+    pass
+
+
 Value = namedtuple("Value", ["run_info", "value"])
 
 
 def data_cls_getter(output_node, visited_node):
     # visited_node is intentionally unused
     if output_node is None:
         return ExpectedManifest
     elif isinstance(output_node, ExpectedManifest):
@@ -70,16 +74,19 @@ class ExpectedManifest(ManifestItem):
         ManifestItem.__init__(self, node)
         self.child_map = {}
         self.test_path = test_path
         self.url_base = url_base
         assert self.url_base is not None
         self.modified = False
         self.boolean_properties = boolean_properties
         self.property_order = property_order
+        self.update_properties = {
+            "lsan": LsanUpdate(self),
+        }
 
     def append(self, child):
         ManifestItem.append(self, child)
         if child.id in self.child_map:
             print "Warning: Duplicate heading %s" % child.id
         self.child_map[child.id] = child
 
     def _remove_child(self, child):
@@ -101,16 +108,29 @@ class ExpectedManifest(ManifestItem):
 
         return test_id in self.child_map
 
     @property
     def url(self):
         return urlparse.urljoin(self.url_base,
                                 "/".join(self.test_path.split(os.path.sep)))
 
+    def set_lsan(self, run_info, result):
+        """Set the result of the test in a particular run
+
+        :param run_info: Dictionary of run_info parameters corresponding
+                         to this run
+        :param result: Lsan violations detected"""
+
+        self.update_properties["lsan"].set(run_info, result)
+
+    def coalesce_properties(self, stability):
+        for prop_update in self.update_properties.itervalues():
+            prop_update.coalesce(stability)
+
 
 class TestNode(ManifestItem):
     def __init__(self, node):
         """Tree node associated with a particular test in a manifest
 
         :param node: AST node associated with the test"""
 
         ManifestItem.__init__(self, node)
@@ -326,19 +346,25 @@ class PropertyUpdate(object):
                                 if result.value != unconditional_value)
 
         # It is an invariant that nothing in new matches an existing
         # condition except for the default condition
         if self.new:
             update_default, new_default_value = self.update_default()
             if update_default:
                 if new_default_value != self.default_value:
-                    self.node.set(self.property_name, self.update_value(None, new_default_value), condition=None)
+                    self.node.set(self.property_name,
+                                  self.update_value(unconditional_value, new_default_value),
+                                  condition=None)
             else:
-                self.add_new(unconditional_value, stability)
+                try:
+                    self.add_new(unconditional_value, stability)
+                except UpdateError as e:
+                    print("%s for %s, cannot update %s" % (e, self.node.root.test_path,
+                                                           self.property_name))
 
         # Remove cases where the value matches the default
         if (self.property_name in self.node._data and
             len(self.node._data[self.property_name]) > 0 and
             self.node._data[self.property_name][-1].condition_node is None and
             self.node._data[self.property_name][-1].value_as(self.value_type) == self.default_value):
 
             self.node.remove_value(self.property_name, self.node._data[self.property_name][-1])
@@ -352,17 +378,17 @@ class PropertyUpdate(object):
 
     def update_default(self):
         """Get the updated default value for the property (i.e. the one chosen when no conditions match).
 
         :returns: (update, new_default_value) where updated is a bool indicating whether the property
                   should be updated, and new_default_value is the value to set if it should."""
         raise NotImplementedError
 
-    def add_new(self, unconditional_value, stability=False):
+    def add_new(self, unconditional_value, stability):
         """Add new conditional values for the property.
 
         Subclasses need not implement this if they only ever update the default value."""
         raise NotImplementedError
 
     def update_value(self, old_value, new_value):
         """Get a value to set on the property, given its previous value and the new value from logs.
 
@@ -384,102 +410,141 @@ class ExpectedUpdate(PropertyUpdate):
         return in_value.status
 
     def update_default(self):
         update_default = all(self.new[0].value == result.value
                              for result in self.new) and not self.updated
         new_value = self.new[0].value
         return update_default, new_value
 
-    def add_new(self, unconditional_value, stability=False):
+    def add_new(self, unconditional_value, stability):
         try:
             conditionals = group_conditionals(
                 self.new,
                 property_order=self.node.root.property_order,
                 boolean_properties=self.node.root.boolean_properties)
         except ConditionError as e:
             if stability is not None:
                 self.node.set("disabled", stability or "unstable", e.cond.children[0])
                 self.node.new_disabled = True
             else:
-                print "Conflicting metadata values for %s, cannot update" % self.root.test_path
-                return
+                raise UpdateError("Conflicting metadata values")
         for conditional_node, value in conditionals:
             if value != unconditional_value:
                 self.node.set(self.property_name, value, condition=conditional_node.children[0])
 
 
 class MaxAssertsUpdate(PropertyUpdate):
     property_name = "max-asserts"
     cls_default_value = 0
     value_type = int
 
     def update_value(self, old_value, new_value):
+        new_value = self.value_type(new_value)
         if old_value is not None:
             old_value = self.value_type(old_value)
-        if old_value and old_value < new_value:
-            return new_value
+        if old_value is not None and old_value < new_value:
+            return new_value + 1
         if old_value is None:
-            return new_value
+            return new_value + 1
         return old_value
 
     def update_default(self):
         """For asserts we always update the default value and never add new conditionals.
         The value we set as the default is the maximum the current default or one more than the
         number of asserts we saw in any configuration."""
         # Current values
         values = []
         current_default = None
         if self.property_name in self.node._data:
             current_default = [item for item in
                                self.node._data[self.property_name]
                                if item.condition_node is None]
             if current_default:
                 values.append(int(current_default[0].value))
-        values.extend(item.value + 1 for item in self.new)
-        values.extend(item.value + 1 for item in
+        values.extend(item.value for item in self.new)
+        values.extend(item.value for item in
                       itertools.chain.from_iterable(results for _, results in self.updated))
         new_value = max(values)
         return True, new_value
 
 
 class MinAssertsUpdate(PropertyUpdate):
     property_name = "min-asserts"
     cls_default_value = 0
     value_type = int
 
     def update_value(self, old_value, new_value):
+        new_value = self.value_type(new_value)
         if old_value is not None:
             old_value = self.value_type(old_value)
-        if old_value and new_value < old_value:
+        if old_value is not None and new_value < old_value:
             return 0
         if old_value is None:
             # If we are getting some asserts for the first time, set the minimum to 0
-            return 0
+            return new_value
         return old_value
 
     def update_default(self):
         """For asserts we always update the default value and never add new conditionals.
         This is either set to the current value or one less than the number of asserts
         we saw, whichever is lower."""
         values = []
         current_default = None
         if self.property_name in self.node._data:
             current_default = [item for item in
                                self.node._data[self.property_name]
                                if item.condition_node is None]
         if current_default:
             values.append(current_default[0].value_as(self.value_type))
-        values.extend(max(0, item.value - 1) for item in self.new)
-        values.extend(max(0, item.value - 1) for item in
+        values.extend(max(0, item.value) for item in self.new)
+        values.extend(max(0, item.value) for item in
                       itertools.chain.from_iterable(results for _, results in self.updated))
         new_value = min(values)
         return True, new_value
 
 
+class LsanUpdate(PropertyUpdate):
+    property_name = "lsan-allowed"
+    cls_default_value = None
+
+    def get_value(self, result):
+        # If we have an allowed_match that matched, return None
+        # This value is ignored later (because it matches the default)
+        # We do that because then if we allow a failure in foo/__dir__.ini
+        # we don't want to update foo/bar/__dir__.ini with the same rule
+        if result[1]:
+            return None
+        # Otherwise return the topmost stack frame
+        # TODO: there is probably some improvement to be made by looking for a "better" stack frame
+        return result[0][0]
+
+    def update_value(self, old_value, new_value):
+        if isinstance(new_value, (str, unicode)):
+            new_value = {new_value}
+        else:
+            new_value = set(new_value)
+        if old_value is None:
+            old_value = set()
+        old_value = set(old_value)
+        return sorted((old_value | new_value) - {None})
+
+    def update_default(self):
+        current_default = None
+        if self.property_name in self.node._data:
+            current_default = [item for item in
+                               self.node._data[self.property_name]
+                               if item.condition_node is None]
+        if current_default:
+            current_default = current_default[0].value
+        new_values = [item.value for item in self.new]
+        new_value = self.update_value(current_default, new_values)
+        return True, new_value if new_value else None
+
+
 def group_conditionals(values, property_order=None, boolean_properties=None):
     """Given a list of Value objects, return a list of
     (conditional_node, status) pairs representing the conditional
     expressions that are required to match each status
 
     :param values: List of Values
     :param property_order: List of properties to use in expectation metadata
                            from most to least significant.
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/metadata.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/metadata.py
@@ -1,33 +1,34 @@
 import os
 import shutil
 import tempfile
 import uuid
+from collections import defaultdict, namedtuple
 
-from mozlog import reader
 from mozlog import structuredlog
 
-import expected
 import manifestupdate
 import testloader
 import wptmanifest
 import wpttest
+from expected import expected_path
 from vcs import git
 manifest = None  # Module that will be imported relative to test_root
 manifestitem = None
 
 logger = structuredlog.StructuredLogger("web-platform-tests")
 
+
+TestItem = namedtuple("TestItem", ["test_manifest", "expected"])
+
 try:
-    import ujson
+    import ujson as json
 except ImportError:
-    pass
-else:
-    reader.json = ujson
+    import json
 
 
 def load_test_manifests(serve_root, test_paths):
     do_delayed_imports(serve_root)
     manifest_loader = testloader.ManifestLoader(test_paths, False)
     return manifest_loader.load()
 
 
@@ -38,49 +39,43 @@ def update_expected(test_paths, serve_ro
     """Update the metadata files for web-platform-tests based on
     the results obtained in a previous run or runs
 
     If stability is not None, assume log_file_names refers to logs from repeated
     test jobs, disable tests that don't behave as expected on all runs"""
 
     manifests = load_test_manifests(serve_root, test_paths)
 
-    change_data = {}
-
-    if sync_root is not None:
-        if rev_old is not None:
-            rev_old = git("rev-parse", rev_old, repo=sync_root).strip()
-        rev_new = git("rev-parse", rev_new, repo=sync_root).strip()
-
-        if rev_old is not None:
-            change_data = load_change_data(rev_old, rev_new, repo=sync_root)
+    id_test_map = update_from_logs(manifests,
+                                   *log_file_names,
+                                   ignore_existing=ignore_existing,
+                                   property_order=property_order,
+                                   boolean_properties=boolean_properties,
+                                   stability=stability)
 
-    expected_map_by_manifest = update_from_logs(manifests,
-                                                *log_file_names,
-                                                ignore_existing=ignore_existing,
-                                                property_order=property_order,
-                                                boolean_properties=boolean_properties,
-                                                stability=stability)
+    by_test_manifest = defaultdict(list)
+    while id_test_map:
+        item = id_test_map.popitem()[1]
+        by_test_manifest[item.test_manifest].append(item.expected)
 
-    for test_manifest, expected_map in expected_map_by_manifest.iteritems():
-        url_base = manifests[test_manifest]["url_base"]
-        metadata_path = test_paths[url_base]["metadata_path"]
-        write_changes(metadata_path, expected_map)
+    for test_manifest, expected in by_test_manifest.iteritems():
+        metadata_path = manifests[test_manifest]["metadata_path"]
+        write_changes(metadata_path, expected)
         if stability is not None:
-            for tree in expected_map.itervalues():
-                for test in tree.iterchildren():
+            for tree in expected:
+                if not tree.modified:
+                    continue
+                for test in expected.iterchildren():
                     for subtest in test.iterchildren():
                         if subtest.new_disabled:
                             print "disabled: %s" % os.path.dirname(subtest.root.test_path) + "/" + subtest.name
-                    if test.new_disabled:
-                        print "disabled: %s" % test.root.test_path
+                        if test.new_disabled:
+                            print "disabled: %s" % test.root.test_path
 
-    results_changed = [item.test_path for item in expected_map.itervalues() if item.modified]
-
-    return unexpected_changes(manifests, change_data, results_changed)
+    return by_test_manifest
 
 
 def do_delayed_imports(serve_root):
     global manifest, manifestitem
     from manifest import manifest, item as manifestitem
 
 
 def files_in_repo(repo_root):
@@ -142,131 +137,132 @@ def unexpected_changes(manifests, change
 
 
 def update_from_logs(manifests, *log_filenames, **kwargs):
     ignore_existing = kwargs.get("ignore_existing", False)
     property_order = kwargs.get("property_order")
     boolean_properties = kwargs.get("boolean_properties")
     stability = kwargs.get("stability")
 
-    expected_map = {}
     id_test_map = {}
 
     for test_manifest, paths in manifests.iteritems():
-        expected_map_manifest, id_path_map_manifest = create_test_tree(
+        id_test_map.update(create_test_tree(
             paths["metadata_path"],
             test_manifest,
             property_order=property_order,
-            boolean_properties=boolean_properties)
-        expected_map[test_manifest] = expected_map_manifest
-        id_test_map.update(id_path_map_manifest)
+            boolean_properties=boolean_properties))
 
-    updater = ExpectedUpdater(manifests, expected_map, id_test_map,
+    updater = ExpectedUpdater(manifests,
+                              id_test_map,
                               ignore_existing=ignore_existing)
     for log_filename in log_filenames:
         with open(log_filename) as f:
             updater.update_from_log(f)
+    return coalesce_results(id_test_map, stability)
 
-    for manifest_expected in expected_map.itervalues():
-        for tree in manifest_expected.itervalues():
-            for test in tree.iterchildren():
-                for subtest in test.iterchildren():
-                    subtest.coalesce_properties(stability=stability)
-                test.coalesce_properties(stability=stability)
 
-    return expected_map
+def coalesce_results(id_test_map, stability):
+    for _, expected in id_test_map.itervalues():
+        if not expected.modified:
+            continue
+        expected.coalesce_properties(stability=stability)
+        for test in expected.iterchildren():
+            for subtest in test.iterchildren():
+                subtest.coalesce_properties(stability=stability)
+            test.coalesce_properties(stability=stability)
+
+    return id_test_map
 
 
 def directory_manifests(metadata_path):
     rv = []
     for dirpath, dirname, filenames in os.walk(metadata_path):
         if "__dir__.ini" in filenames:
             rel_path = os.path.relpath(dirpath, metadata_path)
             rv.append(os.path.join(rel_path, "__dir__.ini"))
     return rv
 
 
-def write_changes(metadata_path, expected_map):
+def write_changes(metadata_path, expected):
     # First write the new manifest files to a temporary directory
     temp_path = tempfile.mkdtemp(dir=os.path.split(metadata_path)[0])
-    write_new_expected(temp_path, expected_map)
-
-    # Keep all __dir__.ini files (these are not in expected_map because they
-    # aren't associated with a specific test)
-    keep_files = directory_manifests(metadata_path)
+    write_new_expected(temp_path, expected)
 
     # Copy all files in the root to the temporary location since
     # these cannot be ini files
-    keep_files.extend(item for item in os.listdir(metadata_path) if
-                      not os.path.isdir(os.path.join(metadata_path, item)))
+    keep_files = [item for item in os.listdir(metadata_path) if
+                  not os.path.isdir(os.path.join(metadata_path, item))]
 
     for item in keep_files:
         dest_dir = os.path.dirname(os.path.join(temp_path, item))
         if not os.path.exists(dest_dir):
             os.makedirs(dest_dir)
         shutil.copyfile(os.path.join(metadata_path, item),
                         os.path.join(temp_path, item))
 
     # Then move the old manifest files to a new location
     temp_path_2 = metadata_path + str(uuid.uuid4())
     os.rename(metadata_path, temp_path_2)
     # Move the new files to the destination location and remove the old files
     os.rename(temp_path, metadata_path)
     shutil.rmtree(temp_path_2)
 
 
-def write_new_expected(metadata_path, expected_map):
+def write_new_expected(metadata_path, expected):
     # Serialize the data back to a file
-    for tree in expected_map.itervalues():
+    for tree in expected:
         if not tree.is_empty:
             manifest_str = wptmanifest.serialize(tree.node, skip_empty_data=True)
             assert manifest_str != ""
-            path = expected.expected_path(metadata_path, tree.test_path)
+            path = expected_path(metadata_path, tree.test_path)
             dir = os.path.split(path)[0]
             if not os.path.exists(dir):
                 os.makedirs(dir)
             with open(path, "wb") as f:
                 f.write(manifest_str)
 
 
 class ExpectedUpdater(object):
-    def __init__(self, test_manifests, expected_tree, id_path_map, ignore_existing=False):
-        self.test_manifests = test_manifests
-        self.expected_tree = expected_tree
-        self.id_path_map = id_path_map
+    def __init__(self, test_manifests, id_test_map, ignore_existing=False):
+        self.id_test_map = id_test_map
         self.ignore_existing = ignore_existing
         self.run_info = None
         self.action_map = {"suite_start": self.suite_start,
                            "test_start": self.test_start,
                            "test_status": self.test_status,
                            "test_end": self.test_end,
-                           "assertion_count": self.assertion_count}
+                           "assertion_count": self.assertion_count,
+                           "lsan_leak": self.lsan_leak}
         self.tests_visited = {}
 
         self.test_cache = {}
 
         self.types_by_path = {}
-        for manifest in self.test_manifests.iterkeys():
+        for manifest in test_manifests.iterkeys():
             for test_type, path, _ in manifest:
                 if test_type in wpttest.manifest_test_cls:
                     self.types_by_path[path] = wpttest.manifest_test_cls[test_type]
 
     def update_from_log(self, log_file):
         self.run_info = None
-        log_reader = reader.read(log_file)
-        reader.each_log(log_reader, self.action_map)
+        action_map = self.action_map
+        for line in log_file:
+            data = json.loads(line)
+            action = data["action"]
+            if action in action_map:
+                action_map[action](data)
 
     def suite_start(self, data):
         self.run_info = data["run_info"]
 
     def test_start(self, data):
         test_id = data["test"]
         try:
-            test_manifest, test = self.id_path_map[test_id]
-            expected_node = self.expected_tree[test_manifest][test].get_test(test_id)
+            expected_node = self.id_test_map[test_id].expected.get_test(test_id)
         except KeyError:
             print "Test not found %s, skipping" % test_id
             return
         self.test_cache[test_id] = expected_node
 
         if test_id not in self.tests_visited:
             if self.ignore_existing:
                 expected_node.clear("expected")
@@ -309,43 +305,91 @@ class ExpectedUpdater(object):
     def assertion_count(self, data):
         test_id = data["test"]
         test = self.test_cache.get(test_id)
         if test is None:
             return
 
         test.set_asserts(self.run_info, data["count"])
 
+    def lsan_leak(self, data):
+        dir_path = data.get("scope", "/")
+        dir_id = os.path.join(dir_path, "__dir__").replace(os.path.sep, "/")
+        if dir_id.startswith("/"):
+            dir_id = dir_id[1:]
+        expected_node = self.id_test_map[dir_id].expected
+
+        expected_node.set_lsan(self.run_info, (data["frames"], data.get("allowed_match")))
+
 
 def create_test_tree(metadata_path, test_manifest, property_order=None,
                      boolean_properties=None):
-    expected_map = {}
+    """Create a map of expectation manifests for all tests in test_manifest,
+    reading existing manifests under manifest_path
+
+    :returns: A map of test_id to (manifest, test, expectation_data)
+    """
     id_test_map = {}
     exclude_types = frozenset(["stub", "helper", "manual", "support", "conformancechecker"])
     all_types = [item.item_type for item in manifestitem.__dict__.itervalues()
                  if type(item) == type and
                  issubclass(item, manifestitem.ManifestItem) and
                  item.item_type is not None]
     include_types = set(all_types) - exclude_types
     for _, test_path, tests in test_manifest.itertypes(*include_types):
-        expected_data = load_expected(test_manifest, metadata_path, test_path, tests,
-                                      property_order=property_order,
-                                      boolean_properties=boolean_properties)
-        if expected_data is None:
-            expected_data = create_expected(test_manifest,
-                                            test_path,
-                                            tests,
-                                            property_order=property_order,
-                                            boolean_properties=boolean_properties)
+        expected_data = load_or_create_expected(test_manifest, metadata_path, test_path, tests,
+                                                property_order, boolean_properties)
+        for test in tests:
+            id_test_map[test.id] = TestItem(test_manifest, expected_data)
+
+        dir_path = os.path.split(test_path)[0].replace(os.path.sep, "/")
+        while True:
+            if dir_path:
+                dir_id = dir_path + "/__dir__"
+            else:
+                dir_id = "__dir__"
+            dir_id = (test_manifest.url_base + dir_id).lstrip("/")
+            if dir_id not in id_test_map:
+                dir_object = DirObject(dir_id, dir_path)
+                expected_data = load_or_create_expected(test_manifest,
+                                                        metadata_path,
+                                                        dir_id,
+                                                        [],
+                                                        property_order,
+                                                        boolean_properties)
 
-        for test in tests:
-            id_test_map[test.id] = (test_manifest, test)
-            expected_map[test] = expected_data
+                id_test_map[dir_id] = TestItem(test_manifest, expected_data)
+            if not dir_path:
+                break
+            dir_path = dir_path.rsplit("/", 1)[0] if "/" in dir_path else ""
+
+    return id_test_map
+
+
+class DirObject(object):
+    def __init__(self, id, path):
+        self.id = id
+        self.path = path
 
-    return expected_map, id_test_map
+    def __hash__(self):
+        return hash(self.id)
+
+
+def load_or_create_expected(test_manifest, metadata_path, test_path, tests, property_order=None,
+                            boolean_properties=None):
+    expected_data = load_expected(test_manifest, metadata_path, test_path, tests,
+                                  property_order=property_order,
+                                  boolean_properties=boolean_properties)
+    if expected_data is None:
+        expected_data = create_expected(test_manifest,
+                                        test_path,
+                                        tests,
+                                        property_order=property_order,
+                                        boolean_properties=boolean_properties)
+    return expected_data
 
 
 def create_expected(test_manifest, test_path, tests, property_order=None,
                     boolean_properties=None):
     expected = manifestupdate.ExpectedManifest(None, test_path, test_manifest.url_base,
                                                property_order=property_order,
                                                boolean_properties=boolean_properties)
     for test in tests:
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testloader.py
@@ -450,16 +450,17 @@ class ManifestLoader(object):
 
 
 def iterfilter(filters, iter):
     for f in filters:
         iter = f(iter)
     for item in iter:
         yield item
 
+
 class TestLoader(object):
     def __init__(self,
                  test_manifests,
                  test_types,
                  run_info,
                  manifest_filters=None,
                  meta_filters=None,
                  chunk_type="none",
@@ -510,17 +511,17 @@ class TestLoader(object):
             inherit_metadata.append(test_metadata)
             test_metadata = test_metadata.get_test(manifest_test.id)
 
         return wpttest.from_manifest(manifest_test, inherit_metadata, test_metadata)
 
     def load_dir_metadata(self, test_manifest, metadata_path, test_path):
         rv = []
         path_parts = os.path.dirname(test_path).split(os.path.sep)
-        for i in xrange(1,len(path_parts) + 1):
+        for i in xrange(len(path_parts) + 1):
             path = os.path.join(metadata_path, os.path.sep.join(path_parts[:i]), "__dir__.ini")
             if path not in self.directory_manifests:
                 self.directory_manifests[path] = manifestexpected.get_dir_manifest(path,
                                                                                    self.run_info)
             manifest = self.directory_manifests[path]
             if manifest is not None:
                 rv.append(manifest)
         return rv
@@ -592,16 +593,20 @@ class TestSource(object):
         self.current_metadata = None
 
     @abstractmethod
     # noqa: N805
     #@classmethod (doesn't compose with @abstractmethod)
     def make_queue(cls, tests, **kwargs):
         pass
 
+    @classmethod
+    def group_metadata(self, state):
+        return {"scope": "/"}
+
     def group(self):
         if not self.current_group or len(self.current_group) == 0:
             try:
                 self.current_group, self.current_metadata = self.test_queue.get(block=False)
             except Empty:
                 return None, None
         return self.current_group, self.current_metadata
 
@@ -615,34 +620,35 @@ class GroupedSource(TestSource):
     def make_queue(cls, tests, **kwargs):
         test_queue = Queue()
         groups = []
 
         state = {}
 
         for test in tests:
             if cls.new_group(state, test, **kwargs):
-                groups.append((deque(), {}))
+                group_metadata = cls.group_metadata(state)
+                groups.append((deque(), group_metadata))
 
             group, metadata = groups[-1]
             group.append(test)
             test.update_metadata(metadata)
 
         for item in groups:
             test_queue.put(item)
         return test_queue
 
 
 class SingleTestSource(TestSource):
     @classmethod
     def make_queue(cls, tests, **kwargs):
         test_queue = Queue()
         processes = kwargs["processes"]
         queues = [deque([]) for _ in xrange(processes)]
-        metadatas = [{} for _ in xrange(processes)]
+        metadatas = [cls.group_metadata(None) for _ in xrange(processes)]
         for test in tests:
             idx = hash(test.id) % processes
             group = queues[idx]
             metadata = metadatas[idx]
             group.append(test)
             test.update_metadata(metadata)
 
         for item in zip(queues, metadatas):
@@ -650,14 +656,18 @@ class SingleTestSource(TestSource):
 
         return test_queue
 
 
 class PathGroupedSource(GroupedSource):
     @classmethod
     def new_group(cls, state, test, **kwargs):
         depth = kwargs.get("depth")
-        if depth is True:
+        if depth is True or depth == 0:
             depth = None
         path = urlparse.urlsplit(test.url).path.split("/")[1:-1][:depth]
         rv = path != state.get("prev_path")
         state["prev_path"] = path
         return rv
+
+    @classmethod
+    def group_metadata(cls, state):
+        return {"scope": "/%s" % "/".join(state["prev_path"])}
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/testrunner.py
@@ -169,17 +169,17 @@ class BrowserManager(object):
         browser_settings = self.browser.settings(test)
         restart_required = ((self.browser_settings is not None and
                              self.browser_settings != browser_settings) or
                             (self.last_test != test and test.expected() == "CRASH"))
         self.browser_settings = browser_settings
         self.last_test = test
         return restart_required
 
-    def init(self):
+    def init(self, group_metadata):
         """Launch the browser that is being tested,
         and the TestRunner process that will run the tests."""
         # It seems that this lock is helpful to prevent some race that otherwise
         # sometimes stops the spawned processes initialising correctly, and
         # leaves this thread hung
         if self.init_timer is not None:
             self.init_timer.cancel()
 
@@ -187,17 +187,17 @@ class BrowserManager(object):
 
         if not self.no_timeout:
             self.init_timer = threading.Timer(self.browser.init_timeout,
                                               self.init_timeout)
         try:
             if self.init_timer is not None:
                 self.init_timer.start()
             self.logger.debug("Starting browser with settings %r" % self.browser_settings)
-            self.browser.start(**self.browser_settings)
+            self.browser.start(group_metadata=group_metadata, **self.browser_settings)
             self.browser_pid = self.browser.pid()
         except Exception:
             self.logger.warning("Failure during init %s" % traceback.format_exc())
             if self.init_timer is not None:
                 self.init_timer.cancel()
             self.logger.error(traceback.format_exc())
             succeeded = False
         else:
@@ -446,17 +446,17 @@ class TestRunnerManager(threading.Thread
     def init(self):
         assert isinstance(self.state, RunnerManagerState.initializing)
         if self.state.failure_count > self.max_restarts:
             self.logger.error("Max restarts exceeded")
             return RunnerManagerState.error()
 
         self.browser.update_settings(self.state.test)
 
-        result = self.browser.init()
+        result = self.browser.init(self.state.group_metadata)
         if result is Stop:
             return RunnerManagerState.error()
         elif not result:
             return RunnerManagerState.initializing(self.state.test,
                                                    self.state.test_group,
                                                    self.state.group_metadata,
                                                    self.state.failure_count + 1)
         else:
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_update.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/tests/test_update.py
@@ -1,328 +1,548 @@
-import unittest
-import StringIO
+import mock
+import os
+import sys
+from io import BytesIO
+
+from .. import metadata, manifestupdate, wptmanifest
+from mozlog import structuredlog, handlers, formatters
 
-import pytest
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
+from manifest import manifest, item as manifest_item
+
 
-from .. import metadata, manifestupdate
-from mozlog import structuredlog, handlers, formatters
+def rel_path_to_url(rel_path, url_base="/"):
+    assert not os.path.isabs(rel_path)
+    if url_base[0] != "/":
+        url_base = "/" + url_base
+    if url_base[-1] != "/":
+        url_base += "/"
+    return url_base + rel_path.replace(os.sep, "/")
 
 
-class TestExpectedUpdater(unittest.TestCase):
-    def create_manifest(self, data, test_path="path/to/test.ini"):
-        f = StringIO.StringIO(data)
-        return manifestupdate.compile(f, test_path)
+def SourceFileWithTest(path, hash, cls, *args):
+    s = mock.Mock(rel_path=path, hash=hash)
+    test = cls(s, rel_path_to_url(path), *args)
+    s.manifest_items = mock.Mock(return_value=(cls.item_type, [test]))
+    return s
 
-    def create_updater(self, data, **kwargs):
-        expected_tree = {}
-        id_path_map = {}
-        for test_path, test_ids, manifest_str in data:
-            if isinstance(test_ids, (str, unicode)):
-                test_ids = [test_ids]
-            expected_tree[test_path] = self.create_manifest(manifest_str, test_path)
-            for test_id in test_ids:
-                id_path_map[test_id] = test_path
-
-        return metadata.ExpectedUpdater(expected_tree, id_path_map, **kwargs)
 
-    def create_log(self, *args, **kwargs):
-        logger = structuredlog.StructuredLogger("expected_test")
-        data = StringIO.StringIO()
-        handler = handlers.StreamHandler(data, formatters.JSONFormatter())
-        logger.add_handler(handler)
+item_classes = {"testharness": manifest_item.TestharnessTest,
+                "reftest": manifest_item.RefTest,
+                "reftest_node": manifest_item.RefTestNode,
+                "manual": manifest_item.ManualTest,
+                "stub": manifest_item.Stub,
+                "wdspec": manifest_item.WebdriverSpecTest,
+                "conformancechecker": manifest_item.ConformanceCheckerTest,
+                "visual": manifest_item.VisualTest,
+                "support": manifest_item.SupportFile}
 
-        log_entries = ([("suite_start", {"tests": [], "run_info": kwargs.get("run_info", {})})] +
-                       list(args) +
-                       [("suite_end", {})])
 
-        for item in log_entries:
-            action, kwargs = item
-            getattr(logger, action)(**kwargs)
-        logger.remove_handler(handler)
-        data.seek(0)
-        return data
+def update(tests, *logs):
+    updater = create_updater(tests)
+    for log in logs:
+        log = create_log(log)
+        updater.update_from_log(log)
+
+    return metadata.coalesce_results(updater.id_test_map, False)
 
 
-    def coalesce_results(self, trees):
-        for tree in trees:
-            for test in tree.iterchildren():
-                for subtest in test.iterchildren():
-                    subtest.coalesce_expected()
-                test.coalesce_expected()
-
-    @pytest.mark.xfail
-    def test_update_0(self):
-        prev_data = [("path/to/test.htm.ini", ["/path/to/test.htm"], """[test.htm]
-  type: testharness
-  [test1]
-    expected: FAIL""")]
+def create_updater(tests, url_base="/", **kwargs):
+    id_test_map = {}
+    m = create_test_manifest(tests, url_base)
+    test_manifests = {
+        m: {"url_base": "/",
+            "tests_path": "."}
+    }
+    for test_path, test_ids, test_type, manifest_str in tests:
+        if isinstance(test_ids, (str, unicode)):
+            test_ids = [test_ids]
+        expected = manifestupdate.compile(BytesIO(manifest_str), test_path, url_base)
+        for test_id in test_ids:
+            id_test_map[test_id] = metadata.TestItem(m, expected)
 
-        new_data = self.create_log(("test_start", {"test": "/path/to/test.htm"}),
-                                   ("test_status", {"test": "/path/to/test.htm",
-                                                    "subtest": "test1",
-                                                    "status": "PASS",
-                                                    "expected": "FAIL"}),
-                                   ("test_end", {"test": "/path/to/test.htm",
-                                                 "status": "OK"}))
-        updater = self.create_updater(prev_data)
-        updater.update_from_log(new_data)
+    return metadata.ExpectedUpdater(test_manifests, id_test_map, **kwargs)
+
 
-        new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-        self.coalesce_results([new_manifest])
-        self.assertTrue(new_manifest.is_empty)
+def create_log(entries):
+    logger = structuredlog.StructuredLogger("expected_test")
+    data = BytesIO()
+    handler = handlers.StreamHandler(data, formatters.JSONFormatter())
+    logger.add_handler(handler)
 
-    @pytest.mark.xfail
-    def test_update_1(self):
-        test_id = "/path/to/test.htm"
-        prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
-  type: testharness
-  [test1]
-    expected: ERROR""")]
+    for item in entries:
+        action, kwargs = item
+        getattr(logger, action)(**kwargs)
+    logger.remove_handler(handler)
+    data.seek(0)
+    return data
+
+
+def suite_log(entries, run_info=None):
+    return ([("suite_start", {"tests": [], "run_info": run_info or {}})] +
+            entries +
+            [("suite_end", {})])
+
 
-        new_data = self.create_log(("test_start", {"test": test_id}),
-                                   ("test_status", {"test": test_id,
-                                                    "subtest": "test1",
-                                                    "status": "FAIL",
-                                                    "expected": "ERROR"}),
-                                   ("test_end", {"test": test_id,
-                                                 "status": "OK"}))
-        updater = self.create_updater(prev_data)
-        updater.update_from_log(new_data)
+def create_test_manifest(tests, url_base="/"):
+    source_files = []
+    for i, (test, _, test_type, _) in enumerate(tests):
+        if test_type:
+            source_files.append(SourceFileWithTest(test, str(i) * 40, item_classes[test_type]))
+    m = manifest.Manifest()
+    m.update(source_files)
+    return m
 
-        new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-        self.coalesce_results([new_manifest])
-        self.assertFalse(new_manifest.is_empty)
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get("expected"), "FAIL")
 
-    @pytest.mark.xfail
-    def test_new_subtest(self):
-        test_id = "/path/to/test.htm"
-        prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
-  type: testharness
+def test_update_0():
+    tests = [("path/to/test.htm.ini", ["/path/to/test.htm"], "testharness",
+              """[test.htm]
   [test1]
     expected: FAIL""")]
 
-        new_data = self.create_log(("test_start", {"test": test_id}),
-                                   ("test_status", {"test": test_id,
-                                                    "subtest": "test1",
-                                                    "status": "FAIL",
-                                                    "expected": "FAIL"}),
-                                   ("test_status", {"test": test_id,
-                                                    "subtest": "test2",
-                                                    "status": "FAIL",
-                                                    "expected": "PASS"}),
-                                   ("test_end", {"test": test_id,
-                                                 "status": "OK"}))
-        updater = self.create_updater(prev_data)
-        updater.update_from_log(new_data)
+    log = suite_log([("test_start", {"test": "/path/to/test.htm"}),
+                     ("test_status", {"test": "/path/to/test.htm",
+                                      "subtest": "test1",
+                                      "status": "PASS",
+                                      "expected": "FAIL"}),
+                     ("test_end", {"test": "/path/to/test.htm",
+                                   "status": "OK"})])
+
+    id_test_map = update(tests, log)
+
+    assert len(id_test_map) == 1
+    assert id_test_map.popitem()[1].expected.is_empty
+
 
-        new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-        self.coalesce_results([new_manifest])
-        self.assertFalse(new_manifest.is_empty)
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get("expected"), "FAIL")
-        self.assertEquals(new_manifest.get_test(test_id).children[1].get("expected"), "FAIL")
+def test_update_1():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness",
+              """[test.htm]
+  [test1]
+    expected: ERROR""")]
 
-    @pytest.mark.xfail
-    def test_update_multiple_0(self):
-        test_id = "/path/to/test.htm"
-        prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
-  type: testharness
+    log = suite_log([("test_start", {"test": test_id}),
+                     ("test_status", {"test": test_id,
+                                      "subtest": "test1",
+                                      "status": "FAIL",
+                                      "expected": "ERROR"}),
+                     ("test_end", {"test": test_id,
+                                   "status": "OK"})])
+
+    id_test_map = update(tests, log)
+
+    new_manifest = id_test_map.popitem()[1].expected
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).children[0].get("expected") == "FAIL"
+
+
+def test_new_subtest():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
   [test1]
     expected: FAIL""")]
 
-        new_data_0 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "FAIL",
-                                                      "expected": "FAIL"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": False, "os": "osx"})
-
-        new_data_1 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "TIMEOUT",
-                                                      "expected": "FAIL"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": False, "os": "linux"})
-        updater = self.create_updater(prev_data)
+    log = suite_log([("test_start", {"test": test_id}),
+                     ("test_status", {"test": test_id,
+                                      "subtest": "test1",
+                                      "status": "FAIL",
+                                      "expected": "FAIL"}),
+                     ("test_status", {"test": test_id,
+                                      "subtest": "test2",
+                                      "status": "FAIL",
+                                      "expected": "PASS"}),
+                     ("test_end", {"test": test_id,
+                                   "status": "OK"})])
+    id_test_map = update(tests, log)
+    new_manifest = id_test_map.popitem()[1].expected
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).children[0].get("expected") == "FAIL"
+    assert new_manifest.get_test(test_id).children[1].get("expected") == "FAIL"
 
-        updater.update_from_log(new_data_0)
-        updater.update_from_log(new_data_1)
 
-        new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
-        self.coalesce_results([new_manifest])
-
-        self.assertFalse(new_manifest.is_empty)
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": False, "os": "osx"}), "FAIL")
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": False, "os": "linux"}), "TIMEOUT")
-
-    @pytest.mark.xfail
-    def test_update_multiple_1(self):
-        test_id = "/path/to/test.htm"
-        prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
-  type: testharness
+def test_update_multiple_0():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
   [test1]
     expected: FAIL""")]
 
-        new_data_0 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "FAIL",
-                                                      "expected": "FAIL"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": False, "os": "osx"})
-
-        new_data_1 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "TIMEOUT",
-                                                      "expected": "FAIL"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": False, "os": "linux"})
-        updater = self.create_updater(prev_data)
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "FAIL",
+                                        "expected": "FAIL"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"debug": False, "os": "osx"})
 
-        updater.update_from_log(new_data_0)
-        updater.update_from_log(new_data_1)
-
-        new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
-        self.coalesce_results([new_manifest])
+    log_1 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "TIMEOUT",
+                                        "expected": "FAIL"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                       run_info={"debug": False, "os": "linux"})
 
-        self.assertFalse(new_manifest.is_empty)
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": False, "os": "osx"}), "FAIL")
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": False, "os": "linux"}), "TIMEOUT")
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": False, "os": "windows"}), "FAIL")
+    id_test_map = update(tests, log_0, log_1)
+    new_manifest = id_test_map.popitem()[1].expected
 
-    @pytest.mark.xfail
-    def test_update_multiple_2(self):
-        test_id = "/path/to/test.htm"
-        prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
-  type: testharness
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": False, "os": "osx"}) == "FAIL"
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": False, "os": "linux"}) == "TIMEOUT"
+
+
+def test_update_multiple_1():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
   [test1]
     expected: FAIL""")]
 
-        new_data_0 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "FAIL",
-                                                      "expected": "FAIL"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": False, "os": "osx"})
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "FAIL",
+                                        "expected": "FAIL"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"debug": False, "os": "osx"})
 
-        new_data_1 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "TIMEOUT",
-                                                      "expected": "FAIL"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": True, "os": "osx"})
-        updater = self.create_updater(prev_data)
+    log_1 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "TIMEOUT",
+                                        "expected": "FAIL"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"debug": False, "os": "linux"})
+
+    id_test_map = update(tests, log_0, log_1)
+    new_manifest = id_test_map.popitem()[1].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": False, "os": "osx"}) == "FAIL"
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": False, "os": "linux"}) == "TIMEOUT"
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": False, "os": "windows"}) == "FAIL"
+
 
-        updater.update_from_log(new_data_0)
-        updater.update_from_log(new_data_1)
+def test_update_multiple_2():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
+  [test1]
+    expected: FAIL""")]
 
-        new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
-        self.coalesce_results([new_manifest])
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "FAIL",
+                                        "expected": "FAIL"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"debug": False, "os": "osx"})
 
-        self.assertFalse(new_manifest.is_empty)
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": False, "os": "osx"}), "FAIL")
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": True, "os": "osx"}), "TIMEOUT")
+    log_1 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "TIMEOUT",
+                                        "expected": "FAIL"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"debug": True, "os": "osx"})
 
-    @pytest.mark.xfail
-    def test_update_multiple_3(self):
-        test_id = "/path/to/test.htm"
-        prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
-  type: testharness
+    id_test_map = update(tests, log_0, log_1)
+    new_manifest = id_test_map.popitem()[1].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": False, "os": "osx"}) == "FAIL"
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": True, "os": "osx"}) == "TIMEOUT"
+
+
+def test_update_multiple_3():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
   [test1]
     expected:
       if debug: FAIL
       if not debug and os == "osx": TIMEOUT""")]
 
-        new_data_0 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "FAIL",
-                                                      "expected": "FAIL"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": False, "os": "osx"})
-
-        new_data_1 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "TIMEOUT",
-                                                      "expected": "FAIL"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": True, "os": "osx"})
-        updater = self.create_updater(prev_data)
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "FAIL",
+                                        "expected": "FAIL"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"debug": False, "os": "osx"})
 
-        updater.update_from_log(new_data_0)
-        updater.update_from_log(new_data_1)
-
-        new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
-        self.coalesce_results([new_manifest])
+    log_1 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "TIMEOUT",
+                                        "expected": "FAIL"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"debug": True, "os": "osx"})
 
-        self.assertFalse(new_manifest.is_empty)
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": False, "os": "osx"}), "FAIL")
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": True, "os": "osx"}), "TIMEOUT")
+    id_test_map = update(tests, log_0, log_1)
+    new_manifest = id_test_map.popitem()[1].expected
 
-    @pytest.mark.xfail
-    def test_update_ignore_existing(self):
-        test_id = "/path/to/test.htm"
-        prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
-  type: testharness
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": False, "os": "osx"}) == "FAIL"
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": True, "os": "osx"}) == "TIMEOUT"
+
+
+def test_update_ignore_existing():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
   [test1]
     expected:
       if debug: TIMEOUT
       if not debug and os == "osx": NOTRUN""")]
 
-        new_data_0 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "FAIL",
-                                                      "expected": "PASS"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": False, "os": "linux"})
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "FAIL",
+                                        "expected": "PASS"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                       run_info={"debug": False, "os": "linux"})
+
+    log_1 = suite_log([("test_start", {"test": test_id}),
+                       ("test_status", {"test": test_id,
+                                        "subtest": "test1",
+                                        "status": "FAIL",
+                                        "expected": "PASS"}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"debug": True, "os": "windows"})
+
+    id_test_map = update(tests, log_0, log_1)
+    new_manifest = id_test_map.popitem()[1].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": True, "os": "osx"}) == "FAIL"
+    assert new_manifest.get_test(test_id).children[0].get(
+        "expected", {"debug": False, "os": "osx"}) == "NOTRUN"
+
+
+def test_update_assertion_count_0():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
+  max-asserts: 4
+  min-asserts: 2
+""")]
+
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("assertion_count", {"test": test_id,
+                                            "count": 6,
+                                            "min_expected": 2,
+                                            "max_expected": 4}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})])
+
+    id_test_map = update(tests, log_0)
+    new_manifest = id_test_map.popitem()[1].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).get("max-asserts") == 7
+    assert new_manifest.get_test(test_id).get("min-asserts") == 2
+
+
+def test_update_assertion_count_1():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
+  max-asserts: 4
+  min-asserts: 2
+""")]
+
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("assertion_count", {"test": test_id,
+                                            "count": 1,
+                                            "min_expected": 2,
+                                            "max_expected": 4}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})])
+
+    id_test_map = update(tests, log_0)
+    new_manifest = id_test_map.popitem()[1].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).get("max-asserts") == 4
+    assert new_manifest.get_test(test_id).has_key("min-asserts") is False
+
+
+def test_update_assertion_count_2():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
+  max-asserts: 4
+  min-asserts: 2
+""")]
+
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("assertion_count", {"test": test_id,
+                                            "count": 3,
+                                            "min_expected": 2,
+                                            "max_expected": 4}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})])
+
+    id_test_map = update(tests, log_0)
+    new_manifest = id_test_map.popitem()[1].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).get("max-asserts") == 4
+    assert new_manifest.get_test(test_id).get("min-asserts") == 2
+
+
+def test_update_assertion_count_3():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]
+  max-asserts: 4
+  min-asserts: 2
+""")]
+
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("assertion_count", {"test": test_id,
+                                            "count": 6,
+                                            "min_expected": 2,
+                                            "max_expected": 4}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"os": "windows"})
 
-        new_data_1 = self.create_log(("test_start", {"test": test_id}),
-                                     ("test_status", {"test": test_id,
-                                                      "subtest": "test1",
-                                                      "status": "FAIL",
-                                                      "expected": "PASS"}),
-                                     ("test_end", {"test": test_id,
-                                                   "status": "OK"}),
-                                     run_info={"debug": True, "os": "windows"})
-        updater = self.create_updater(prev_data, ignore_existing=True)
+    log_1 = suite_log([("test_start", {"test": test_id}),
+                       ("assertion_count", {"test": test_id,
+                                            "count": 7,
+                                            "min_expected": 2,
+                                            "max_expected": 4}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"os": "linux"})
+
+    id_test_map = update(tests, log_0, log_1)
+    new_manifest = id_test_map.popitem()[1].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).get("max-asserts") == 8
+    assert new_manifest.get_test(test_id).get("min-asserts") == 2
+
+
+def test_update_assertion_count_4():
+    test_id = "/path/to/test.htm"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", """[test.htm]""")]
+
+    log_0 = suite_log([("test_start", {"test": test_id}),
+                       ("assertion_count", {"test": test_id,
+                                            "count": 6,
+                                            "min_expected": 0,
+                                            "max_expected": 0}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"os": "windows"})
+
+    log_1 = suite_log([("test_start", {"test": test_id}),
+                       ("assertion_count", {"test": test_id,
+                                            "count": 7,
+                                            "min_expected": 0,
+                                            "max_expected": 0}),
+                       ("test_end", {"test": test_id,
+                                     "status": "OK"})],
+                      run_info={"os": "linux"})
+
+    id_test_map = update(tests, log_0, log_1)
+    new_manifest = id_test_map.popitem()[1].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get_test(test_id).get("max-asserts") == "8"
+    assert new_manifest.get_test(test_id).has_key("min-asserts") is False
+
+
+def test_update_lsan_0():
+    test_id = "/path/to/test.htm"
+    dir_id = "path/to/__dir__"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", ""),
+             ("path/to/__dir__.ini", [dir_id], None, "")]
+
+    log_0 = suite_log([("lsan_leak", {"scope": "path/to/",
+                                      "frames": ["foo", "bar"]})])
+
+
+    id_test_map = update(tests, log_0)
+    new_manifest = id_test_map[dir_id].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get("lsan-allowed") == ["foo"]
 
-        updater.update_from_log(new_data_0)
-        updater.update_from_log(new_data_1)
+
+def test_update_lsan_1():
+    test_id = "/path/to/test.htm"
+    dir_id = "path/to/__dir__"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", ""),
+             ("path/to/__dir__.ini", [dir_id], None, """
+lsan-allowed: [foo]""")]
+
+    log_0 = suite_log([("lsan_leak", {"scope": "path/to/",
+                                      "frames": ["foo", "bar"]}),
+                       ("lsan_leak", {"scope": "path/to/",
+                                      "frames": ["baz", "foobar"]})])
+
 
-        new_manifest = updater.expected_tree["path/to/test.htm.ini"]
+    id_test_map = update(tests, log_0)
+    new_manifest = id_test_map[dir_id].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get("lsan-allowed") == ["baz", "foo"]
+
+
+def test_update_lsan_2():
+    test_id = "/path/to/test.htm"
+    dir_id = "path/to/__dir__"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", ""),
+             ("path/__dir__.ini", ["path/__dir__"], None, """
+lsan-allowed: [foo]"""),
+             ("path/to/__dir__.ini", [dir_id], None, "")]
 
-        self.coalesce_results([new_manifest])
+    log_0 = suite_log([("lsan_leak", {"scope": "path/to/",
+                                      "frames": ["foo", "bar"],
+                                      "allowed_match": ["foo"]}),
+                       ("lsan_leak", {"scope": "path/to/",
+                                      "frames": ["baz", "foobar"]})])
+
+
+    id_test_map = update(tests, log_0)
+    new_manifest = id_test_map[dir_id].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get("lsan-allowed") == ["baz"]
+
 
-        self.assertFalse(new_manifest.is_empty)
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": True, "os": "osx"}), "FAIL")
-        self.assertEquals(new_manifest.get_test(test_id).children[0].get(
-            "expected", {"debug": False, "os": "osx"}), "FAIL")
+def test_update_lsan_3():
+    test_id = "/path/to/test.htm"
+    dir_id = "path/to/__dir__"
+    tests = [("path/to/test.htm.ini", [test_id], "testharness", ""),
+             ("path/to/__dir__.ini", [dir_id], None, "")]
+
+    log_0 = suite_log([("lsan_leak", {"scope": "path/to/",
+                                      "frames": ["foo", "bar"]})],
+                      run_info={"os": "win"})
+
+    log_1 = suite_log([("lsan_leak", {"scope": "path/to/",
+                                      "frames": ["baz", "foobar"]})],
+                      run_info={"os": "linux"})
+
+
+    id_test_map = update(tests, log_0, log_1)
+    new_manifest = id_test_map[dir_id].expected
+
+    assert not new_manifest.is_empty
+    assert new_manifest.get("lsan-allowed") == ["baz", "foo"]
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/update/metadata.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/update/metadata.py
@@ -13,33 +13,31 @@ class GetUpdatePropertyList(Step):
             state.config, state.product)
         state.property_order = property_order + state.extra_properties
         state.boolean_properties = boolean_properties
 
 
 class UpdateExpected(Step):
     """Do the metadata update on the local checkout"""
 
-    provides = ["needs_human"]
-
     def create(self, state):
         if state.sync_tree is not None:
             sync_root = state.sync_tree.root
         else:
             sync_root = None
 
-        state.needs_human = metadata.update_expected(state.paths,
-                                                     state.serve_root,
-                                                     state.run_log,
-                                                     rev_old=None,
-                                                     ignore_existing=state.ignore_existing,
-                                                     sync_root=sync_root,
-                                                     property_order=state.property_order,
-                                                     boolean_properties=state.boolean_properties,
-                                                     stability=state.stability)
+        metadata.update_expected(state.paths,
+                                 state.serve_root,
+                                 state.run_log,
+                                 rev_old=None,
+                                 ignore_existing=state.ignore_existing,
+                                 sync_root=sync_root,
+                                 property_order=state.property_order,
+                                 boolean_properties=state.boolean_properties,
+                                 stability=state.stability)
 
 
 class CreateMetadataPatch(Step):
     """Create a patch/commit for the metadata checkout"""
 
     def create(self, state):
         if not state.patch:
             return
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py
@@ -21,17 +21,25 @@ class ConditionalValue(object):
     def value(self):
         if isinstance(self.value_node, ValueNode):
             return self.value_node.data
         else:
             return [item.data for item in self.value_node.children]
 
     @value.setter
     def value(self, value):
-        self.value_node.data = value
+        if isinstance(self.value_node, ValueNode):
+            self.value_node.data = value
+        else:
+            assert(isinstance(self.value_node, ListNode))
+            while self.value_node.children:
+                self.value_node.children[0].remove()
+            assert len(self.value_node.children) == 0
+            for list_value in value:
+                self.value_node.append(ValueNode(list_value))
 
     def __call__(self, run_info):
         return self.condition_func(run_info)
 
     def set_value(self, value):
         if type(value) not in (str, unicode):
             value = unicode(value)
         self.value = value
@@ -262,17 +270,22 @@ class ManifestItem(object):
                     node = child
                     break
             assert node is not None
 
         else:
             node = KeyValueNode(key)
             self.node.append(node)
 
-        value_node = ValueNode(unicode(value))
+        if isinstance(value, list):
+            value_node = ListNode()
+            for item in value:
+                value_node.append(ValueNode(unicode(item)))
+        else:
+            value_node = ValueNode(unicode(value))
         if condition is not None:
             conditional_node = ConditionalNode()
             conditional_node.append(condition)
             conditional_node.append(value_node)
             node.append(conditional_node)
             cond_value = Compiler().compile_condition(conditional_node)
         else:
             node.append(value_node)
@@ -323,17 +336,20 @@ class ManifestItem(object):
         for item in self._flatten().iteritems():
             yield item
 
     def iterkeys(self):
         for item in self._flatten().iterkeys():
             yield item
 
     def remove_value(self, key, value):
-        self._data[key].remove(value)
+        try:
+            self._data[key].remove(value)
+        except ValueError:
+            return
         if not self._data[key]:
             del self._data[key]
         value.remove()
 
 
 def compile_ast(ast, data_cls_getter=None, **kwargs):
     return Compiler().compile(ast, data_cls_getter=data_cls_getter, **kwargs)
 
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptrunner.py
@@ -200,17 +200,18 @@ def run_tests(config, test_paths, produc
                 repeat_count += 1
                 if repeat_until_unexpected:
                     logger.info("Repetition %i" % (repeat_count))
                 elif repeat > 1:
                     logger.info("Repetition %i / %i" % (repeat_count, repeat))
 
                 test_count = 0
                 unexpected_count = 0
-                logger.suite_start(test_loader.test_ids, name='web-platform-test', run_info=run_info)
+                logger.suite_start(test_loader.test_ids, name='web-platform-test', run_info=run_info,
+                                   extra={"run_by_dir": kwargs["run_by_dir"]})
                 for test_type in kwargs["test_types"]:
                     logger.info("Running %s tests" % test_type)
 
                     # WebDriver tests may create and destroy multiple browser
                     # processes as part of their expected behavior. These
                     # processes are managed by a WebDriver server binary. This
                     # obviates the need for wptrunner to provide a browser, so
                     # the NullBrowser is used in place of the "target" browser
@@ -311,16 +312,17 @@ def check_stability(**kwargs):
     return stability.check_stability(logger,
                                      max_time=kwargs['verify_max_time'],
                                      chaos_mode=kwargs['verify_chaos_mode'],
                                      repeat_loop=kwargs['verify_repeat_loop'],
                                      repeat_restart=kwargs['verify_repeat_restart'],
                                      output_results=kwargs['verify_output_results'],
                                      **kwargs)
 
+
 def start(**kwargs):
     if kwargs["list_test_groups"]:
         list_test_groups(**kwargs)
     elif kwargs["list_disabled"]:
         list_disabled(**kwargs)
     elif kwargs["list_tests"]:
         list_tests(**kwargs)
     elif kwargs["verify"] or kwargs["stability"]:
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/wpttest.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wpttest.py
@@ -210,16 +210,26 @@ class Test(object):
     def max_assertion_count(self):
         for meta in self.itermeta(None):
             count = meta.max_assertion_count
             if count is not None:
                 return count
         return 0
 
     @property
+    def lsan_allowed(self):
+        lsan_allowed = set()
+        for meta in self.itermeta():
+            lsan_allowed |= meta.lsan_allowed
+            if atom_reset in lsan_allowed:
+                lsan_allowed.remove(atom_reset)
+                break
+        return lsan_allowed
+
+    @property
     def tags(self):
         tags = set()
         for meta in self.itermeta():
             meta_tags = meta.tags
             tags |= meta_tags
             if atom_reset in meta_tags:
                 tags.remove(atom_reset)
                 break
--- a/toolkit/components/backgroundhangmonitor/HangDetails.cpp
+++ b/toolkit/components/backgroundhangmonitor/HangDetails.cpp
@@ -362,18 +362,17 @@ ReadModuleInformation(HangStack& stack)
         moduleReferenced = true;
         uint32_t module = stack.modules().Length();
         HangEntryModOffset modOffset(module, static_cast<uint32_t>(offset));
         *frame = modOffset;
       }
     }
 
     if (moduleReferenced) {
-      nsDependentCString cstr(info.GetBreakpadId().c_str());
-      HangModule module(info.GetDebugName(), cstr);
+      HangModule module(info.GetDebugName(), info.GetBreakpadId());
       stack.modules().AppendElement(module);
     }
   }
 #endif
 }
 
 NS_IMETHODIMP
 ProcessHangStackRunnable::Run()
--- a/toolkit/components/telemetry/CombinedStacks.cpp
+++ b/toolkit/components/telemetry/CombinedStacks.cpp
@@ -162,17 +162,17 @@ CreateJSStackObject(JSContext *cx, const
 
     // Module name
     JS::Rooted<JSString*> str(cx, JS_NewUCStringCopyZ(cx, module.mName.get()));
     if (!str || !JS_DefineElement(cx, moduleInfoArray, index++, str, JSPROP_ENUMERATE)) {
       return nullptr;
     }
 
     // Module breakpad identifier
-    JS::Rooted<JSString*> id(cx, JS_NewStringCopyZ(cx, module.mBreakpadId.c_str()));
+    JS::Rooted<JSString*> id(cx, JS_NewStringCopyZ(cx, module.mBreakpadId.get()));
     if (!id || !JS_DefineElement(cx, moduleInfoArray, index++, id, JSPROP_ENUMERATE)) {
       return nullptr;
     }
   }
 
   JS::Rooted<JSObject*> reportArray(cx, JS_NewArrayObject(cx, 0));
   if (!reportArray) {
     return nullptr;
--- a/toolkit/components/telemetry/ProcessedStack.h
+++ b/toolkit/components/telemetry/ProcessedStack.h
@@ -31,17 +31,17 @@ public:
     // was in.
     uint16_t mModIndex;
   };
   struct Module
   {
     // The file name, /foo/bar/libxul.so for example.
     // It can contain unicode characters.
     nsString mName;
-    std::string mBreakpadId;
+    nsCString mBreakpadId;
 
     bool operator==(const Module& other) const;
   };
 
   const Frame &GetFrame(unsigned aIndex) const;
   void AddFrame(const Frame& aFrame);
   const Module &GetModule(unsigned aIndex) const;
   void AddModule(const Module& aFrame);
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -789,18 +789,18 @@ public:
       if (!JS_DefineProperty(cx, moduleObj, "debugName", moduleDebugName, JSPROP_ENUMERATE)) {
         mPromise->MaybeReject(NS_ERROR_FAILURE);
         return NS_OK;
       }
 
       // Module Breakpad identifier.
       JS::RootedValue id(cx);
 
-      if (!info.GetBreakpadId().empty()) {
-        JS::RootedString str_id(cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().c_str()));
+      if (!info.GetBreakpadId().IsEmpty()) {
+        JS::RootedString str_id(cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().get()));
         if (!str_id) {
           mPromise->MaybeReject(NS_ERROR_FAILURE);
           return NS_OK;
         }
         id.setString(str_id);
       } else {
         id.setNull();
       }
@@ -808,18 +808,18 @@ public:
       if (!JS_DefineProperty(cx, moduleObj, "debugID", id, JSPROP_ENUMERATE)) {
         mPromise->MaybeReject(NS_ERROR_FAILURE);
         return NS_OK;
       }
 
       // Module version.
       JS::RootedValue version(cx);
 
-      if (!info.GetVersion().empty()) {
-        JS::RootedString v(cx, JS_NewStringCopyZ(cx, info.GetVersion().c_str()));
+      if (!info.GetVersion().IsEmpty()) {
+        JS::RootedString v(cx, JS_NewStringCopyZ(cx, info.GetVersion().BeginReading()));
         if (!v) {
           mPromise->MaybeReject(NS_ERROR_FAILURE);
           return NS_OK;
         }
         version.setString(v);
       } else {
         version.setNull();
       }
@@ -985,17 +985,17 @@ ReadStack(PathCharPtr aFileName, Telemet
     std::string moduleName;
     getline(file, moduleName);
     if (file.fail() || moduleName[0] == ' ') {
       return;
     }
 
     Telemetry::ProcessedStack::Module module = {
       NS_ConvertUTF8toUTF16(moduleName.c_str()),
-      breakpadId
+      nsCString(breakpadId.c_str(), breakpadId.size()),
     };
     stack.AddModule(module);
   }
 
   size_t numFrames;
   file >> numFrames;
   if (file.fail()) {
     return;
--- a/toolkit/content/tests/chrome/test_custom_element_base.xul
+++ b/toolkit/content/tests/chrome/test_custom_element_base.xul
@@ -7,24 +7,27 @@
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
 
+  <simpleelement id="simple"/>
+
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
   SimpleTest.waitForExplicitFinish();
 
   function runTests() {
     ok(MozXULElement, "MozXULElement defined on the window");
     testParseXULToFragment();
+    testCustomInterface();
     SimpleTest.finish();
   }
 
   function testParseXULToFragment() {
     ok(MozXULElement.parseXULToFragment, "parseXULToFragment helper exists");
 
     let frag = MozXULElement.parseXULToFragment(`<deck id='foo' />`);
     ok(frag instanceof DocumentFragment);
@@ -34,12 +37,45 @@
     let deck = document.documentElement.lastChild;
     ok(deck instanceof MozXULElement, "instance of MozXULElement");
     ok(deck instanceof XULElement, "instance of XULElement");
     is(deck.id, "foo", "attribute set");
     is(deck.selectedIndex, "0", "Custom Element is property attached");
     deck.remove();
   }
 
+  function testCustomInterface() {
+    class SimpleElement extends MozXULElement {
+      get disabled() {
+        return false;
+      }
+
+      set disabled(val) {
+      }
+
+      get tabIndex() {
+        return 0;
+      }
+
+      set tabIndex(val) {
+      }
+    }
+
+    customElements.define("simpleelement", SimpleElement);
+    MozXULElement.implementCustomInterface(SimpleElement, [Ci.nsIDOMXULControlElement]);
+
+    is(document.documentElement.getCustomInterfaceCallback, undefined,
+       "No getCustomInterfaceCallback on non-custom element");
+    is(typeof document.getElementById("simple").getCustomInterfaceCallback, "function",
+       "getCustomInterfaceCallback available on custom element when set");
+    try {
+      document.documentElement.QueryInterface(Ci.nsIDOMXULControlElement)
+      ok(false, "Non-custom element implements custom interface");
+    } catch (ex) {
+      ok(true, "Non-custom element implements custom interface");
+    }
+    ok(document.getElementById("simple").QueryInterface(Ci.nsIDOMXULControlElement),
+       "Implements custom interface");
+  }
   ]]>
   </script>
 </window>
 
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -1509,17 +1509,17 @@ AddSharedLibraryInfoToStream(JSONWriter&
   aWriter.StartObjectElement();
   aWriter.IntProperty("start", SafeJSInteger(aLib.GetStart()));
   aWriter.IntProperty("end", SafeJSInteger(aLib.GetEnd()));
   aWriter.IntProperty("offset", SafeJSInteger(aLib.GetOffset()));
   aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(aLib.GetModuleName()).get());
   aWriter.StringProperty("path", NS_ConvertUTF16toUTF8(aLib.GetModulePath()).get());
   aWriter.StringProperty("debugName", NS_ConvertUTF16toUTF8(aLib.GetDebugName()).get());
   aWriter.StringProperty("debugPath", NS_ConvertUTF16toUTF8(aLib.GetDebugPath()).get());
-  aWriter.StringProperty("breakpadId", aLib.GetBreakpadId().c_str());
+  aWriter.StringProperty("breakpadId", aLib.GetBreakpadId().get());
   aWriter.StringProperty("arch", aLib.GetArch().c_str());
   aWriter.EndObject();
 }
 
 void
 AppendSharedLibraries(JSONWriter& aWriter)
 {
   SharedLibraryInfo info = SharedLibraryInfo::GetInfoForSelf();
--- a/tools/profiler/core/shared-libraries-linux.cc
+++ b/tools/profiler/core/shared-libraries-linux.cc
@@ -58,44 +58,57 @@ struct LoadedLibraryInfo
 #if defined(GP_OS_android)
 static void
 outputMapperLog(const char* aBuf)
 {
   LOG("%s", aBuf);
 }
 #endif
 
-// Get the breakpad Id for the binary file pointed by bin_name
-static std::string getId(const char *bin_name)
+static nsCString
+IDtoUUIDString(const google_breakpad::wasteful_vector<uint8_t>& aIdentifier)
 {
   using namespace google_breakpad;
-  using namespace std;
+
+  nsCString uuid;
+  const std::string str = FileID::ConvertIdentifierToUUIDString(aIdentifier);
+  uuid.Append(str.c_str(), str.size());
+  // This is '0', not '\0', since it represents the breakpad id age.
+  uuid.Append('0');
+  return uuid;
+}
+
+// Get the breakpad Id for the binary file pointed by bin_name
+static nsCString
+getId(const char *bin_name)
+{
+  using namespace google_breakpad;
 
   PageAllocator allocator;
   auto_wasteful_vector<uint8_t, sizeof(MDGUID)> identifier(&allocator);
 
 #if defined(GP_OS_android)
   if (nsCString(bin_name).Find("!/") != kNotFound) {
     AutoObjectMapperFaultyLib mapper(outputMapperLog);
     void* image = nullptr;
     size_t size = 0;
     if (mapper.Map(&image, &size, bin_name) && image && size) {
       if (FileID::ElfFileIdentifierFromMappedFile(image, identifier)) {
-        return FileID::ConvertIdentifierToUUIDString(identifier) + "0";
+        return IDtoUUIDString(identifier);
       }
     }
   }
 #endif
 
   FileID file_id(bin_name);
   if (file_id.ElfFileIdentifier(identifier)) {
-    return FileID::ConvertIdentifierToUUIDString(identifier) + "0";
+    return IDtoUUIDString(identifier);
   }
 
-  return "";
+  return EmptyCString();
 }
 
 static SharedLibrary
 SharedLibraryAtPath(const char* path, unsigned long libStart,
                     unsigned long libEnd, unsigned long offset = 0)
 {
   nsAutoString pathStr;
   mozilla::Unused <<
@@ -105,17 +118,17 @@ SharedLibraryAtPath(const char* path, un
   nsAutoString nameStr = pathStr;
   int32_t pos = nameStr.RFindChar('/');
   if (pos != kNotFound) {
     nameStr.Cut(0, pos + 1);
   }
 
   return SharedLibrary(libStart, libEnd, offset, getId(path),
                        nameStr, pathStr, nameStr, pathStr,
-                       "", "");
+                       EmptyCString(), "");
 }
 
 static int
 dl_iterate_callback(struct dl_phdr_info *dl_info, size_t size, void *data)
 {
   auto libInfoList = reinterpret_cast<nsTArray<LoadedLibraryInfo>*>(data);
 
   if (dl_info->dlpi_phnum <= 0)
--- a/tools/profiler/core/shared-libraries-macos.cc
+++ b/tools/profiler/core/shared-libraries-macos.cc
@@ -124,41 +124,44 @@ void addSharedLibrary(const platform_mac
       const uuid_command *ucmd = reinterpret_cast<const uuid_command *>(cmd);
       uuid_bytes = ucmd->uuid;
     }
 
     cmd = reinterpret_cast<const struct load_command *>
       (reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
   }
 
-  std::stringstream uuid;
-  uuid << std::hex << std::uppercase;
+  nsAutoCString uuid;
   if (uuid_bytes != nullptr) {
-    for (int i = 0; i < 16; ++i) {
-      uuid << ((uuid_bytes[i] & 0xf0) >> 4);
-      uuid << (uuid_bytes[i] & 0xf);
-    }
-    uuid << '0';
+    uuid.AppendPrintf("%02X" "%02X" "%02X" "%02X"
+                      "%02X" "%02X" "%02X" "%02X"
+                      "%02X" "%02X" "%02X" "%02X"
+                      "%02X" "%02X" "%02X" "%02X"
+                      "0" /* breakpad id age */,
+                      uuid_bytes[0], uuid_bytes[1], uuid_bytes[2], uuid_bytes[3],
+                      uuid_bytes[4], uuid_bytes[5], uuid_bytes[6], uuid_bytes[7],
+                      uuid_bytes[8], uuid_bytes[9], uuid_bytes[10], uuid_bytes[11],
+                      uuid_bytes[12], uuid_bytes[13], uuid_bytes[14], uuid_bytes[15]);
   }
 
   nsAutoString pathStr;
   mozilla::Unused << NS_WARN_IF(NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(path), pathStr)));
 
   nsAutoString nameStr = pathStr;
   int32_t pos = nameStr.RFindChar('/');
   if (pos != kNotFound) {
     nameStr.Cut(0, pos + 1);
   }
 
   const NXArchInfo* archInfo =
     NXGetArchInfoFromCpuType(header->cputype, header->cpusubtype);
 
-  info.AddSharedLibrary(SharedLibrary(start, start + size, 0, uuid.str(),
+  info.AddSharedLibrary(SharedLibrary(start, start + size, 0, uuid,
                                       nameStr, pathStr, nameStr, pathStr,
-                                      "",
+                                      EmptyCString(),
                                       archInfo ? archInfo->name : ""));
 }
 
 // Translate the statically stored sSharedLibrariesList information into a
 // SharedLibraryInfo object.
 SharedLibraryInfo
 SharedLibraryInfo::GetInfoForSelf()
 {
--- a/tools/profiler/core/shared-libraries-win32.cc
+++ b/tools/profiler/core/shared-libraries-win32.cc
@@ -8,16 +8,18 @@
 #include <sstream>
 #include <psapi.h>
 
 #include "shared-libraries.h"
 #include "nsWindowsHelpers.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "nsNativeCharsetUtils.h"
+#include "nsPrintfCString.h"
+#include "nsReadableUtils.h"
 
 #define CV_SIGNATURE 0x53445352 // 'SDSR'
 
 struct CodeViewRecord70
 {
   uint32_t signature;
   GUID pdbSignature;
   uint32_t pdbAge;
@@ -74,44 +76,44 @@ static bool GetPdbInfo(uintptr_t aStart,
   return true;
 }
 
 static bool IsDashOrBraces(char c)
 {
   return c == '-' || c == '{' || c == '}';
 }
 
-std::string GetVersion(WCHAR* dllPath)
+static nsCString
+GetVersion(WCHAR* dllPath)
 {
   DWORD infoSize = GetFileVersionInfoSizeW(dllPath, nullptr);
   if (infoSize == 0) {
-    return "";
+    return EmptyCString();
   }
 
   mozilla::UniquePtr<unsigned char[]> infoData = mozilla::MakeUnique<unsigned char[]>(infoSize);
   if (!GetFileVersionInfoW(dllPath, 0, infoSize, infoData.get())) {
-    return "";
+    return EmptyCString();
   }
 
   VS_FIXEDFILEINFO* vInfo;
   UINT vInfoLen;
   if (!VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)) {
-    return "";
+    return EmptyCString();
   }
   if (!vInfo) {
-    return "";
+    return EmptyCString();
   }
 
-  std::ostringstream stream;
-  stream << (vInfo->dwFileVersionMS >> 16)    << "."
-         << (vInfo->dwFileVersionMS & 0xFFFF) << "."
-         << (vInfo->dwFileVersionLS >> 16)    << "."
-         << (vInfo->dwFileVersionLS & 0xFFFF);
-
-  return stream.str();
+  nsPrintfCString version("%d.%d.%d.%d",
+                          vInfo->dwFileVersionMS >> 16,
+                          vInfo->dwFileVersionMS & 0xFFFF,
+                          vInfo->dwFileVersionLS >> 16,
+                          vInfo->dwFileVersionLS & 0xFFFF);
+  return version;
 }
 
 SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
 {
   SharedLibraryInfo sharedLibraryInfo;
 
   HANDLE hProcess = GetCurrentProcess();
   mozilla::UniquePtr<HMODULE[]> hMods;
@@ -128,58 +130,60 @@ SharedLibraryInfo SharedLibraryInfo::Get
     }
     // The list may have shrunk between calls
     if (modulesSize / sizeof(HMODULE) < modulesNum) {
       modulesNum = modulesSize / sizeof(HMODULE);
     }
   }
 
   for (unsigned int i = 0; i < modulesNum; i++) {
-    nsID pdbSig;
-    uint32_t pdbAge;
     nsAutoString pdbPathStr;
     nsAutoString pdbNameStr;
     char *pdbName = NULL;
-    std::string breakpadId;
     WCHAR modulePath[MAX_PATH + 1];
 
     if (!GetModuleFileNameEx(hProcess, hMods[i], modulePath, sizeof(modulePath) / sizeof(WCHAR))) {
       continue;
     }
 
     MODULEINFO module = {0};
     if (!GetModuleInformation(hProcess, hMods[i], &module, sizeof(MODULEINFO))) {
       continue;
     }
 
+    nsCString breakpadId;
     // Load the module again to make sure that its handle will remain
     // valid as we attempt to read the PDB information from it.  We load the
     // DLL as a datafile so that if the module actually gets unloaded between
     // the call to EnumProcessModules and the following LoadLibraryEx, we don't
     // end up running the now newly loaded module's DllMain function.  If the
     // module is already loaded, LoadLibraryEx just increments its refcount.
     //
     // Note that because of the race condition above, merely loading the DLL
     // again is not safe enough, therefore we also need to make sure that we
     // can read the memory mapped at the base address before we can safely
     // proceed to actually access those pages.
     HMODULE handleLock = LoadLibraryEx(modulePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
     MEMORY_BASIC_INFORMATION vmemInfo = { 0 };
+    nsID pdbSig;
+    uint32_t pdbAge;
     if (handleLock &&
       sizeof(vmemInfo) == VirtualQuery(module.lpBaseOfDll, &vmemInfo, sizeof(vmemInfo)) &&
       vmemInfo.State == MEM_COMMIT &&
       GetPdbInfo((uintptr_t)module.lpBaseOfDll, pdbSig, pdbAge, &pdbName)) {
-      std::ostringstream stream;
-      stream << pdbSig.ToString() << std::hex << pdbAge;
-      breakpadId = stream.str();
-      std::string::iterator end =
-        std::remove_if(breakpadId.begin(), breakpadId.end(), IsDashOrBraces);
-      breakpadId.erase(end, breakpadId.end());
-      std::transform(breakpadId.begin(), breakpadId.end(),
-        breakpadId.begin(), toupper);
+      MOZ_ASSERT(breakpadId.IsEmpty());
+      breakpadId.AppendPrintf("%08X" // m0
+                              "%04X%04X" // m1,m2
+                              "%02X%02X%02X%02X%02X%02X%02X%02X" // m3
+                              "%X", // pdbAge
+                              pdbSig.m0,
+                              pdbSig.m1, pdbSig.m2,
+                              pdbSig.m3[0], pdbSig.m3[1], pdbSig.m3[2], pdbSig.m3[3],
+                              pdbSig.m3[4], pdbSig.m3[5], pdbSig.m3[6], pdbSig.m3[7],
+                              pdbAge);
 
       pdbPathStr = NS_ConvertUTF8toUTF16(pdbName);
       pdbNameStr = pdbPathStr;
       int32_t pos = pdbNameStr.RFindChar('\\');
       if (pos != kNotFound) {
         pdbNameStr.Cut(0, pos + 1);
       }
     }
--- a/tools/profiler/public/shared-libraries.h
+++ b/tools/profiler/public/shared-libraries.h
@@ -21,22 +21,22 @@
 #include "nsNativeCharsetUtils.h"
 
 class SharedLibrary {
 public:
 
   SharedLibrary(uintptr_t aStart,
                 uintptr_t aEnd,
                 uintptr_t aOffset,
-                const std::string& aBreakpadId,
+                const nsCString& aBreakpadId,
                 const nsString& aModuleName,
                 const nsString& aModulePath,
                 const nsString& aDebugName,
                 const nsString& aDebugPath,
-                const std::string& aVersion,
+                const nsCString& aVersion,
                 const char* aArch)
     : mStart(aStart)
     , mEnd(aEnd)
     , mOffset(aOffset)
     , mBreakpadId(aBreakpadId)
     , mModuleName(aModuleName)
     , mModulePath(aModulePath)
     , mDebugName(aDebugName)
@@ -88,43 +88,43 @@ public:
            (mBreakpadId == other.mBreakpadId) &&
            (mVersion == other.mVersion) &&
            (mArch == other.mArch);
   }
 
   uintptr_t GetStart() const { return mStart; }
   uintptr_t GetEnd() const { return mEnd; }
   uintptr_t GetOffset() const { return mOffset; }
-  const std::string &GetBreakpadId() const { return mBreakpadId; }
+  const nsCString &GetBreakpadId() const { return mBreakpadId; }
   const nsString &GetModuleName() const { return mModuleName; }
   const nsString &GetModulePath() const { return mModulePath; }
   const std::string GetNativeDebugPath() const {
     nsAutoCString debugPathStr;
 
     NS_CopyUnicodeToNative(mDebugPath, debugPathStr);
 
     return debugPathStr.get();
   }
   const nsString &GetDebugName() const { return mDebugName; }
   const nsString &GetDebugPath() const { return mDebugPath; }
-  const std::string &GetVersion() const { return mVersion; }
+  const nsCString &GetVersion() const { return mVersion; }
   const std::string &GetArch() const { return mArch; }
 
 private:
   SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {}
 
   uintptr_t mStart;
   uintptr_t mEnd;
   uintptr_t mOffset;
-  std::string mBreakpadId;
+  nsCString mBreakpadId;
   nsString mModuleName;
   nsString mModulePath;
   nsString mDebugName;
   nsString mDebugPath;
-  std::string mVersion;
+  nsCString mVersion;
   std::string mArch;
 };
 
 static bool
 CompareAddresses(const SharedLibrary& first, const SharedLibrary& second)
 {
   return first.GetStart() < second.GetStart();
 }
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -3449,16 +3449,18 @@ static const NSString* kStateCollectionB
   // We override this so that it won't beep if it can't act.
   // We want to control the beeping for missing or disabled
   // commands ourselves.
   [self tryToPerform:aSelector with:nil];
 }
 
 - (id)accessibilityAttributeValue:(NSString *)attribute
 {
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
   id retval = [super accessibilityAttributeValue:attribute];
 
   // The following works around a problem with Text-to-Speech on OS X 10.7.
   // See bug 674612 for more info.
   //
   // When accessibility is off, AXUIElementCopyAttributeValue(), when called
   // on an AXApplication object to get its AXFocusedUIElement attribute,
   // always returns an AXWindow object (the actual browser window -- never a
@@ -3492,16 +3494,18 @@ static const NSString* kStateCollectionB
           ![item respondsToSelector:@selector(hasRepresentedView)]) {
         [holder removeObjectAtIndex:i];
       }
     }
     retval = [NSArray arrayWithArray:holder];
   }
 
   return retval;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 @end
 
 // This class allows us to exercise control over the window's title bar. This
 // allows for a "unified toolbar" look without having to extend the content
 // area into the title bar.
 //
--- a/xpcom/build/LateWriteChecks.cpp
+++ b/xpcom/build/LateWriteChecks.cpp
@@ -168,17 +168,17 @@ LateWriteObserver::Observe(IOInterposeOb
 #endif
 
   SHA1Stream sha1Stream(stream);
 
   size_t numModules = stack.GetNumModules();
   sha1Stream.Printf("%u\n", (unsigned)numModules);
   for (size_t i = 0; i < numModules; ++i) {
     Telemetry::ProcessedStack::Module module = stack.GetModule(i);
-    sha1Stream.Printf("%s %s\n", module.mBreakpadId.c_str(),
+    sha1Stream.Printf("%s %s\n", module.mBreakpadId.get(),
                       NS_ConvertUTF16toUTF8(module.mName).get());
   }
 
   size_t numFrames = stack.GetStackSize();
   sha1Stream.Printf("%u\n", (unsigned)numFrames);
   for (size_t i = 0; i < numFrames; ++i) {
     const Telemetry::ProcessedStack::Frame& frame = stack.GetFrame(i);
     // NOTE: We write the offsets, while the atos tool expects a value with