Merge inbound to mozilla-central. a=merge
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Tue, 22 May 2018 12:49:47 +0300
changeset 419320 f85be0c4f0562ea59a91000883e0e7848491837c
parent 419319 ac1c5c363e29e16c99c87a978d1db82b45a787ed (current diff)
parent 419202 116bf80e887145e918be4de6c6a11bad885c7d96 (diff)
child 419321 b75acf9652937ce79a9bf02de843c100db0e5ec7
push id103497
push usernbeleuzu@mozilla.com
push dateTue, 22 May 2018 11:25:17 +0000
treeherdermozilla-inbound@738e6d38c1d9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
f85be0c4f056 / 62.0a1 / 20180522100110 / files
nightly linux64
f85be0c4f056 / 62.0a1 / 20180522100110 / files
nightly mac
f85be0c4f056 / 62.0a1 / 20180522100110 / files
nightly win32
f85be0c4f056 / 62.0a1 / 20180522100110 / files
nightly win64
f85be0c4f056 / 62.0a1 / 20180522100110 / 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
browser/app/profile/firefox.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1018,18 +1018,19 @@ pref("dom.ipc.shims.enabledWarnings", fa
 // 0 - no sandbox
 // 1 - sandbox with USER_NON_ADMIN access token level
 // 2 - a more strict sandbox, which might cause functionality issues. This now
 //     includes running at low integrity.
 // 3 - the strongest settings we seem to be able to use without breaking
 //     everything, but will probably cause some functionality restrictions
 pref("dom.ipc.plugins.sandbox-level.default", 0);
 #if defined(_AMD64_)
-// The lines in PluginModuleParent.cpp should be changed in line with this.
-pref("dom.ipc.plugins.sandbox-level.flash", 2);
+// The base sandbox level in nsPluginTag::InitSandboxLevel must be
+// updated to keep in sync with this value.
+pref("dom.ipc.plugins.sandbox-level.flash", 3);
 #else
 pref("dom.ipc.plugins.sandbox-level.flash", 0);
 #endif
 
 #if defined(MOZ_CONTENT_SANDBOX)
 // This controls the strength of the Windows content process sandbox for testing
 // purposes. This will require a restart.
 // On windows these levels are:
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -640,36 +640,39 @@ 64;
 static_assert(sizeof(nsINode::nsSlots) <= MaxDOMSlotSizeAllowed,
               "DOM slots cannot be grown without consideration");
 static_assert(sizeof(FragmentOrElement::nsDOMSlots) <= MaxDOMSlotSizeAllowed,
               "DOM slots cannot be grown without consideration");
 
 void
 nsIContent::nsExtendedContentSlots::Unlink()
 {
+  mBindingParent = nullptr;
   mXBLInsertionPoint = nullptr;
   mContainingShadow = nullptr;
   mAssignedSlot = nullptr;
 }
 
 void
 nsIContent::nsExtendedContentSlots::Traverse(nsCycleCollectionTraversalCallback& aCb)
 {
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mExtendedSlots->mBindingParent");
+  aCb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mBindingParent));
+
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mExtendedSlots->mContainingShadow");
   aCb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mExtendedSlots->mAssignedSlot");
   aCb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mAssignedSlot.get()));
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mExtendedSlots->mXBLInsertionPoint");
   aCb.NoteXPCOMChild(mXBLInsertionPoint.get());
 }
 
 nsIContent::nsExtendedContentSlots::nsExtendedContentSlots()
-  : mBindingParent(nullptr)
 {
 }
 
 nsIContent::nsExtendedContentSlots::~nsExtendedContentSlots() = default;
 
 FragmentOrElement::nsDOMSlots::nsDOMSlots()
   : nsIContent::nsContentSlots(),
     mDataset(nullptr)
@@ -731,18 +734,19 @@ FragmentOrElement::nsDOMSlots::SizeOfInc
   // - Superclass members (nsINode::nsSlots)
   // - mStyle
   // - mDataSet
   // - mSMILOverrideStyle
   // - mSMILOverrideStyleDeclaration
   // - mChildrenList
   // - mClassList
 
-  // The following members are not measured:
-  // - mBindingParent / mControllers: because they're   non-owning
+  // The following member are not measured:
+  // - mControllers: because it is non-owning
+  // - mBindingParent: because it is some ancestor element.
   return n;
 }
 
 FragmentOrElement::nsExtendedDOMSlots::nsExtendedDOMSlots() = default;
 
 FragmentOrElement::nsExtendedDOMSlots::~nsExtendedDOMSlots()
 {
   RefPtr<nsFrameLoader> frameLoader = do_QueryObject(mFrameLoaderOrOpener);
--- a/dom/base/StructuredCloneBlob.cpp
+++ b/dom/base/StructuredCloneBlob.cpp
@@ -137,17 +137,17 @@ StructuredCloneBlob::ReadStructuredClone
 #ifdef FUZZING
     if (blobOffset >= aHolder->BlobImpls().Length()) {
       return false;
     }
 #endif
     BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount);
   }
 
-  JSStructuredCloneData data;
+  JSStructuredCloneData data(mStructuredCloneScope);
   while (length) {
     size_t size;
     char* buffer = data.AllocateBytes(length, &size);
     if (!buffer || !JS_ReadBytes(aReader, buffer, size)) {
       return false;
     }
     length -= size;
   }
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -869,16 +869,17 @@ nsFrameMessageManager::ReceiveMessage(ns
             // report any exceptions (after which we'll move on to the next listener).
             continue;
           }
         }
       }
 
       if (aRetVal) {
         StructuredCloneData* data = aRetVal->AppendElement();
+        data->InitScope(JS::StructuredCloneScope::DifferentProcess);
         data->Write(cx, rval, aError);
         if (NS_WARN_IF(aError.Failed())) {
           aRetVal->RemoveLastElement();
           nsString msg = aMessage + NS_LITERAL_STRING(": message reply cannot be cloned. Are you trying to send an XPCOM object?");
 
           nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
           if (console) {
             nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -446,17 +446,17 @@ public:
    * null for all explicit content (i.e., content reachable from the top
    * of its GetParent() chain via child lists).
    *
    * @return the binding parent
    */
   virtual nsIContent* GetBindingParent() const
   {
     const nsExtendedContentSlots* slots = GetExistingExtendedContentSlots();
-    return slots ? slots->mBindingParent : nullptr;
+    return slots ? slots->mBindingParent.get() : nullptr;
   }
 
   /**
    * Gets the current XBL binding that is bound to this element.
    *
    * @return the current binding.
    */
   nsXBLBinding* GetXBLBinding() const
@@ -803,17 +803,17 @@ protected:
     virtual void Unlink();
 
     /**
      * The nearest enclosing content node with a binding that created us.
      * TODO(emilio): This should be an Element*.
      *
      * @see nsIContent::GetBindingParent
      */
-    nsIContent* mBindingParent;  // [Weak]
+    nsCOMPtr<nsIContent> mBindingParent;
 
     /**
      * @see nsIContent::GetXBLInsertionPoint
      */
     nsCOMPtr<nsIContent> mXBLInsertionPoint;
 
     /**
      * @see nsIContent::GetContainingShadow
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -19520,17 +19520,17 @@ UpgradeFileIdsFunction::OnFunctionCall(m
     return rv;
   }
 
   if (argc != 2) {
     NS_WARNING("Don't call me with the wrong number of arguments!");
     return NS_ERROR_UNEXPECTED;
   }
 
-  StructuredCloneReadInfo cloneInfo;
+  StructuredCloneReadInfo cloneInfo(JS::StructuredCloneScope::DifferentProcess);
   DatabaseOperationBase::GetStructuredCloneReadInfoFromValueArray(aArguments,
                                                                   1,
                                                                   0,
                                                                   mFileManager,
                                                                   &cloneInfo);
 
   nsAutoString fileIds;
   rv = IDBObjectStore::DeserializeUpgradeValueToFileIds(cloneInfo, fileIds);
@@ -25000,17 +25000,17 @@ UpdateIndexDataValuesFunction::OnFunctio
                valueType == mozIStorageValueArray::VALUE_TYPE_TEXT);
 
     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(3, &valueType));
     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_BLOB ||
                valueType == mozIStorageValueArray::VALUE_TYPE_INTEGER);
   }
 #endif
 
-  StructuredCloneReadInfo cloneInfo;
+  StructuredCloneReadInfo cloneInfo(JS::StructuredCloneScope::DifferentProcess);
   nsresult rv =
     GetStructuredCloneReadInfoFromValueArray(aValues,
                                              /* aDataIndex */ 3,
                                              /* aFileIdsIndex */ 2,
                                              mOp->mFileManager,
                                              &cloneInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -27698,17 +27698,17 @@ CursorOpBase::PopulateResponseFromStatem
 
   nsresult rv = mCursor->mKey.SetFromStatement(aStmt, 0);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   switch (mCursor->mType) {
     case OpenCursorParams::TObjectStoreOpenCursorParams: {
-      StructuredCloneReadInfo cloneInfo;
+      StructuredCloneReadInfo cloneInfo(JS::StructuredCloneScope::DifferentProcess);
       rv = GetStructuredCloneReadInfoFromStatement(aStmt,
                                                    2,
                                                    1,
                                                    mCursor->mFileManager,
                                                    &cloneInfo);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
@@ -27746,17 +27746,17 @@ CursorOpBase::PopulateResponseFromStatem
         return rv;
       }
 
       rv = mCursor->mObjectKey.SetFromStatement(aStmt, 2);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
-      StructuredCloneReadInfo cloneInfo;
+      StructuredCloneReadInfo cloneInfo(JS::StructuredCloneScope::DifferentProcess);
       rv = GetStructuredCloneReadInfoFromStatement(aStmt,
                                                    4,
                                                    3,
                                                    mCursor->mFileManager,
                                                    &cloneInfo);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -60,16 +60,20 @@ struct StructuredCloneFile
 struct StructuredCloneReadInfo
 {
   JSStructuredCloneData mData;
   nsTArray<StructuredCloneFile> mFiles;
   IDBDatabase* mDatabase;
   bool mHasPreprocessInfo;
 
   // In IndexedDatabaseInlines.h
+  inline explicit
+  StructuredCloneReadInfo(JS::StructuredCloneScope aScope);
+
+  // In IndexedDatabaseInlines.h
   inline
   StructuredCloneReadInfo();
 
   // In IndexedDatabaseInlines.h
   inline
   ~StructuredCloneReadInfo();
 
   // In IndexedDatabaseInlines.h
--- a/dom/indexedDB/IndexedDatabaseInlines.h
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -40,24 +40,31 @@ StructuredCloneFile::operator==(const St
 {
   return this->mBlob == aOther.mBlob &&
          this->mMutableFile == aOther.mMutableFile &&
          this->mFileInfo == aOther.mFileInfo &&
          this->mType == aOther.mType;
 }
 
 inline
-StructuredCloneReadInfo::StructuredCloneReadInfo()
-  : mDatabase(nullptr)
+StructuredCloneReadInfo::StructuredCloneReadInfo(JS::StructuredCloneScope aScope)
+  : mData(aScope)
+  , mDatabase(nullptr)
   , mHasPreprocessInfo(false)
 {
   MOZ_COUNT_CTOR(StructuredCloneReadInfo);
 }
 
 inline
+StructuredCloneReadInfo::StructuredCloneReadInfo()
+ : StructuredCloneReadInfo(JS::StructuredCloneScope::DifferentProcessForIndexedDB)
+{
+}
+
+inline
 StructuredCloneReadInfo::StructuredCloneReadInfo(
                              StructuredCloneReadInfo&& aCloneReadInfo)
   : mData(Move(aCloneReadInfo.mData))
 {
   MOZ_ASSERT(&aCloneReadInfo != this);
   MOZ_COUNT_CTOR(StructuredCloneReadInfo);
 
   mFiles.Clear();
--- a/dom/ipc/StructuredCloneData.cpp
+++ b/dom/ipc/StructuredCloneData.cpp
@@ -34,16 +34,17 @@ StructuredCloneData::StructuredCloneData
 {
   *this = Move(aOther);
 }
 
 StructuredCloneData::StructuredCloneData(TransferringSupport aSupportsTransferring)
   : StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
                           aSupportsTransferring,
                           StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
+  , mExternalData(JS::StructuredCloneScope::DifferentProcess)
   , mInitialized(false)
 {}
 
 StructuredCloneData::~StructuredCloneData()
 {}
 
 StructuredCloneData&
 StructuredCloneData::operator=(StructuredCloneData&& aOther)
@@ -119,17 +120,17 @@ StructuredCloneData::Write(JSContext* aC
   MOZ_ASSERT(!mInitialized);
 
   StructuredCloneHolder::Write(aCx, aValue, aTransfer,
                                JS::CloneDataPolicy().denySharedArrayBuffer(), aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  JSStructuredCloneData data;
+  JSStructuredCloneData data(mBuffer->scope());
   mBuffer->abandon();
   mBuffer->steal(&data);
   mBuffer = nullptr;
   mSharedData = new SharedJSAllocatedData(Move(data));
   mInitialized = true;
 }
 
 enum ActorFlavorEnum {
@@ -146,17 +147,17 @@ template<typename M>
 bool
 BuildClonedMessageData(M* aManager, StructuredCloneData& aData,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   auto iter = aData.Data().Start();
   size_t size = aData.Data().Size();
   bool success;
-  buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
+  buffer.data = aData.Data().Borrow(iter, size, &success);
   if (NS_WARN_IF(!success)) {
     return false;
   }
   if (aData.SupportsTransferring()) {
     aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
   }
 
   const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
@@ -417,17 +418,17 @@ StructuredCloneData::WriteIPCParams(IPC:
   WriteParam(aMsg, Data());
 }
 
 bool
 StructuredCloneData::ReadIPCParams(const IPC::Message* aMsg,
                                    PickleIterator* aIter)
 {
   MOZ_ASSERT(!mInitialized);
-  JSStructuredCloneData data;
+  JSStructuredCloneData data(JS::StructuredCloneScope::DifferentProcess);
   if (!ReadParam(aMsg, aIter, &data)) {
     return false;
   }
   mSharedData = new SharedJSAllocatedData(Move(data));
   mInitialized = true;
   return true;
 }
 
--- a/dom/ipc/StructuredCloneData.h
+++ b/dom/ipc/StructuredCloneData.h
@@ -49,27 +49,27 @@ class SharedJSAllocatedData final
 public:
   explicit SharedJSAllocatedData(JSStructuredCloneData&& aData)
     : mData(Move(aData))
   { }
 
   static already_AddRefed<SharedJSAllocatedData>
   CreateFromExternalData(const char* aData, size_t aDataLength)
   {
-    JSStructuredCloneData buf;
+    JSStructuredCloneData buf(JS::StructuredCloneScope::DifferentProcess);
     buf.AppendBytes(aData, aDataLength);
     RefPtr<SharedJSAllocatedData> sharedData =
       new SharedJSAllocatedData(Move(buf));
     return sharedData.forget();
   }
 
   static already_AddRefed<SharedJSAllocatedData>
   CreateFromExternalData(const JSStructuredCloneData& aData)
   {
-    JSStructuredCloneData buf;
+    JSStructuredCloneData buf(aData.scope());
     buf.Append(aData);
     RefPtr<SharedJSAllocatedData> sharedData =
       new SharedJSAllocatedData(Move(buf));
     return sharedData.forget();
   }
 
   NS_INLINE_DECL_REFCOUNTING(SharedJSAllocatedData)
 
@@ -231,18 +231,17 @@ public:
 
   // Initialize this instance, borrowing the contents of the given
   // JSStructuredCloneData.  You are responsible for ensuring that this
   // StructuredCloneData instance is destroyed before aData is destroyed.
   bool UseExternalData(const JSStructuredCloneData& aData)
   {
     auto iter = aData.Start();
     bool success = false;
-    mExternalData =
-      aData.Borrow<js::SystemAllocPolicy>(iter, aData.Size(), &success);
+    mExternalData = aData.Borrow(iter, aData.Size(), &success);
     mInitialized = true;
     return success;
   }
 
   // Initialize this instance by copying the given data that probably came from
   // nsStructuredClone doing a base64 decode.  Don't use this.
   bool CopyExternalData(const char* aData, size_t aDataLength);
   // Initialize this instance by copying the contents of an existing
@@ -261,16 +260,21 @@ public:
     return mSharedData ? mSharedData->Data() : mExternalData;
   }
 
   const JSStructuredCloneData& Data() const
   {
     return mSharedData ? mSharedData->Data() : mExternalData;
   }
 
+  void InitScope(JS::StructuredCloneScope aScope)
+  {
+    Data().initScope(aScope);
+  }
+
   size_t DataLength() const
   {
     return mSharedData ? mSharedData->DataLength() : mExternalData.Size();
   }
 
   SharedJSAllocatedData* SharedData() const
   {
     return mSharedData;
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -414,19 +414,19 @@ nsPluginTag::InitSandboxLevel()
   nsAutoCString sandboxPref("dom.ipc.plugins.sandbox-level.");
   sandboxPref.Append(GetNiceFileName());
   if (NS_FAILED(Preferences::GetInt(sandboxPref.get(), &mSandboxLevel))) {
     mSandboxLevel = Preferences::GetInt("dom.ipc.plugins.sandbox-level.default"
 );
   }
 
 #if defined(_AMD64_)
-  // As level 2 is now the default NPAPI sandbox level for 64-bit flash, we
-  // don't want to allow a lower setting. This should be changed if the
-  // firefox.js pref file is changed.
+  // Level 3 is now the default NPAPI sandbox level for 64-bit flash.
+  // We permit the user to drop the sandbox level by at most 1.  This should
+  // be kept up to date with the default value in the firefox.js pref file.
   if (mIsFlashPlugin && mSandboxLevel < 2) {
     mSandboxLevel = 2;
   }
 #endif /* defined(_AMD64_) */
 
 #elif defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   if (mIsFlashPlugin) {
     if (PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX") ||
--- a/dom/plugins/ipc/FunctionBroker.cpp
+++ b/dom/plugins/ipc/FunctionBroker.cpp
@@ -6,16 +6,17 @@
 
 #include "FunctionBroker.h"
 #include "FunctionBrokerParent.h"
 #include "PluginQuirks.h"
 
 #if defined(XP_WIN)
 #include <commdlg.h>
 #include <schannel.h>
+#include <sddl.h>
 #endif // defined(XP_WIN)
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 using namespace mozilla::plugins;
 
 namespace mozilla {
 namespace plugins {
@@ -25,34 +26,223 @@ static bool CheckQuirks(int aQuirks)
 {
   return static_cast<bool>(aQuirks & QuirkFlag);
 }
 
 void FreeDestructor(void* aObj) { free(aObj); }
 
 #if defined(XP_WIN)
 
+// Specialization of EndpointHandlers for Flash file dialog brokering.
+struct FileDlgEHContainer
+{
+  template<Endpoint e> struct EndpointHandler;
+};
+
+template<>
+struct FileDlgEHContainer::EndpointHandler<CLIENT> :
+  public BaseEndpointHandler<CLIENT, FileDlgEHContainer::EndpointHandler<CLIENT>>
+{
+  using BaseEndpointHandler<CLIENT, EndpointHandler<CLIENT>>::Copy;
+
+  inline static void Copy(OpenFileNameIPC& aDest, const LPOPENFILENAMEW& aSrc)
+  {
+    aDest.CopyFromOfn(aSrc);
+  }
+  inline static void Copy(LPOPENFILENAMEW& aDest, const OpenFileNameRetIPC& aSrc)
+  {
+    aSrc.AddToOfn(aDest);
+  }
+};
+
+template<>
+struct FileDlgEHContainer::EndpointHandler<SERVER> :
+  public BaseEndpointHandler<SERVER, FileDlgEHContainer::EndpointHandler<SERVER>>
+{
+  using BaseEndpointHandler<SERVER, EndpointHandler<SERVER>>::Copy;
+
+  inline static void Copy(OpenFileNameRetIPC& aDest, const LPOPENFILENAMEW& aSrc)
+  {
+    aDest.CopyFromOfn(aSrc);
+  }
+  inline static void Copy(ServerCallData* aScd, LPOPENFILENAMEW& aDest, const OpenFileNameIPC& aSrc)
+  {
+    MOZ_ASSERT(!aDest);
+    ServerCallData::DestructorType* destructor =
+      [](void* aObj) {
+      OpenFileNameIPC::FreeOfnStrings(static_cast<LPOPENFILENAMEW>(aObj));
+      DeleteDestructor<OPENFILENAMEW>(aObj);
+    };
+    aDest = aScd->Allocate<OPENFILENAMEW>(destructor);
+    aSrc.AllocateOfnStrings(aDest);
+    aSrc.AddToOfn(aDest);
+  }
+};
+
+// FunctionBroker type that uses FileDlgEHContainer
+template <FunctionHookId functionId, typename FunctionType>
+using FileDlgFunctionBroker = FunctionBroker<functionId, FunctionType, FileDlgEHContainer>;
+
+// Specialization of EndpointHandlers for Flash SSL brokering.
+struct SslEHContainer {
+  template<Endpoint e> struct EndpointHandler;
+};
+
+template<>
+struct SslEHContainer::EndpointHandler<CLIENT> :
+  public BaseEndpointHandler<CLIENT, SslEHContainer::EndpointHandler<CLIENT>>
+{
+  using BaseEndpointHandler<CLIENT, EndpointHandler<CLIENT>>::Copy;
+
+  inline static void Copy(uint64_t& aDest, const PSecHandle& aSrc)
+  {
+    MOZ_ASSERT((aSrc->dwLower == aSrc->dwUpper) && IsOdd(aSrc->dwLower));
+    aDest = static_cast<uint64_t>(aSrc->dwLower);
+  }
+  inline static void Copy(PSecHandle& aDest, const uint64_t& aSrc)
+  {
+    MOZ_ASSERT(IsOdd(aSrc));
+    aDest->dwLower = static_cast<ULONG_PTR>(aSrc);
+    aDest->dwUpper = static_cast<ULONG_PTR>(aSrc);
+  }
+  inline static void Copy(IPCSchannelCred& aDest, const PSCHANNEL_CRED& aSrc)
+  {
+    if (aSrc) {
+      aDest.CopyFrom(aSrc);
+    }
+  }
+  inline static void Copy(IPCInternetBuffers& aDest, const LPINTERNET_BUFFERSA& aSrc)
+  {
+    aDest.CopyFrom(aSrc);
+  }
+};
+
+template<>
+struct SslEHContainer::EndpointHandler<SERVER> :
+  public BaseEndpointHandler<SERVER, SslEHContainer::EndpointHandler<SERVER>>
+{
+  using BaseEndpointHandler<SERVER, EndpointHandler<SERVER>>::Copy;
+
+  // PSecHandle is the same thing as PCtxtHandle and PCredHandle.
+  inline static void Copy(uint64_t& aDest, const PSecHandle& aSrc)
+  {
+    // If the SecHandle was an error then don't store it.
+    if (!aSrc) {
+      aDest = 0;
+      return;
+    }
+
+    static uint64_t sNextVal = 1;
+    UlongPair key(aSrc->dwLower, aSrc->dwUpper);
+    // Fetch val by reference to update the value in the map
+    uint64_t& val = sPairToIdMap[key];
+    if (val == 0) {
+      MOZ_ASSERT(IsOdd(sNextVal));
+      val = sNextVal;
+      sIdToPairMap[val] = key;
+      sNextVal += 2;
+    }
+    aDest = val;
+  }
+
+  // HANDLEs and HINTERNETs marshal with obfuscation (for return values)
+  inline static void Copy(uint64_t& aDest, void* const & aSrc)
+  {
+    // If the HANDLE/HINTERNET was an error then don't store it.
+    if (!aSrc) {
+      aDest = 0;
+      return;
+    }
+
+    static uint64_t sNextVal = 1;
+    // Fetch val by reference to update the value in the map
+    uint64_t& val = sPtrToIdMap[aSrc];
+    if (val == 0) {
+      MOZ_ASSERT(IsOdd(sNextVal));
+      val = sNextVal;
+      sIdToPtrMap[val] = aSrc;
+      sNextVal += 2;
+    }
+    aDest = val;
+  }
+
+  // HANDLEs and HINTERNETs unmarshal with obfuscation
+  inline static void Copy(void*& aDest, const uint64_t& aSrc)
+  {
+    aDest = nullptr;
+    MOZ_RELEASE_ASSERT(IsOdd(aSrc));
+
+    // If the src is not found in the map then we get aDest == 0
+    void* ptr = sIdToPtrMap[aSrc];
+    aDest = reinterpret_cast<void*>(ptr);
+    MOZ_RELEASE_ASSERT(aDest);
+  }
+
+  inline static void Copy(PSCHANNEL_CRED& aDest, const IPCSchannelCred& aSrc)
+  {
+    if (aDest) {
+      aSrc.CopyTo(aDest);
+    }
+  }
+
+  inline static void Copy(ServerCallData* aScd, PSecHandle& aDest, const uint64_t& aSrc)
+  {
+    MOZ_ASSERT(!aDest);
+    MOZ_RELEASE_ASSERT(IsOdd(aSrc));
+
+    // If the src is not found in the map then we get the pair { 0, 0 }
+    aDest = aScd->Allocate<SecHandle>();
+    const UlongPair& pair = sIdToPairMap[aSrc];
+    MOZ_RELEASE_ASSERT(pair.first || pair.second);
+    aDest->dwLower = pair.first;
+    aDest->dwUpper = pair.second;
+  }
+
+  inline static void Copy(ServerCallData* aScd, PSCHANNEL_CRED& aDest, const IPCSchannelCred& aSrc)
+  {
+    MOZ_ASSERT(!aDest);
+    aDest = aScd->Allocate<SCHANNEL_CRED>();
+    Copy(aDest, aSrc);
+  }
+
+  inline static void Copy(ServerCallData* aScd, LPINTERNET_BUFFERSA& aDest, const IPCInternetBuffers& aSrc)
+  {
+    MOZ_ASSERT(!aDest);
+    aSrc.CopyTo(aDest);
+    ServerCallData::DestructorType* destructor =
+      [](void* aObj) {
+      LPINTERNET_BUFFERSA inetBuf = static_cast<LPINTERNET_BUFFERSA>(aObj);
+      IPCInternetBuffers::FreeBuffers(inetBuf);
+      FreeDestructor(inetBuf);
+    };
+    aScd->PostDestructor(aDest, destructor);
+  }
+};
+
+// FunctionBroker type that uses SslEHContainer
+template <FunctionHookId functionId, typename FunctionType>
+using SslFunctionBroker = FunctionBroker<functionId, FunctionType, SslEHContainer>;
+
 /* GetKeyState */
 
-typedef FunctionBroker<ID_GetKeyState,
-                       decltype(GetKeyState)> GetKeyStateFB;
+typedef FunctionBroker<ID_GetKeyState, decltype(GetKeyState)> GetKeyStateFB;
 
 template<>
 ShouldHookFunc* const
 GetKeyStateFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_GETKEYSTATE>;
 
 /* SetCursorPos */
 
 typedef FunctionBroker<ID_SetCursorPos,
                        decltype(SetCursorPos)> SetCursorPosFB;
 
 /* GetSaveFileNameW */
 
-typedef FunctionBroker<ID_GetSaveFileNameW,
-                             decltype(GetSaveFileNameW)> GetSaveFileNameWFB;
+typedef FileDlgFunctionBroker<ID_GetSaveFileNameW,
+                              decltype(GetSaveFileNameW)> GetSaveFileNameWFB;
 
 // Remember files granted access in the chrome process
 static void GrantFileAccess(base::ProcessId aClientId, LPOPENFILENAME& aLpofn,
                             bool isSave)
 {
 #if defined(MOZ_SANDBOX)
   if (aLpofn->Flags & OFN_ALLOWMULTISELECT) {
     // We only support multiselect with the OFN_EXPLORER flag.
@@ -105,18 +295,18 @@ BOOL GetSaveFileNameWFB::RunFunction(Get
   return result;
 }
 
 template<> template<>
 struct GetSaveFileNameWFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
 
 /* GetOpenFileNameW */
 
-typedef FunctionBroker<ID_GetOpenFileNameW,
-                       decltype(GetOpenFileNameW)> GetOpenFileNameWFB;
+typedef FileDlgFunctionBroker<ID_GetOpenFileNameW,
+                              decltype(GetOpenFileNameW)> GetOpenFileNameWFB;
 
 template<> template<>
 BOOL GetOpenFileNameWFB::RunFunction(GetOpenFileNameWFB::FunctionType* aOrigFunction,
                                     base::ProcessId aClientId,
                                     LPOPENFILENAMEW& aLpofn) const
 {
   BOOL result = aOrigFunction(aLpofn);
   if (result) {
@@ -126,27 +316,27 @@ BOOL GetOpenFileNameWFB::RunFunction(Get
   return result;
 }
 
 template<> template<>
 struct GetOpenFileNameWFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
 
 /* InternetOpenA */
 
-typedef FunctionBroker<ID_InternetOpenA,
-                       decltype(InternetOpenA)> InternetOpenAFB;
+typedef SslFunctionBroker<ID_InternetOpenA,
+                          decltype(InternetOpenA)> InternetOpenAFB;
 
 template<>
 ShouldHookFunc* const
 InternetOpenAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 /* InternetConnectA */
 
-typedef FunctionBroker<ID_InternetConnectA,
-                             decltype(InternetConnectA)> InternetConnectAFB;
+typedef SslFunctionBroker<ID_InternetConnectA,
+                          decltype(InternetConnectA)> InternetConnectAFB;
 
 template<>
 ShouldHookFunc* const
 InternetConnectAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef InternetConnectAFB::Request ICAReqHandler;
 
 template<>
@@ -156,18 +346,18 @@ bool ICAReqHandler::ShouldBroker(Endpoin
                                   const DWORD& svc, const DWORD& flags,
                                   const DWORD_PTR& cxt)
 {
   return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
 }
 
 /* InternetCloseHandle */
 
-typedef FunctionBroker<ID_InternetCloseHandle,
-                       decltype(InternetCloseHandle)> InternetCloseHandleFB;
+typedef SslFunctionBroker<ID_InternetCloseHandle,
+                          decltype(InternetCloseHandle)> InternetCloseHandleFB;
 
 template<>
 ShouldHookFunc* const
 InternetCloseHandleFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef InternetCloseHandleFB::Request ICHReqHandler;
 
 template<>
@@ -176,27 +366,25 @@ bool ICHReqHandler::ShouldBroker(Endpoin
   // If we are server side then we were already validated since we had to be
   // looked up in the "uint64_t <-> HINTERNET" hashtable.
   // In the client, we check that this is a dummy handle.
   return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
 }
 
 /* InternetQueryDataAvailable */
 
-typedef FunctionBroker<ID_InternetQueryDataAvailable,
-                       decltype(InternetQueryDataAvailable)> InternetQueryDataAvailableFB;
+typedef SslFunctionBroker<ID_InternetQueryDataAvailable,
+                          decltype(InternetQueryDataAvailable)> InternetQueryDataAvailableFB;
 
 template<>
 ShouldHookFunc* const
 InternetQueryDataAvailableFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef InternetQueryDataAvailableFB::Request IQDAReq;
-
-typedef struct RequestHandler<ID_InternetQueryDataAvailable,
-                              BOOL HOOK_CALL (HINTERNET)> IQDADelegateReq;
+typedef InternetQueryDataAvailableFB::RequestDelegate<BOOL HOOK_CALL (HINTERNET)> IQDADelegateReq;
 
 template<>
 void IQDAReq::Marshal(IpdlTuple& aTuple, const HINTERNET& file,
                       const LPDWORD& nBytes, const DWORD& flags,
                       const DWORD_PTR& cxt)
 {
   IQDADelegateReq::Marshal(aTuple, file);
 }
@@ -228,26 +416,25 @@ bool IQDAReq::ShouldBroker(Endpoint endp
           IsOdd(reinterpret_cast<uint64_t>(file)));
 }
 
 template<> template<>
 struct InternetQueryDataAvailableFB::Response::Info::ShouldMarshal<1> { static const bool value = true; };
 
 /* InternetReadFile */
 
-typedef FunctionBroker<ID_InternetReadFile,
-                       decltype(InternetReadFile)> InternetReadFileFB;
+typedef SslFunctionBroker<ID_InternetReadFile,
+                          decltype(InternetReadFile)> InternetReadFileFB;
 
 template<>
 ShouldHookFunc* const
 InternetReadFileFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef InternetReadFileFB::Request IRFRequestHandler;
-typedef struct RequestHandler<ID_InternetReadFile,
-                              BOOL HOOK_CALL (HINTERNET, DWORD)> IRFDelegateReq;
+typedef InternetReadFileFB::RequestDelegate<BOOL HOOK_CALL (HINTERNET, DWORD)> IRFDelegateReq;
 
 template<>
 void IRFRequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
                                 const LPVOID& buf, const DWORD& nBytesToRead,
                                 const LPDWORD& nBytesRead)
 {
   IRFDelegateReq::Marshal(aTuple, h, nBytesToRead);
 }
@@ -275,23 +462,22 @@ bool IRFRequestHandler::ShouldBroker(End
                                      const LPDWORD& nBytesRead)
 {
   // For server-side validation, the HINTERNET deserialization will have
   // required it to already be looked up in the IdToPtrMap.  At that point,
   // any call is valid.
   return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
 }
 
+typedef InternetReadFileFB::Response IRFResponseHandler;
+typedef InternetReadFileFB::ResponseDelegate<BOOL HOOK_CALL (nsDependentCSubstring)> IRFDelegateResponseHandler;
+
 // Marshal the output parameter that we sent to the response delegate.
 template<> template<>
-struct InternetReadFileFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
-
-typedef ResponseHandler<ID_InternetReadFile, decltype(InternetReadFile)> IRFResponseHandler;
-typedef ResponseHandler<ID_InternetReadFile,
-                               BOOL HOOK_CALL (nsDependentCSubstring)> IRFDelegateResponseHandler;
+struct IRFResponseHandler::Info::ShouldMarshal<0> { static const bool value = true; };
 
 template<>
 void IRFResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, const HINTERNET& h,
                                  const LPVOID& buf, const DWORD& nBytesToRead,
                                  const LPDWORD& nBytesRead)
 {
   nsDependentCSubstring str;
   if (*nBytesRead) {
@@ -316,26 +502,25 @@ bool IRFResponseHandler::Unmarshal(const
     memcpy(buf, str.Data(), str.Length());
     *nBytesRead = str.Length();
   }
   return true;
 }
 
 /* InternetWriteFile */
 
-typedef FunctionBroker<ID_InternetWriteFile,
-                       decltype(InternetWriteFile)> InternetWriteFileFB;
+typedef SslFunctionBroker<ID_InternetWriteFile,
+                          decltype(InternetWriteFile)> InternetWriteFileFB;
 
 template<>
 ShouldHookFunc* const
 InternetWriteFileFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef InternetWriteFileFB::Request IWFReqHandler;
-typedef RequestHandler<ID_InternetWriteFile,
-                       int HOOK_CALL (HINTERNET, nsDependentCSubstring)> IWFDelegateReqHandler;
+typedef InternetWriteFileFB::RequestDelegate<int HOOK_CALL (HINTERNET, nsDependentCSubstring)> IWFDelegateReqHandler;
 
 template<>
 void IWFReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& file, const LPCVOID& buf,
                             const DWORD& nToWrite, const LPDWORD& nWritten)
 {
   MOZ_ASSERT(nWritten);
   IWFDelegateReqHandler::Marshal(aTuple, file,
                                   nsDependentCSubstring(static_cast<const char*>(buf), nToWrite));
@@ -367,26 +552,25 @@ bool IWFReqHandler::ShouldBroker(Endpoin
   return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(file));
 }
 
 template<> template<>
 struct InternetWriteFileFB::Response::Info::ShouldMarshal<3> { static const bool value = true; };
 
 /* InternetSetOptionA */
 
-typedef FunctionBroker<ID_InternetSetOptionA,
-                       decltype(InternetSetOptionA)> InternetSetOptionAFB;
+typedef SslFunctionBroker<ID_InternetSetOptionA,
+                          decltype(InternetSetOptionA)> InternetSetOptionAFB;
 
 template<>
 ShouldHookFunc* const
 InternetSetOptionAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef InternetSetOptionAFB::Request ISOAReqHandler;
-typedef RequestHandler<ID_InternetSetOptionA,
-                       BOOL HOOK_CALL (HINTERNET, DWORD, nsDependentCSubstring)> ISOADelegateReqHandler;
+typedef InternetSetOptionAFB::RequestDelegate<BOOL HOOK_CALL (HINTERNET, DWORD, nsDependentCSubstring)> ISOADelegateReqHandler;
 
 template<>
 void ISOAReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h, const DWORD& opt,
                              const LPVOID& buf, const DWORD& bufLen)
 {
   ISOADelegateReqHandler::Marshal(aTuple, h, opt,
                                   nsDependentCSubstring(static_cast<const char*>(buf), bufLen));
 }
@@ -412,18 +596,18 @@ bool ISOAReqHandler::ShouldBroker(Endpoi
   // For server-side validation, the HINTERNET deserialization will have
   // required it to already be looked up in the IdToPtrMap.  At that point,
   // any call is valid.
   return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
 }
 
 /* HttpAddRequestHeadersA */
 
-typedef FunctionBroker<ID_HttpAddRequestHeadersA,
-                       decltype(HttpAddRequestHeadersA)> HttpAddRequestHeadersAFB;
+typedef SslFunctionBroker<ID_HttpAddRequestHeadersA,
+                          decltype(HttpAddRequestHeadersA)> HttpAddRequestHeadersAFB;
 
 template<>
 ShouldHookFunc* const
 HttpAddRequestHeadersAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef HttpAddRequestHeadersAFB::Request HARHAReqHandler;
 
 template<>
@@ -434,27 +618,25 @@ bool HARHAReqHandler::ShouldBroker(Endpo
   // For server-side validation, the HINTERNET deserialization will have
   // required it to already be looked up in the IdToPtrMap.  At that point,
   // any call is valid.
   return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
 }
 
 /* HttpOpenRequestA */
 
-typedef FunctionBroker<ID_HttpOpenRequestA,
-                       decltype(HttpOpenRequestA)> HttpOpenRequestAFB;
+typedef SslFunctionBroker<ID_HttpOpenRequestA,
+                          decltype(HttpOpenRequestA)> HttpOpenRequestAFB;
 
 template<>
 ShouldHookFunc* const
 HttpOpenRequestAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef HttpOpenRequestAFB::Request HORAReqHandler;
-typedef RequestHandler<ID_HttpOpenRequestA,
-                       HINTERNET HOOK_CALL (HINTERNET, LPCSTR, LPCSTR, LPCSTR, LPCSTR,
-                                            nsTArray<nsCString>, DWORD, DWORD_PTR)> HORADelegateReqHandler;
+typedef HttpOpenRequestAFB::RequestDelegate<HINTERNET HOOK_CALL (HINTERNET, LPCSTR, LPCSTR, LPCSTR, LPCSTR, nsTArray<nsCString>, DWORD, DWORD_PTR)> HORADelegateReqHandler;
 
 template<>
 void HORAReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
                              const LPCSTR& verb, const LPCSTR& obj,
                              const LPCSTR& ver, const LPCSTR& ref,
                              LPCSTR * const & acceptTypes, const DWORD& flags,
                              const DWORD_PTR& cxt)
 {
@@ -502,27 +684,25 @@ bool HORAReqHandler::ShouldBroker(Endpoi
   // For the server-side test, the HINTERNET deserialization will have
   // required it to already be looked up in the IdToPtrMap.  At that point,
   // any call is valid.
   return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
 }
 
 /* HttpQueryInfoA */
 
-typedef FunctionBroker<ID_HttpQueryInfoA,
-                       decltype(HttpQueryInfoA)> HttpQueryInfoAFB;
+typedef SslFunctionBroker<ID_HttpQueryInfoA,
+                          decltype(HttpQueryInfoA)> HttpQueryInfoAFB;
 
 template<>
 ShouldHookFunc* const
 HttpQueryInfoAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef HttpQueryInfoAFB::Request HQIARequestHandler;
-typedef RequestHandler<ID_HttpQueryInfoA,
-                       BOOL HOOK_CALL (HINTERNET, DWORD, BOOL, DWORD, BOOL,
-                                       DWORD)> HQIADelegateRequestHandler;
+typedef HttpQueryInfoAFB::RequestDelegate<BOOL HOOK_CALL (HINTERNET, DWORD, BOOL, DWORD, BOOL, DWORD)> HQIADelegateRequestHandler;
 
 template<>
 void HQIARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
                                  const DWORD& lvl, const LPVOID& buf, const LPDWORD& bufLen,
                                  const LPDWORD& idx)
 {
   HQIADelegateRequestHandler::Marshal(aTuple, h, lvl,
                                       bufLen != nullptr, bufLen ? *bufLen : 0,
@@ -567,19 +747,17 @@ bool HQIARequestHandler::ShouldBroker(En
 template<> template<>
 struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
 template<> template<>
 struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<1> { static const bool value = true; };
 template<> template<>
 struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<2> { static const bool value = true; };
 
 typedef HttpQueryInfoAFB::Response HQIAResponseHandler;
-typedef ResponseHandler<ID_HttpQueryInfoA,
-                        BOOL HOOK_CALL (nsDependentCSubstring,
-                                        DWORD, DWORD)> HQIADelegateResponseHandler;
+typedef HttpQueryInfoAFB::ResponseDelegate<BOOL HOOK_CALL (nsDependentCSubstring, DWORD, DWORD)> HQIADelegateResponseHandler;
 
 template<>
 void HQIAResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, const HINTERNET& h,
                                  const DWORD& lvl, const LPVOID& buf, const LPDWORD& bufLen,
                                  const LPDWORD& idx)
 {
   nsDependentCSubstring str;
   if (buf && ret) {
@@ -626,27 +804,25 @@ bool HQIAResponseHandler::Unmarshal(cons
       cbuf[str.Length()] = '\0';
     }
   }
   return true;
 }
 
 /* HttpSendRequestA */
 
-typedef FunctionBroker<ID_HttpSendRequestA,
-                       decltype(HttpSendRequestA)> HttpSendRequestAFB;
+typedef SslFunctionBroker<ID_HttpSendRequestA,
+                          decltype(HttpSendRequestA)> HttpSendRequestAFB;
 
 template<>
 ShouldHookFunc* const
 HttpSendRequestAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef HttpSendRequestAFB::Request HSRARequestHandler;
-typedef RequestHandler<ID_HttpSendRequestA,
-                       BOOL HOOK_CALL (HINTERNET, nsDependentCSubstring,
-                                       nsDependentCSubstring)> HSRADelegateRequestHandler;
+typedef HttpSendRequestAFB::RequestDelegate<BOOL HOOK_CALL (HINTERNET, nsDependentCSubstring, nsDependentCSubstring)> HSRADelegateRequestHandler;
 
 template<>
 void HSRARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
                                  const LPCSTR& head, const DWORD& headLen,
                                  const LPVOID& opt, const DWORD& optLen)
 {
   nsDependentCSubstring headStr;
   headStr.SetIsVoid(head == nullptr);
@@ -704,18 +880,18 @@ bool HSRARequestHandler::ShouldBroker(En
   // If we are server side then we were already validated since we had to be
   // looked up in the "uint64_t <-> HINTERNET" hashtable.
   // In the client, we check that this is a dummy handle.
   return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
 }
 
 /* HttpSendRequestExA */
 
-typedef FunctionBroker<ID_HttpSendRequestExA,
-                       decltype(HttpSendRequestExA)> HttpSendRequestExAFB;
+typedef SslFunctionBroker<ID_HttpSendRequestExA,
+                          decltype(HttpSendRequestExA)> HttpSendRequestExAFB;
 
 template<>
 ShouldHookFunc* const
 HttpSendRequestExAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef RequestInfo<ID_HttpSendRequestExA> HSRExAReqInfo;
 
 template<> template<>
@@ -728,26 +904,25 @@ const LPINTERNET_BUFFERSA HSRExAReqInfo:
 // struct HSRExAReqInfo::FixedValue<3> { static const DWORD value = 0; };
 
 template<> template<>
 struct HSRExAReqInfo::FixedValue<4> { static const DWORD_PTR value; };
 const DWORD_PTR HSRExAReqInfo::FixedValue<4>::value = 0;
 
 /* InternetQueryOptionA */
 
-typedef FunctionBroker<ID_InternetQueryOptionA,
-                       decltype(InternetQueryOptionA)> InternetQueryOptionAFB;
+typedef SslFunctionBroker<ID_InternetQueryOptionA,
+                          decltype(InternetQueryOptionA)> InternetQueryOptionAFB;
 
 template<>
 ShouldHookFunc* const
 InternetQueryOptionAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef InternetQueryOptionAFB::Request IQOARequestHandler;
-typedef RequestHandler<ID_InternetQueryOptionA,
-                       BOOL HOOK_CALL (HINTERNET, DWORD, DWORD)> IQOADelegateRequestHandler;
+typedef InternetQueryOptionAFB::RequestDelegate<BOOL HOOK_CALL (HINTERNET, DWORD, DWORD)> IQOADelegateRequestHandler;
 
 template<>
 void IQOARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
                                  const DWORD& opt, const LPVOID& buf, const LPDWORD& bufLen)
 {
   MOZ_ASSERT(bufLen);
   IQOADelegateRequestHandler::Marshal(aTuple, h, opt, buf ? *bufLen : 0);
 }
@@ -780,18 +955,17 @@ bool IQOARequestHandler::ShouldBroker(En
 
 // Marshal all of the output parameters that we sent to the response delegate.
 template<> template<>
 struct InternetQueryOptionAFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
 template<> template<>
 struct InternetQueryOptionAFB::Response::Info::ShouldMarshal<1> { static const bool value = true; };
 
 typedef InternetQueryOptionAFB::Response IQOAResponseHandler;
-typedef ResponseHandler<ID_InternetQueryOptionA,
-                        BOOL HOOK_CALL (nsDependentCSubstring, DWORD)> IQOADelegateResponseHandler;
+typedef InternetQueryOptionAFB::ResponseDelegate<BOOL HOOK_CALL (nsDependentCSubstring, DWORD)> IQOADelegateResponseHandler;
 
 template<>
 void IQOAResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, const HINTERNET& h,
                                   const DWORD& opt, const LPVOID& buf, const LPDWORD& bufLen)
 {
   nsDependentCSubstring str;
   if (buf && ret) {
     MOZ_ASSERT(*bufLen);
@@ -815,18 +989,18 @@ bool IQOAResponseHandler::Unmarshal(cons
     MOZ_ASSERT(str.Length() == *bufLen);
     memcpy(buf, str.Data(), str.Length());
   }
   return true;
 }
 
 /* InternetErrorDlg */
 
-typedef FunctionBroker<ID_InternetErrorDlg,
-                       decltype(InternetErrorDlg)> InternetErrorDlgFB;
+typedef SslFunctionBroker<ID_InternetErrorDlg,
+                          decltype(InternetErrorDlg)> InternetErrorDlgFB;
 
 template<>
 ShouldHookFunc* const
 InternetErrorDlgFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef RequestInfo<ID_InternetErrorDlg> IEDReqInfo;
 
 template<> template<>
@@ -848,18 +1022,18 @@ bool IEDReqHandler::ShouldBroker(Endpoin
   // (2) we support the requested action flags and (3) there is no user
   // data, which wouldn't make sense for our supported flags anyway.
   return ((endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h))) &&
          (!(flags & ~SUPPORTED_FLAGS)) && (data == nullptr);
 }
 
 /* AcquireCredentialsHandleA */
 
-typedef FunctionBroker<ID_AcquireCredentialsHandleA,
-                       decltype(AcquireCredentialsHandleA)> AcquireCredentialsHandleAFB;
+typedef SslFunctionBroker<ID_AcquireCredentialsHandleA,
+                          decltype(AcquireCredentialsHandleA)> AcquireCredentialsHandleAFB;
 
 template<>
 ShouldHookFunc* const
 AcquireCredentialsHandleAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef RequestInfo<ID_AcquireCredentialsHandleA> ACHAReqInfo;
 
 template<> template<>
@@ -882,20 +1056,17 @@ template<> template<>
 struct ACHAReqInfo::FixedValue<5> { static const SEC_GET_KEY_FN value; };
 const SEC_GET_KEY_FN ACHAReqInfo::FixedValue<5>::value = nullptr;
 
 template<> template<>
 struct ACHAReqInfo::FixedValue<6> { static void* const value; };
 void* const ACHAReqInfo::FixedValue<6>::value = nullptr;
 
 typedef AcquireCredentialsHandleAFB::Request ACHARequestHandler;
-typedef RequestHandler<ID_AcquireCredentialsHandleA,
-                       SECURITY_STATUS HOOK_CALL (LPSTR, LPSTR, unsigned long,
-                                       void*, PSCHANNEL_CRED, SEC_GET_KEY_FN,
-                                       void*)> ACHADelegateRequestHandler;
+typedef AcquireCredentialsHandleAFB::RequestDelegate<SECURITY_STATUS HOOK_CALL (LPSTR, LPSTR, unsigned long, void*, PSCHANNEL_CRED, SEC_GET_KEY_FN, void*)> ACHADelegateRequestHandler;
 
 template<>
 void ACHARequestHandler::Marshal(IpdlTuple& aTuple, const LPSTR& principal,
                                  const LPSTR& pkg, const unsigned long& credUse,
                                  const PVOID& logonId, const PVOID& auth,
                                  const SEC_GET_KEY_FN& getKeyFn,
                                  const PVOID& getKeyArg, const PCredHandle& cred,
                                  const PTimeStamp& expiry)
@@ -927,27 +1098,27 @@ typedef ResponseInfo<ID_AcquireCredentia
 // Response phase must send output parameters
 template<> template<>
 struct ACHARspInfo::ShouldMarshal<7> { static const bool value = true; };
 template<> template<>
 struct ACHARspInfo::ShouldMarshal<8> { static const bool value = true; };
 
 /* QueryCredentialsAttributesA */
 
-typedef FunctionBroker<ID_QueryCredentialsAttributesA,
-                       decltype(QueryCredentialsAttributesA)> QueryCredentialsAttributesAFB;
+typedef SslFunctionBroker<ID_QueryCredentialsAttributesA,
+                          decltype(QueryCredentialsAttributesA)> QueryCredentialsAttributesAFB;
 
 template<>
 ShouldHookFunc* const
 QueryCredentialsAttributesAFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 /* FreeCredentialsHandle */
 
-typedef FunctionBroker<ID_FreeCredentialsHandle,
-                       decltype(FreeCredentialsHandle)> FreeCredentialsHandleFB;
+typedef SslFunctionBroker<ID_FreeCredentialsHandle,
+                          decltype(FreeCredentialsHandle)> FreeCredentialsHandleFB;
 
 template<>
 ShouldHookFunc* const
 FreeCredentialsHandleFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_SSL>;
 
 typedef FreeCredentialsHandleFB::Request FCHReq;
 
 template<>
@@ -955,16 +1126,138 @@ bool FCHReq::ShouldBroker(Endpoint endpo
 {
   // If we are server side then we were already validated since we had to be
   // looked up in the "uint64_t <-> CredHandle" hashtable.
   // In the client, we check that this is a dummy handle.
   return (endpoint == SERVER) ||
          ((h->dwLower == h->dwUpper) && IsOdd(static_cast<uint64_t>(h->dwLower)));
 }
 
+/* CreateMutexW */
+
+// Get the user's SID as a string.  Returns an empty string on failure.
+static std::wstring GetUserSid()
+{
+  std::wstring ret;
+  // Get user SID from process token information
+  HANDLE token;
+  BOOL success = ::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token);
+  if (!success) {
+    return ret;
+  }
+  DWORD bufLen;
+  success = ::GetTokenInformation(token, TokenUser, nullptr, 0, &bufLen);
+  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    return ret;
+  }
+  void* buf = malloc(bufLen);
+  success = ::GetTokenInformation(token, TokenUser, buf, bufLen, &bufLen);
+  MOZ_ASSERT(success);
+  if (success) {
+    TOKEN_USER* tokenUser = static_cast<TOKEN_USER*>(buf);
+    PSID sid = tokenUser->User.Sid;
+    LPWSTR sidStr;
+    success = ::ConvertSidToStringSid(sid, &sidStr);
+    if (success) {
+      ret = sidStr;
+      ::LocalFree(sidStr);
+    }
+  }
+  free(buf);
+  ::CloseHandle(token);
+  return ret;
+}
+
+// Get the name Windows uses for the camera mutex.  Returns an empty string
+// on failure.
+// The camera mutex is identified in Windows code using a hard-coded GUID string,
+// "eed3bd3a-a1ad-4e99-987b-d7cb3fcfa7f0", and the user's SID.  The GUID
+// value was determined by investigating Windows code.  It is referenced in
+// CCreateSwEnum::CCreateSwEnum(void) in devenum.dll.
+static std::wstring GetCameraMutexName()
+{
+  std::wstring userSid = GetUserSid();
+  if (userSid.empty()) {
+    return userSid;
+  }
+  return std::wstring(L"eed3bd3a-a1ad-4e99-987b-d7cb3fcfa7f0 - ") + userSid;
+}
+
+typedef FunctionBroker<ID_CreateMutexW, decltype(CreateMutexW)> CreateMutexWFB;
+
+template<>
+ShouldHookFunc* const
+CreateMutexWFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_CREATEMUTEXW>;
+
+typedef CreateMutexWFB::Request CMWReqHandler;
+typedef CMWReqHandler::Info CMWReqInfo;
+typedef CreateMutexWFB::Response CMWRspHandler;
+
+template<>
+bool CMWReqHandler::ShouldBroker(Endpoint endpoint,
+                                 const LPSECURITY_ATTRIBUTES& aAttribs,
+                                 const BOOL& aOwner,
+                                 const LPCWSTR& aName)
+{
+  // Statically hold the camera mutex name so that we dont recompute it for
+  // every CreateMutexW call in the client process.
+  static std::wstring camMutexName = GetCameraMutexName();
+
+  // Only broker if we are requesting the camera mutex.  Note that we only
+  // need to check that the client is actually requesting the camera.  The
+  // command is always valid on the server as long as we can construct the
+  // mutex name.
+  if (endpoint == SERVER) {
+    return !camMutexName.empty();
+  }
+
+  return (!aOwner) && aName && (!camMutexName.empty()) && (camMutexName == aName);
+}
+
+// We dont need to marshal any parameters.  We construct all of them server-side.
+template<> template<>
+struct CMWReqInfo::ShouldMarshal<0> { static const bool value = false; };
+template<> template<>
+struct CMWReqInfo::ShouldMarshal<1> { static const bool value = false; };
+template<> template<>
+struct CMWReqInfo::ShouldMarshal<2> { static const bool value = false; };
+
+template<> template<>
+HANDLE CreateMutexWFB::RunFunction(CreateMutexWFB::FunctionType* aOrigFunction,
+                                   base::ProcessId aClientId,
+                                   LPSECURITY_ATTRIBUTES& aAttribs,
+                                   BOOL& aOwner,
+                                   LPCWSTR& aName) const
+{
+  // Use CreateMutexW to get the camera mutex and DuplicateHandle to open it
+  // for use in the child process.
+  // Recall that aAttribs, aOwner and aName are all unmarshaled so they are
+  // unassigned garbage.
+  SECURITY_ATTRIBUTES mutexAttrib =
+    { sizeof(SECURITY_ATTRIBUTES), nullptr /* ignored */, TRUE };
+  std::wstring camMutexName = GetCameraMutexName();
+  if (camMutexName.empty()) {
+    return 0;
+  }
+  HANDLE serverMutex = ::CreateMutexW(&mutexAttrib, FALSE, camMutexName.c_str());
+  if (serverMutex == 0) {
+    return 0;
+  }
+  ScopedProcessHandle clientProcHandle;
+  if (!base::OpenProcessHandle(aClientId, &clientProcHandle.rwget())) {
+    return 0;
+  }
+  HANDLE ret;
+  if (!::DuplicateHandle(::GetCurrentProcess(), serverMutex, clientProcHandle,
+                         &ret, SYNCHRONIZE, FALSE, DUPLICATE_CLOSE_SOURCE)) {
+    return 0;
+  }
+  return ret;
+}
+
 #endif // defined(XP_WIN)
 
 /*****************************************************************************/
 
 #define FUN_HOOK(x) static_cast<FunctionHook*>(x)
 void
 AddBrokeredFunctionHooks(FunctionHookArray& aHooks)
 {
@@ -1030,15 +1323,17 @@ AddBrokeredFunctionHooks(FunctionHookArr
   aHooks[ID_QueryCredentialsAttributesA] =
     FUN_HOOK(new QueryCredentialsAttributesAFB("sspicli.dll",
                                                "QueryCredentialsAttributesA",
                                                &QueryCredentialsAttributesA));
   aHooks[ID_FreeCredentialsHandle] =
     FUN_HOOK(new FreeCredentialsHandleFB("sspicli.dll",
                                          "FreeCredentialsHandle",
                                          &FreeCredentialsHandle));
+  aHooks[ID_CreateMutexW] =
+    FUN_HOOK(new CreateMutexWFB("kernel32.dll", "CreateMutexW", &CreateMutexW));
 #endif // defined(XP_WIN)
 }
 
 #undef FUN_HOOK
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/ipc/FunctionBroker.h
+++ b/dom/plugins/ipc/FunctionBroker.h
@@ -90,17 +90,20 @@
  * The IPCTypeMap in FunctionBroker maps a parameter or return type
  * to a type that IpdlTuple knows how to marshal.  By default, the map is
  * the identity but some types need special handling.
  * The map is endpoint-specific (it is a member of the EndpointHandler),
  * so a different type can be used
  * for client -> server and for server -> client.  Note that the
  * types must be able to Copy() from one another -- the default Copy()
  * implementation uses the type's assignment operator.
- * See e.g. EndpointHandler<CLIENT>::IPCTypeMap<LPOPENFILENAMEW>.
+ * The EndpointHandler itself is a template parameter of the FunctionBroker.
+ * The default EndpointHandler recognizes basic types.
+ * See e.g. FileDlgEndpointHandler<CLIENT>::IPCTypeMap<LPOPENFILENAMEW>
+ * for an example of specialization.
  *
  * * Anything more complex involving parameter transmission:
  *
  * Sometimes marshaling parameters can require something more complex.  In
  * those cases, you will need to specialize the Marshal and Unmarshal
  * methods of the request or response handler and perform your complex logic
  * there.  A wise approach is to map your complex parameters into a simpler
  * parameter list and delegate the Marshal/Unmarshal calls to them.  For
@@ -451,342 +454,158 @@ inline void Copy(uint64_t& aDest, const 
 template<>
 inline void Copy(PTimeStamp& aDest, const uint64_t& aSrc)
 {
   aDest->QuadPart = static_cast<LONGLONG>(aSrc);
 }
 
 #endif // defined(XP_WIN)
 
-template<Endpoint e> struct EndpointHandler;
-template<> struct EndpointHandler<CLIENT> {
+template<Endpoint e, typename SelfType> struct BaseEndpointHandler;
+template<typename SelfType>
+struct BaseEndpointHandler<CLIENT,SelfType> {
   static const Endpoint OtherSide = SERVER;
 
   template<typename DestType, typename SrcType>
   inline static void Copy(ServerCallData* aScd, DestType& aDest, const SrcType& aSrc)
   {
     MOZ_ASSERT(!aScd);    // never used in the CLIENT
-    Copy(aDest, aSrc);
+    SelfType::Copy(aDest, aSrc);
   }
 
   template<typename DestType, typename SrcType>
   inline static void Copy(DestType& aDest, const SrcType& aSrc)
   {
     mozilla::plugins::Copy(aDest, aSrc);
   }
-};
+
+  // const char* should be null terminated but this is not always the case.
+  // In those cases, we must override this default behavior.
+  inline static void Copy(nsDependentCSubstring& aDest, const char* const& aSrc)
+  {
+    // In the client, we just bind to the caller's string
+    if (aSrc) {
+      aDest.Rebind(aSrc, strlen(aSrc));
+    } else {
+      aDest.SetIsVoid(true);
+    }
+  }
+
+  inline static void Copy(const char*& aDest, const nsDependentCSubstring& aSrc)
+  {
+    MOZ_ASSERT_UNREACHABLE("Cannot return const parameters.");
+  }
+
+  inline static void Copy(nsDependentCSubstring& aDest, char* const& aSrc)
+  {
+    // In the client, we just bind to the caller's string
+    if (aSrc) {
+      aDest.Rebind(aSrc, strlen(aSrc));
+    } else {
+      aDest.SetIsVoid(true);
+    }
+  }
+
+  inline static void Copy(char*& aDest, const nsDependentCSubstring& aSrc)
+  {
+    MOZ_ASSERT_UNREACHABLE("Returning char* parameters is not yet suported.");
+  }
 
 #if defined(XP_WIN)
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(uint64_t& aDest, const PSecHandle& aSrc)
-{
-  MOZ_ASSERT((aSrc->dwLower == aSrc->dwUpper) && IsOdd(aSrc->dwLower));
-  aDest = static_cast<uint64_t>(aSrc->dwLower);
-}
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(PSecHandle& aDest, const uint64_t& aSrc)
-{
-  MOZ_ASSERT(IsOdd(aSrc));
-  aDest->dwLower = static_cast<ULONG_PTR>(aSrc);
-  aDest->dwUpper = static_cast<ULONG_PTR>(aSrc);
-}
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(OpenFileNameIPC& aDest, const LPOPENFILENAMEW& aSrc)
-{
-  aDest.CopyFromOfn(aSrc);
-}
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(LPOPENFILENAMEW& aDest, const OpenFileNameRetIPC& aSrc)
-{
-  aSrc.AddToOfn(aDest);
-}
-
-#endif // defined(XP_WIN)
-
-// const char* should be null terminated but this is not always the case.
-// In those cases, we must override this default behavior.
-template<>
-inline void EndpointHandler<CLIENT>::Copy(nsDependentCSubstring& aDest, const char* const& aSrc)
-{
-  // In the client, we just bind to the caller's string
-  if (aSrc) {
-    aDest.Rebind(aSrc, strlen(aSrc));
-  } else {
-    aDest.SetIsVoid(true);
+  inline static void Copy(uint32_t& aDest, const LPDWORD& aSrc)
+  {
+    aDest = *aSrc;
   }
-}
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(const char*& aDest, const nsDependentCSubstring& aSrc)
-{
-  MOZ_ASSERT_UNREACHABLE("Cannot return const parameters.");
-}
 
-template<>
-inline void EndpointHandler<CLIENT>::Copy(nsDependentCSubstring& aDest, char* const& aSrc)
-{
-  // In the client, we just bind to the caller's string
-  if (aSrc) {
-    aDest.Rebind(aSrc, strlen(aSrc));
-  } else {
-    aDest.SetIsVoid(true);
+  inline static void Copy(LPDWORD& aDest, const uint32_t& aSrc)
+  {
+    *aDest = aSrc;
   }
-}
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(char*& aDest,
-                                          const nsDependentCSubstring& aSrc)
-{
-  MOZ_ASSERT_UNREACHABLE("Returning char* parameters is not yet suported.");
-}
-
-#if defined(XP_WIN)
+#endif // #if defined(XP_WIN)
+};
 
-template<>
-inline void EndpointHandler<CLIENT>::Copy(IPCSchannelCred& aDest,
-                                          const PSCHANNEL_CRED& aSrc)
-{
-  if (aSrc) {
-    aDest.CopyFrom(aSrc);
-  }
-}
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(IPCInternetBuffers& aDest,
-                                          const LPINTERNET_BUFFERSA& aSrc)
-{
-  aDest.CopyFrom(aSrc);
-}
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(uint32_t& aDest, const LPDWORD& aSrc)
-{
-  aDest = *aSrc;
-}
-
-template<>
-inline void EndpointHandler<CLIENT>::Copy(LPDWORD& aDest, const uint32_t& aSrc)
-{
-  *aDest = aSrc;
-}
-
-#endif // #if defined(XP_WIN)
-
-template<> struct EndpointHandler<SERVER> {
+template<typename SelfType>
+struct BaseEndpointHandler<SERVER, SelfType> {
   static const Endpoint OtherSide = CLIENT;
 
   // Specializations of this method may allocate memory for types that need it
   // during Unmarshaling.  They record the allocation in the ServerCallData.
   // When copying values in the SERVER, we should be sure to carefully validate
   // the information that came from the client as the client may be compromised
   // by malicious code.
   template<typename DestType, typename SrcType>
   inline static void Copy(ServerCallData* aScd, DestType& aDest, const SrcType& aSrc)
   {
-    Copy(aDest, aSrc);
+    SelfType::Copy(aDest, aSrc);
   }
 
   template<typename DestType, typename SrcType>
   inline static void Copy(DestType& aDest, const SrcType& aSrc)
   {
     mozilla::plugins::Copy(aDest, aSrc);
   }
-};
 
-template<>
-inline void EndpointHandler<SERVER>::Copy(nsDependentCSubstring& aDest, const nsDependentCSubstring& aSrc)
-{
-  aDest.Rebind(aSrc.Data(), aSrc.Length());
-  aDest.SetIsVoid(aSrc.IsVoid());
-}
-
-// const char* should be null terminated but this is not always the case.
-// In those cases, we override this default behavior.
-template<>
-inline void EndpointHandler<SERVER>::Copy(nsDependentCSubstring& aDest, const char* const& aSrc)
-{
-  MOZ_ASSERT_UNREACHABLE("Const parameter cannot be returned by brokering process.");
-}
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(nsDependentCSubstring& aDest, char* const& aSrc)
-{
-  MOZ_ASSERT_UNREACHABLE("Returning char* parameters is not yet suported.");
-}
-
-#if defined(XP_WIN)
+  inline static void Copy(nsDependentCSubstring& aDest, const nsDependentCSubstring& aSrc)
+  {
+    aDest.Rebind(aSrc.Data(), aSrc.Length());
+    aDest.SetIsVoid(aSrc.IsVoid());
+  }
 
-// PSecHandle is the same thing as PCtxtHandle and PCredHandle
-template<>
-inline void EndpointHandler<SERVER>::Copy(uint64_t& aDest, const PSecHandle& aSrc)
-{
-  static uint64_t sNextVal = 1;
-  UlongPair key(aSrc->dwLower, aSrc->dwUpper);
-  // Fetch val by reference to update the value in the map
-  uint64_t& val = sPairToIdMap[key];
-  if (val == 0) {
-    MOZ_ASSERT(IsOdd(sNextVal));
-    val = sNextVal;
-    sIdToPairMap[val] = key;
-    sNextVal += 2;
+  // const char* should be null terminated but this is not always the case.
+  // In those cases, we override this default behavior.
+  inline static void Copy(nsDependentCSubstring& aDest, const char* const& aSrc)
+  {
+    MOZ_ASSERT_UNREACHABLE("Const parameter cannot be returned by brokering process.");
   }
-  aDest = val;
-}
 
-// HANDLEs and HINTERNETs marshal (for return values)
-template<>
-inline void EndpointHandler<SERVER>::Copy(uint64_t& aDest, void* const & aSrc)
-{
-  // If the HANDLE/HINSTANCE was an error then don't store it.
-  if (!aSrc) {
-    aDest = 0;
-    return;
+  inline static void Copy(nsDependentCSubstring& aDest, char* const& aSrc)
+  {
+    MOZ_ASSERT_UNREACHABLE("Returning char* parameters is not yet suported.");
   }
 
-  static uint64_t sNextVal = 1;
-  // Fetch val by reference to update the value in the map
-  uint64_t& val = sPtrToIdMap[aSrc];
-  if (val == 0) {
-    MOZ_ASSERT(IsOdd(sNextVal));
-    val = sNextVal;
-    sIdToPtrMap[val] = aSrc;
-    sNextVal += 2;
-  }
-  aDest = val;
-}
-
-// HANDLEs and HINTERNETs unmarshal
-template<>
-inline void EndpointHandler<SERVER>::Copy(void*& aDest, const uint64_t& aSrc)
-{
-  aDest = nullptr;
-  MOZ_RELEASE_ASSERT(IsOdd(aSrc));
-
-  // If the src is not found in the map then we get aDest == 0
-  void* ptr = sIdToPtrMap[aSrc];
-  aDest = reinterpret_cast<void*>(ptr);
-  MOZ_RELEASE_ASSERT(aDest);
-}
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(OpenFileNameRetIPC& aDest, const LPOPENFILENAMEW& aSrc)
-{
-  aDest.CopyFromOfn(aSrc);
-}
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(PSCHANNEL_CRED& aDest, const IPCSchannelCred& aSrc)
-{
-  if (aDest) {
-    aSrc.CopyTo(aDest);
+  inline static void Copy(ServerCallData* aScd, char*& aDest, const nsDependentCSubstring& aSrc)
+  {
+    // In the parent, we must allocate the string.
+    MOZ_ASSERT(aScd);
+    if (aSrc.IsVoid()) {
+      aDest = nullptr;
+      return;
+    }
+    aScd->AllocateMemory(aSrc.Length() + 1, aDest);
+    memcpy(aDest, aSrc.Data(), aSrc.Length());
+    aDest[aSrc.Length()] = '\0';
   }
-}
 
-template<>
-inline void EndpointHandler<SERVER>::Copy(uint32_t& aDest, const LPDWORD& aSrc)
-{
-  aDest = *aSrc;
-}
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(LPDWORD& aDest, const uint32_t& aSrc)
-{
-  MOZ_RELEASE_ASSERT(aDest);
-  *aDest = aSrc;
-}
-
-#endif // defined(XP_WIN)
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(ServerCallData* aScd, char*& aDest, const nsDependentCSubstring& aSrc)
-{
-  // In the parent, we must allocate the string.
-  MOZ_ASSERT(aScd);
-  if (aSrc.IsVoid()) {
-    aDest = nullptr;
-    return;
+  inline static void Copy(ServerCallData* aScd, const char*& aDest, const nsDependentCSubstring& aSrc)
+  {
+    char* nonConstDest;
+    Copy(aScd, nonConstDest, aSrc);
+    aDest = nonConstDest;
   }
-  aScd->AllocateMemory(aSrc.Length() + 1, aDest);
-  memcpy(aDest, aSrc.Data(), aSrc.Length());
-  aDest[aSrc.Length()] = '\0';
-}
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(ServerCallData* aScd, const char*& aDest, const nsDependentCSubstring& aSrc)
-{
-  char* nonConstDest;
-  Copy(aScd, nonConstDest, aSrc);
-  aDest = nonConstDest;
-}
 
 #if defined(XP_WIN)
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(ServerCallData* aScd, PSecHandle& aDest, const uint64_t& aSrc)
-{
-  MOZ_ASSERT(!aDest);
-  MOZ_RELEASE_ASSERT(IsOdd(aSrc));
-
-  // If the src is not found in the map then we get the pair { 0, 0 }
-  aDest = aScd->Allocate<SecHandle>();
-  const UlongPair& pair = sIdToPairMap[aSrc];
-  MOZ_RELEASE_ASSERT(pair.first || pair.second);
-  aDest->dwLower = pair.first;
-  aDest->dwUpper = pair.second;
-}
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(ServerCallData* aScd, PTimeStamp& aDest, const uint64_t& aSrc)
-{
-  MOZ_ASSERT(!aDest);
-  aDest = aScd->Allocate<::TimeStamp>();
-  Copy(aDest, aSrc);
-}
+  inline static void Copy(uint32_t& aDest, const LPDWORD& aSrc)
+  {
+    aDest = *aSrc;
+  }
 
-template<>
-inline void EndpointHandler<SERVER>::Copy(ServerCallData* aScd, LPOPENFILENAMEW& aDest, const OpenFileNameIPC& aSrc)
-{
-  MOZ_ASSERT(!aDest);
-  ServerCallData::DestructorType* destructor =
-    [](void* aObj) {
-      OpenFileNameIPC::FreeOfnStrings(static_cast<LPOPENFILENAMEW>(aObj));
-      DeleteDestructor<OPENFILENAMEW>(aObj);
-    };
-  aDest = aScd->Allocate<OPENFILENAMEW>(destructor);
-  aSrc.AllocateOfnStrings(aDest);
-  aSrc.AddToOfn(aDest);
-}
+  inline static void Copy(LPDWORD& aDest, const uint32_t& aSrc)
+  {
+    MOZ_RELEASE_ASSERT(aDest);
+    *aDest = aSrc;
+  }
 
-template<>
-inline void EndpointHandler<SERVER>::Copy(ServerCallData* aScd, PSCHANNEL_CRED& aDest, const IPCSchannelCred& aSrc)
-{
-  MOZ_ASSERT(!aDest);
-  aDest = aScd->Allocate<SCHANNEL_CRED>();
-  Copy(aDest, aSrc);
-}
-
-template<>
-inline void EndpointHandler<SERVER>::Copy(ServerCallData* aScd, LPINTERNET_BUFFERSA& aDest, const IPCInternetBuffers& aSrc)
-{
-  MOZ_ASSERT(!aDest);
-  aSrc.CopyTo(aDest);
-  ServerCallData::DestructorType* destructor =
-    [](void* aObj) {
-      LPINTERNET_BUFFERSA inetBuf = static_cast<LPINTERNET_BUFFERSA>(aObj);
-      IPCInternetBuffers::FreeBuffers(inetBuf);
-      FreeDestructor(inetBuf);
-    };
-  aScd->PostDestructor(aDest, destructor);
-}
-
+  inline static void Copy(ServerCallData* aScd, PTimeStamp& aDest, const uint64_t& aSrc)
+  {
+    MOZ_ASSERT(!aDest);
+    aDest = aScd->Allocate<::TimeStamp>();
+    Copy(aDest, aSrc);
+  }
 #endif // defined(XP_WIN)
+};
 
 // PhaseHandler is a RequestHandler or a ResponseHandler.
 template<Endpoint endpoint, typename PhaseHandler>
 struct Marshaler
 {
   // Driver
   template<int firstIndex = 0, typename ... VarParams>
   static void Marshal(IpdlTuple& aMarshaledTuple,
@@ -813,17 +632,18 @@ struct Marshaler
   struct MaybeMarshalParameter<paramIndex, OrigType, true>
   {
     template<typename IPCType = typename PhaseHandler::template IPCTypeMap<OrigType>::ipc_type>
     static void MarshalParameter(IpdlTuple& aMarshaledTuple, const OrigType& aParam)
     {
       HOOK_LOG(LogLevel::Verbose,
                ("%s marshaling parameter %d.", EndpointMsg(endpoint), paramIndex));
       IPCType ipcObject;
-      EndpointHandler<endpoint>::Copy(ipcObject, aParam);  // Must be able to Copy() from OrigType to IPCType
+      // EndpointHandler must be able to Copy() from OrigType to IPCType
+      PhaseHandler::EHContainer::template EndpointHandler<endpoint>::Copy(ipcObject, aParam);
       LogParameterValue(paramIndex, ipcObject);
       aMarshaledTuple.AddElement(ipcObject);
     }
   };
 
   /**
    * shouldMarshal = false case
    */
@@ -876,17 +696,17 @@ struct Marshaler
       if (!ipcObject) {
         HOOK_LOG(LogLevel::Error,
                  ("%s failed to unmarshal parameter %d.", EndpointMsg(endpoint), tupleIndex));
         return false;
       }
       HOOK_LOG(LogLevel::Verbose,
                ("%s unmarshaled parameter %d.", EndpointMsg(endpoint), tupleIndex));
       LogParameterValue(tupleIndex, *ipcObject);
-      EndpointHandler<endpoint>::Copy(aUnmarshaledTuple.GetServerCallData(), aParam, *ipcObject);
+      PhaseHandler::EHContainer::template EndpointHandler<endpoint>::Copy(aUnmarshaledTuple.GetServerCallData(), aParam, *ipcObject);
       ++aNextTupleIdx;
       return true;
     }
   };
 
   /**
    * ShouldMarshal = true : nsDependentCSubstring specialization
    */
@@ -918,17 +738,17 @@ struct Marshaler
    */
   template<int tupleIndex>
   struct MaybeUnmarshalParameter<tupleIndex, char*, true, false>
   {
     static inline bool UnmarshalParameter(IpdlTupleContext& aUnmarshaledTuple, int& aNextTupleIdx, char*& aParam)
     {
       nsDependentCSubstring tempStr;
       bool ret = MaybeUnmarshalParameter<tupleIndex, nsDependentCSubstring, true, false>::UnmarshalParameter(aUnmarshaledTuple, aNextTupleIdx, tempStr);
-      EndpointHandler<endpoint>::Copy(aUnmarshaledTuple.GetServerCallData(), aParam, tempStr);
+      PhaseHandler::EHContainer::template EndpointHandler<endpoint>::Copy(aUnmarshaledTuple.GetServerCallData(), aParam, tempStr);
       return ret;
     }
   };
 
   /**
    * ShouldMarshal = true : const char* specialization
    */
   template<int tupleIndex>
@@ -1017,17 +837,17 @@ template<FunctionHookId functionId> stru
   template<int paramIndex>
   struct ShouldMarshal { static const bool value = !HasFixedValue<paramIndex>::value; };
 };
 
 /**
  * This base stores the RequestHandler's IPCTypeMap.  It really only
  * exists to circumvent the arbitrary C++ rule (enforced by mingw) forbidding
  * full class specialization of a class (IPCTypeMap<T>) inside of an
- * unspecialized template class (RequestHandler<T>).p
+ * unspecialized template class (RequestHandler<T>).
  */
 struct RequestHandlerBase
 {
   // Default to the namespace-level IPCTypeMap
   template<typename OrigType>
   struct IPCTypeMap
   {
     typedef typename mozilla::plugins::IPCTypeMap<OrigType>::ipc_type ipc_type;
@@ -1037,25 +857,30 @@ struct RequestHandlerBase
 #if defined(XP_WIN)
 
 // Request phase uses OpenFileNameIPC for an LPOPENFILENAMEW parameter.
 template<>
 struct RequestHandlerBase::IPCTypeMap<LPOPENFILENAMEW> { typedef OpenFileNameIPC ipc_type; };
 
 #endif // defined(XP_WIN)
 
-template<FunctionHookId functionId, typename FunctionType> struct RequestHandler;
+struct BaseEHContainer {
+  template <Endpoint e> struct EndpointHandler : public BaseEndpointHandler<e,EndpointHandler<e>> {};
+};
 
-template<FunctionHookId functionId, typename ResultType, typename ... ParamTypes>
-struct RequestHandler<functionId, ResultType HOOK_CALL (ParamTypes...)> :
+template<FunctionHookId functionId, typename FunctionType, typename EHContainer> struct RequestHandler;
+
+template<FunctionHookId functionId, typename EHContainerType, typename ResultType, typename ... ParamTypes>
+struct RequestHandler<functionId, ResultType HOOK_CALL (ParamTypes...), EHContainerType> :
   public RequestHandlerBase
 {
   typedef ResultType(HOOK_CALL FunctionType)(ParamTypes...);
-  typedef RequestHandler<functionId, FunctionType> SelfType;
+  typedef RequestHandler<functionId, FunctionType, EHContainerType> SelfType;
   typedef RequestInfo<functionId> Info;
+  typedef EHContainerType EHContainer;
 
   static void Marshal(IpdlTuple& aTuple, const ParamTypes&... aParams)
   {
     ReqMarshaler::Marshal(aTuple, aParams...);
   }
 
   static bool Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, ParamTypes&... aParams)
   {
@@ -1159,25 +984,26 @@ struct ResponseHandlerBase
 #if defined(XP_WIN)
 
 // Response phase uses OpenFileNameRetIPC for an LPOPENFILENAMEW parameter.
 template<>
 struct ResponseHandlerBase::IPCTypeMap<LPOPENFILENAMEW> { typedef OpenFileNameRetIPC ipc_type; };
 
 #endif
 
-template<FunctionHookId functionId, typename FunctionType> struct ResponseHandler;
+template<FunctionHookId functionId, typename FunctionType, typename EHContainer> struct ResponseHandler;
 
-template<FunctionHookId functionId, typename ResultType, typename ... ParamTypes>
-struct ResponseHandler<functionId, ResultType HOOK_CALL (ParamTypes...)> :
+template<FunctionHookId functionId, typename EHContainerType, typename ResultType, typename ... ParamTypes>
+struct ResponseHandler<functionId, ResultType HOOK_CALL (ParamTypes...), EHContainerType> :
   public ResponseHandlerBase
 {
   typedef ResultType(HOOK_CALL FunctionType)(ParamTypes...);
-  typedef ResponseHandler<functionId, FunctionType> SelfType;
+  typedef ResponseHandler<functionId, FunctionType, EHContainerType> SelfType;
   typedef ResponseInfo<functionId> Info;
+  typedef EHContainerType EHContainer;
 
   static void Marshal(IpdlTuple& aTuple, const ResultType& aResult, const ParamTypes&... aParams)
   {
     // Note that this "trick" means that the first parameter we marshal is
     // considered to be parameter #-1 when checking the ResponseInfo.
     // The parameters in the list therefore start at index 0.
     RspMarshaler::template Marshal<-1>(aTuple, aResult, aParams...);
   }
@@ -1210,37 +1036,43 @@ public:
 private:
   ~FDMonitor() {}
 };
 
 /**
  * Data for hooking a function that we automatically broker in a remote
  * process.
  */
-template <FunctionHookId functionId, typename FunctionType>
+template <FunctionHookId functionId, typename FunctionType,
+          typename EHContainer = BaseEHContainer>
 class FunctionBroker;
 
-template <FunctionHookId functionId, typename ResultType, typename ... ParamTypes>
-class FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...)> :
+template <FunctionHookId functionId, typename EHContainer, typename ResultType, typename ... ParamTypes>
+class FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...), EHContainer> :
   public BasicFunctionHook<functionId, ResultType HOOK_CALL (ParamTypes...)>
 {
 public:
   typedef Tuple<ParamTypes...> TupleParamTypes;
   typedef Tuple<mozilla::Maybe<ParamTypes>...> TupleMaybeParamTypes;
   typedef Tuple<ParamTypes*...> TupleParamPtrTypes;
   typedef Tuple<ParamTypes&...> TupleParamRefTypes;
   static const size_t numParams = sizeof...(ParamTypes);
 
   typedef ResultType (HOOK_CALL FunctionType)(ParamTypes...);
-  typedef FunctionBroker<functionId, FunctionType> SelfType;
+  typedef FunctionBroker<functionId, FunctionType, EHContainer> SelfType;
   typedef BasicFunctionHook<functionId, FunctionType> FunctionHookInfoType;
   typedef FunctionHookInfoType BaseType;
 
-  typedef RequestHandler<functionId, FunctionType> Request;
-  typedef ResponseHandler<functionId, FunctionType> Response;
+  typedef RequestHandler<functionId, FunctionType, EHContainer> Request;
+  typedef ResponseHandler<functionId, FunctionType, EHContainer> Response;
+
+  template <typename DelegateFcnType>
+  using RequestDelegate = RequestHandler<functionId, DelegateFcnType, EHContainer>;
+  template <typename DelegateFcnType>
+  using ResponseDelegate = ResponseHandler<functionId, DelegateFcnType, EHContainer>;
 
   FunctionBroker(const char* aModuleName, const char* aMethodName,
                        FunctionType* aOriginalFunction) :
     BasicFunctionHook<functionId, FunctionType>(aModuleName, aMethodName,
                                                 aOriginalFunction, InterceptorStub)
   {
   }
 
@@ -1322,19 +1154,19 @@ protected:
                          IpdlTuple *aOutTuple, std::index_sequence<Indices...>) const
   {
     TupleParamTypes paramTuple;
     return BrokerCallServer(aClientId, aInTuple, aOutTuple,
                              Get<Indices>(paramTuple)...);
   }
 };
 
-template <FunctionHookId functionId, typename ResultType, typename ... ParamTypes>
+template <FunctionHookId functionId, typename EHContainer, typename ResultType, typename ... ParamTypes>
 ResultType
-FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...)>::MaybeBrokerCallClient(ParamTypes&... aParameters) const
+FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...), EHContainer>::MaybeBrokerCallClient(ParamTypes&... aParameters) const
 {
   MOZ_ASSERT(FunctionBrokerChild::GetInstance());
 
   // Broker the call if ShouldBroker says to.  Otherwise, or if brokering
   // fails, then call the original implementation.
   if (!FunctionBrokerChild::GetInstance()) {
     HOOK_LOG(LogLevel::Error,
              ("[%s] Client attempted to broker call without actor.", FunctionHookInfoType::mFunctionName.Data()));
@@ -1359,19 +1191,19 @@ FunctionBroker<functionId, ResultType HO
     }
   }
 
   HOOK_LOG(LogLevel::Info,
             ("[%s] Client could not broker.  Running original version.", FunctionHookInfoType::mFunctionName.Data()));
   return FunctionHookInfoType::mOldFunction(aParameters...);
 }
 
-template <FunctionHookId functionId, typename ResultType, typename ... ParamTypes>
+template <FunctionHookId functionId, typename EHContainer, typename ResultType, typename ... ParamTypes>
 bool
-FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...)>::BrokerCallClient(uint32_t& aWinError,
+FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...), EHContainer>::BrokerCallClient(uint32_t& aWinError,
                                                                   ResultType& aResult,
                                                                   ParamTypes&... aParameters) const
 {
   if (!FunctionBrokerChild::GetInstance()->IsDispatchThread()) {
     return PostToDispatchThread(aWinError, aResult, aParameters...);
   }
 
   if (FunctionBrokerChild::GetInstance()) {
@@ -1406,19 +1238,19 @@ FunctionBroker<functionId, ResultType HO
     }
   }
 
   HOOK_LOG(LogLevel::Error,
             ("[%s] Client failed to broker call.", FunctionHookInfoType::mFunctionName.Data()));
   return false;
 }
 
-template <FunctionHookId functionId, typename ResultType, typename ... ParamTypes>
+template <FunctionHookId functionId, typename EHContainer, typename ResultType, typename ... ParamTypes>
 bool
-FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...)>::BrokerCallServer(base::ProcessId aClientId, const IpdlTuple &aInTuple,
+FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...), EHContainer>::BrokerCallServer(base::ProcessId aClientId, const IpdlTuple &aInTuple,
                   IpdlTuple *aOutTuple, ParamTypes&... aParams) const
 {
   HOOK_LOG(LogLevel::Info, ("[%s] Server brokering function.", FunctionHookInfoType::mFunctionName.Data()));
 
   ServerCallData scd;
   if (!Request::Unmarshal(scd, aInTuple, aParams...)) {
     HOOK_LOG(LogLevel::Info,
              ("[%s] Server failed to unmarshal.", FunctionHookInfoType::mFunctionName.Data()));
@@ -1454,19 +1286,19 @@ FunctionBroker<functionId, ResultType HO
   if (transmitError) {
     aOutTuple->AddElement(err);
   }
 #endif
 
   return true;
 }
 
-template <FunctionHookId functionId, typename ResultType, typename ... ParamTypes>
+template <FunctionHookId functionId, typename EHContainer, typename ResultType, typename ... ParamTypes>
 bool
-FunctionBroker<functionId,ResultType HOOK_CALL (ParamTypes...)>::
+FunctionBroker<functionId,ResultType HOOK_CALL (ParamTypes...), EHContainer>::
 PostToDispatchThread(uint32_t& aWinError, ResultType& aRet,
                      ParamTypes&... aParameters) const
 {
   MOZ_ASSERT(!FunctionBrokerChild::GetInstance()->IsDispatchThread());
   HOOK_LOG(LogLevel::Debug,
            ("Posting broker task '%s' to dispatch thread", FunctionHookInfoType::mFunctionName.Data()));
 
   // Run PostToDispatchHelper on the dispatch thread.  It will notify our
--- a/dom/plugins/ipc/FunctionBrokerIPCUtils.h
+++ b/dom/plugins/ipc/FunctionBrokerIPCUtils.h
@@ -41,16 +41,17 @@ enum FunctionHookId
   , ID_HttpSendRequestA
   , ID_HttpSendRequestExA
   , ID_InternetQueryOptionA
   , ID_InternetErrorDlg
   , ID_AcquireCredentialsHandleA
   , ID_QueryCredentialsAttributesA
   , ID_FreeCredentialsHandle
   , ID_PrintDlgW
+  , ID_CreateMutexW
   , ID_FunctionHookCount
 #else // defined(XP_WIN)
     ID_FunctionHookCount
 #endif // defined(XP_WIN)
 };
 
 // Max number of bytes to show when logging a blob of raw memory
 static const uint32_t MAX_BLOB_CHARS_TO_LOG = 12;
--- a/dom/plugins/ipc/PluginProcessParent.cpp
+++ b/dom/plugins/ipc/PluginProcessParent.cpp
@@ -56,16 +56,22 @@ PluginProcessParent::Launch(mozilla::Uni
                             bool aIsSandboxLoggingEnabled)
 {
 #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_SANDBOX)
     // At present, the Mac Flash plugin sandbox does not support different
     // levels and is enabled via a boolean pref or environment variable.
     // On Mac, when |aSandboxLevel| is positive, we enable the sandbox.
 #if defined(XP_WIN)
     mSandboxLevel = aSandboxLevel;
+
+    // The sandbox process sometimes needs read access to the plugin file.
+    if (aSandboxLevel >= 3) {
+        std::wstring pluginFile(NS_ConvertUTF8toUTF16(mPluginFilePath.c_str()).get());
+        mAllowedFilesRead.push_back(pluginFile);
+    }
 #endif // XP_WIN
 #else
     if (aSandboxLevel != 0) {
         MOZ_ASSERT(false,
                    "Can't enable an NPAPI process sandbox for platform/build.");
     }
 #endif
 
--- a/dom/plugins/ipc/PluginQuirks.cpp
+++ b/dom/plugins/ipc/PluginQuirks.cpp
@@ -26,16 +26,17 @@ int GetQuirksFromMimeTypeAndFilename(con
         quirks |= QUIRK_FLASH_HOOK_SETLONGPTR;
         quirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO;
         quirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE;
         quirks |= QUIRK_WINLESS_HOOK_IME;
 #if defined(_M_X64) || defined(__x86_64__)
         quirks |= QUIRK_FLASH_HOOK_GETKEYSTATE;
         quirks |= QUIRK_FLASH_HOOK_PRINTDLGW;
         quirks |= QUIRK_FLASH_HOOK_SSL;
+        quirks |= QUIRK_FLASH_HOOK_CREATEMUTEXW;
 #endif
 #endif
     }
 
 #ifdef XP_MACOSX
     // Whitelist Flash to support offline renderer.
     if (specialType == nsPluginHost::eSpecialType_Flash) {
         quirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
--- a/dom/plugins/ipc/PluginQuirks.h
+++ b/dom/plugins/ipc/PluginQuirks.h
@@ -46,16 +46,18 @@ enum PluginQuirks {
   // Win: Hook IMM32 API to handle IME event on windowless plugin
   QUIRK_WINLESS_HOOK_IME                          = 1 << 12,
   // Win: Hook GetKeyState to get keyboard state on sandbox process
   QUIRK_FLASH_HOOK_GETKEYSTATE                    = 1 << 13,
   // Win: Hook PrintDlgW to show print settings dialog on sandbox process
   QUIRK_FLASH_HOOK_PRINTDLGW                      = 1 << 14,
   // Win: Broker Win32 SSL operations
   QUIRK_FLASH_HOOK_SSL                            = 1 << 15,
+  // Win: Hook CreateMutexW for brokering when using the camera
+  QUIRK_FLASH_HOOK_CREATEMUTEXW                   = 1 << 16,
 };
 
 int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType,
                                      const nsCString& aPluginFilename);
 
 } /* namespace plugins */
 } /* namespace mozilla */
 
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -299,22 +299,24 @@ NS_TrustedNewXULElement(Element** aResul
 
 //----------------------------------------------------------------------
 // nsISupports interface
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement,
                                                   nsStyledElement)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBindingParent);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULElement,
                                                 nsStyledElement)
     // Why aren't we unlinking the prototype?
     tmp->ClearHasID();
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(mBindingParent);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(nsXULElement, nsStyledElement)
 NS_IMPL_RELEASE_INHERITED(nsXULElement, nsStyledElement)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULElement)
     NS_INTERFACE_TABLE_INHERITED(nsXULElement, nsIDOMNode)
     NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -665,19 +665,19 @@ protected:
     NS_IMETHOD GetParentTree(nsIDOMXULMultiSelectControlElement** aTreeElement);
 
     nsresult AddPopupListener(nsAtom* aName);
 
     void LoadSrc();
 
     /**
      * The nearest enclosing content node with a binding
-     * that created us. [Weak]
+     * that created us.
      */
-    nsIContent*                         mBindingParent;
+    nsCOMPtr<nsIContent> mBindingParent;
 
     /**
      * Abandon our prototype linkage, and copy all attributes locally
      */
     nsresult MakeHeavyweight(nsXULPrototypeElement* aPrototype);
 
     virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
                                    const nsAttrValueOrString* aValue,
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -63,26 +63,32 @@ struct void_t {
   bool operator==(const void_t&) const { return true; }
 };
 struct null_t {
   bool operator==(const null_t&) const { return true; }
 };
 
 struct SerializedStructuredCloneBuffer final
 {
-  SerializedStructuredCloneBuffer() {}
+  SerializedStructuredCloneBuffer()
+   : data(JS::StructuredCloneScope::Unassigned)
+  {
+  }
+
   SerializedStructuredCloneBuffer(const SerializedStructuredCloneBuffer& aOther)
+   : SerializedStructuredCloneBuffer()
   {
     *this = aOther;
   }
 
   SerializedStructuredCloneBuffer&
   operator=(const SerializedStructuredCloneBuffer& aOther)
   {
     data.Clear();
+    data.initScope(aOther.data.scope());
     data.Append(aOther.data);
     return *this;
   }
 
   bool
   operator==(const SerializedStructuredCloneBuffer& aOther) const
   {
     // The copy assignment operator and the equality operator are
@@ -871,17 +877,17 @@ struct ParamTraits<JSStructuredCloneData
 
     bool success;
     mozilla::BufferList<js::SystemAllocPolicy> out =
       buffers.MoveFallible<js::SystemAllocPolicy>(&success);
     if (!success) {
       return false;
     }
 
-    *aResult = JSStructuredCloneData(Move(out));
+    *aResult = JSStructuredCloneData(Move(out), JS::StructuredCloneScope::DifferentProcess);
 
     return true;
   }
 };
 
 template <>
 struct ParamTraits<mozilla::SerializedStructuredCloneBuffer>
 {
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -163,17 +163,24 @@ enum class StructuredCloneScope : uint32
 
     /**
      * Handle a backwards-compatibility case with IndexedDB (bug 1434308): when
      * reading, this means to treat legacy SameProcessSameThread data as if it
      * were DifferentProcess.
      *
      * Do not use this for writing; use DifferentProcess instead.
      */
-    DifferentProcessForIndexedDB
+    DifferentProcessForIndexedDB,
+
+    /**
+     * Existing code wants to be able to create an uninitialized
+     * JSStructuredCloneData without knowing the scope, then populate it with
+     * data (at which point the scope *is* known.)
+     */
+    Unassigned
 };
 
 enum TransferableOwnership {
     /** Transferable data has not been filled in yet */
     SCTAG_TMO_UNFILLED = 0,
 
     /** Structured clone buffer does not yet own the data */
     SCTAG_TMO_UNOWNED = 1,
@@ -382,78 +389,99 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(J
     using BufferList = mozilla::BufferList<js::SystemAllocPolicy>;
     using Iterator = BufferList::IterImpl;
 
   private:
     static const size_t kStandardCapacity = 4096;
 
     BufferList bufList_;
 
+    // The (address space, thread) scope within which this clone is valid. Note
+    // that this must be either set during construction, or start out as
+    // Unassigned and transition once to something else.
+    JS::StructuredCloneScope scope_;
+
     const JSStructuredCloneCallbacks* callbacks_ = nullptr;
     void* closure_ = nullptr;
     OwnTransferablePolicy ownTransferables_ = OwnTransferablePolicy::NoTransferables;
     js::SharedArrayRawBufferRefs refsHeld_;
 
     friend struct JSStructuredCloneWriter;
     friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer);
     template <typename T, typename AllocPolicy> friend struct js::BufferIterator;
 
   public:
     // The constructor must be infallible but SystemAllocPolicy is not, so both
     // the initial size and initial capacity of the BufferList must be zero.
-    explicit JSStructuredCloneData()
+    explicit JSStructuredCloneData(JS::StructuredCloneScope scope)
         : bufList_(0, 0, kStandardCapacity, js::SystemAllocPolicy())
+        , scope_(scope)
         , callbacks_(nullptr)
         , closure_(nullptr)
         , ownTransferables_(OwnTransferablePolicy::NoTransferables)
     {}
 
     // Steal the raw data from a BufferList. In this case, we don't know the
     // scope and none of the callback info is assigned yet.
-    MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
+    JSStructuredCloneData(BufferList&& buffers, JS::StructuredCloneScope scope)
         : bufList_(mozilla::Move(buffers))
+        , scope_(scope)
         , callbacks_(nullptr)
         , closure_(nullptr)
         , ownTransferables_(OwnTransferablePolicy::NoTransferables)
     {}
+    MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
+        : JSStructuredCloneData(mozilla::Move(buffers), JS::StructuredCloneScope::Unassigned)
+    {}
     JSStructuredCloneData(JSStructuredCloneData&& other) = default;
     JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
     ~JSStructuredCloneData() { discardTransferables(); }
 
     void setCallbacks(const JSStructuredCloneCallbacks* callbacks,
                       void* closure,
                       OwnTransferablePolicy policy)
     {
         callbacks_ = callbacks;
         closure_ = closure;
         ownTransferables_ = policy;
     }
 
     bool Init(size_t initialCapacity = 0) { return bufList_.Init(0, initialCapacity); }
 
+    JS::StructuredCloneScope scope() const { return scope_; }
+
+    void initScope(JS::StructuredCloneScope scope) {
+        MOZ_ASSERT(Size() == 0, "initScope() of nonempty JSStructuredCloneData");
+        if (scope_ != JS::StructuredCloneScope::Unassigned)
+            MOZ_ASSERT(scope_ == scope, "Cannot change scope after it has been initialized");
+        scope_ = scope;
+    }
+
     size_t Size() const { return bufList_.Size(); }
 
     const Iterator Start() const { return bufList_.Iter(); }
 
     bool Advance(Iterator& iter, size_t distance) const {
         return iter.AdvanceAcrossSegments(bufList_, distance);
     }
 
     bool ReadBytes(Iterator& iter, char* buffer, size_t size) const {
         return bufList_.ReadBytes(iter, buffer, size);
     }
 
     // Append new data to the end of the buffer.
     bool AppendBytes(const char* data, size_t size) {
+        MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned);
         return bufList_.WriteBytes(data, size);
     }
 
     // Update data stored within the existing buffer. There must be at least
     // 'size' bytes between the position of 'iter' and the end of the buffer.
     bool UpdateBytes(Iterator& iter, const char* data, size_t size) const {
+        MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned);
         while (size > 0) {
             size_t remaining = iter.RemainingInSegment();
             size_t nbytes = std::min(remaining, size);
             memcpy(iter.Data(), data, nbytes);
             data += nbytes;
             size -= nbytes;
             iter.Advance(bufList_, nbytes);
         }
@@ -464,21 +492,25 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(J
         return bufList_.AllocateBytes(maxSize, size);
     }
 
     void Clear() {
         discardTransferables();
         bufList_.Clear();
     }
 
-    template<typename BorrowingAllocPolicy>
-    mozilla::BufferList<BorrowingAllocPolicy> Borrow(Iterator& iter, size_t size, bool* success,
-                                            BorrowingAllocPolicy ap = BorrowingAllocPolicy()) const
+    // Return a new read-only JSStructuredCloneData that "borrows" the contents
+    // of |this|. Its lifetime should not exceed the donor's. This is only
+    // allowed for DifferentProcess clones, so finalization of the borrowing
+    // clone will do nothing.
+    JSStructuredCloneData Borrow(Iterator& iter, size_t size, bool* success) const
     {
-        return bufList_.Borrow<BorrowingAllocPolicy>(iter, size, success);
+        MOZ_ASSERT(scope_ == JS::StructuredCloneScope::DifferentProcess);
+        return JSStructuredCloneData(bufList_.Borrow<js::SystemAllocPolicy>(iter, size, success),
+                                     scope_);
     }
 
     // Iterate over all contained data, one BufferList segment's worth at a
     // time, and invoke the given FunctionToApply with the data pointer and
     // size. The function should return a bool value, and this loop will exit
     // with false if the function ever returns false.
     template <typename FunctionToApply>
     bool ForEachDataChunk(FunctionToApply&& function) const {
@@ -488,30 +520,26 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(J
                 return false;
             iter.Advance(bufList_, iter.RemainingInSegment());
         }
         return true;
     }
 
     // Append the entire contents of other's bufList_ to our own.
     bool Append(const JSStructuredCloneData& other) {
+        MOZ_ASSERT(scope_ == other.scope());
         return other.ForEachDataChunk([&](const char* data, size_t size) {
             return AppendBytes(data, size);
         });
     }
 
     size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
         return bufList_.SizeOfExcludingThis(mallocSizeOf);
     }
 
-    // For testing only.
-    void IgnoreTransferables() {
-        ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny;
-    }
-
     void discardTransferables();
 };
 
 /**
  * Implements StructuredDeserialize and StructuredDeserializeWithTransfer.
  *
  * Note: If `data` contains transferable objects, it can be read only once.
  */
@@ -558,31 +586,33 @@ JS_StructuredClone(JSContext* cx, JS::Ha
 class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
     const JS::StructuredCloneScope scope_;
     JSStructuredCloneData data_;
     uint32_t version_;
 
   public:
     JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope,
                                 const JSStructuredCloneCallbacks* callbacks, void* closure)
-        : scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION)
+        : scope_(scope), data_(scope), version_(JS_STRUCTURED_CLONE_VERSION)
     {
         data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
     }
 
     JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);
     JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other);
 
     ~JSAutoStructuredCloneBuffer() { clear(); }
 
     JSStructuredCloneData& data() { return data_; }
     bool empty() const { return !data_.Size(); }
 
     void clear();
 
+    JS::StructuredCloneScope scope() const { return scope_; }
+
     /**
      * Adopt some memory. It will be automatically freed by the destructor.
      * data must have been allocated by the JS engine (e.g., extracted via
      * JSAutoStructuredCloneBuffer::steal).
      */
     void adopt(JSStructuredCloneData&& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
                const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2840,17 +2840,17 @@ class CloneBufferObject : public NativeO
 
         return &obj->as<CloneBufferObject>();
     }
 
     static CloneBufferObject* Create(JSContext* cx, JSAutoStructuredCloneBuffer* buffer) {
         Rooted<CloneBufferObject*> obj(cx, Create(cx));
         if (!obj)
             return nullptr;
-        auto data = js::MakeUnique<JSStructuredCloneData>();
+        auto data = js::MakeUnique<JSStructuredCloneData>(buffer->scope());
         if (!data) {
             ReportOutOfMemory(cx);
             return nullptr;
         }
         buffer->steal(data.get());
         obj->setData(data.release(), false);
         return obj;
     }
@@ -2862,21 +2862,16 @@ class CloneBufferObject : public NativeO
     bool isSynthetic() const {
         return getReservedSlot(SYNTHETIC_SLOT).toBoolean();
     }
 
     void setData(JSStructuredCloneData* aData, bool synthetic) {
         MOZ_ASSERT(!data());
         setReservedSlot(DATA_SLOT, PrivateValue(aData));
         setReservedSlot(SYNTHETIC_SLOT, BooleanValue(synthetic));
-
-        // For testing only, and will be unnecessary once the scope is moved
-        // into JSStructuredCloneData.
-        if (synthetic)
-            aData->IgnoreTransferables();
     }
 
     // Discard an owned clone buffer.
     void discard() {
         js_delete(data());
         setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
     }
 
@@ -2904,17 +2899,17 @@ class CloneBufferObject : public NativeO
             nbytes = JS_GetStringLength(str);
         }
 
         if (nbytes == 0 || (nbytes % sizeof(uint64_t) != 0)) {
             JS_ReportErrorASCII(cx, "Invalid length for clonebuffer data");
             return false;
         }
 
-        auto buf = js::MakeUnique<JSStructuredCloneData>();
+        auto buf = js::MakeUnique<JSStructuredCloneData>(JS::StructuredCloneScope::DifferentProcess);
         if (!buf || !buf->Init(nbytes)) {
             ReportOutOfMemory(cx);
             return false;
         }
 
         MOZ_ALWAYS_TRUE(buf->AppendBytes((const char*)data, nbytes));
         obj->discard();
         obj->setData(buf.release(), true);
--- a/js/src/fuzz-tests/testStructuredCloneReader.cpp
+++ b/js/src/fuzz-tests/testStructuredCloneReader.cpp
@@ -34,29 +34,29 @@ testStructuredCloneReaderFuzz(const uint
     });
 
     if (!size) return 0;
 
     // Make sure to pad the buffer to a multiple of kSegmentAlignment
     const size_t kSegmentAlignment = 8;
     size_t buf_size = JS_ROUNDUP(size, kSegmentAlignment);
 
-    auto clonebuf = MakeUnique<JSStructuredCloneData>();
+    JS::StructuredCloneScope scope = JS::StructuredCloneScope::DifferentProcess;
+
+    auto clonebuf = MakeUnique<JSStructuredCloneData>(scope);
     if (!clonebuf || !clonebuf->Init(buf_size)) {
         ReportOutOfMemory(gCx);
         return 0;
     }
 
     // Copy buffer then pad with zeroes.
     clonebuf->AppendBytes((const char*)buf, size);
     char padding[kSegmentAlignment] = {0};
     clonebuf->AppendBytes(padding, buf_size - size);
 
-    JS::StructuredCloneScope scope = JS::StructuredCloneScope::DifferentProcess;
-
     RootedValue deserialized(gCx);
     if (!JS_ReadStructuredClone(gCx, *clonebuf,
     			JS_STRUCTURED_CLONE_VERSION,
     			scope,
     			&deserialized, nullptr, nullptr))
     {
         return 0;
     }
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1262,24 +1262,18 @@ CodeGenerator::visitValueToObjectOrNull(
     masm.jump(ool->rejoin());
 
     masm.bind(&isObject);
     masm.unboxObject(input, output);
 
     masm.bind(ool->rejoin());
 }
 
-enum class FieldToBarrier {
-    REGEXP_PENDING_INPUT,
-    REGEXP_MATCHES_INPUT,
-    DEPENDENT_STRING_BASE
-};
-
 static void
-EmitStoreBufferMutation(MacroAssembler& masm, Register holder, FieldToBarrier field,
+EmitStoreBufferMutation(MacroAssembler& masm, Register holder, size_t offset,
                         Register buffer,
                         LiveGeneralRegisterSet& liveVolatiles,
                         void (*fun)(js::gc::StoreBuffer*, js::gc::Cell**))
 {
     Label callVM;
     Label exit;
 
     // Call into the VM to barrier the write. The only registers that need to
@@ -1288,29 +1282,17 @@ EmitStoreBufferMutation(MacroAssembler& 
     masm.bind(&callVM);
     masm.PushRegsInMask(liveVolatiles);
 
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
     regs.takeUnchecked(buffer);
     regs.takeUnchecked(holder);
     Register addrReg = regs.takeAny();
 
-    switch (field) {
-      case FieldToBarrier::REGEXP_PENDING_INPUT:
-        masm.computeEffectiveAddress(Address(holder, RegExpStatics::offsetOfPendingInput()), addrReg);
-        break;
-
-      case FieldToBarrier::REGEXP_MATCHES_INPUT:
-        masm.computeEffectiveAddress(Address(holder, RegExpStatics::offsetOfMatchesInput()), addrReg);
-        break;
-
-      case FieldToBarrier::DEPENDENT_STRING_BASE:
-        masm.leaNewDependentStringBase(holder, addrReg);
-        break;
-    }
+    masm.computeEffectiveAddress(Address(holder, offset), addrReg);
 
     bool needExtraReg = !regs.hasAny<GeneralRegisterSet::DefaultType>();
     if (needExtraReg) {
         masm.push(holder);
         masm.setupUnalignedABICall(holder);
     } else {
         masm.setupUnalignedABICall(regs.takeAny());
     }
@@ -1323,17 +1305,17 @@ EmitStoreBufferMutation(MacroAssembler& 
         masm.pop(holder);
     masm.PopRegsInMask(liveVolatiles);
     masm.bind(&exit);
 }
 
 // Warning: this function modifies prev and next.
 static void
 EmitPostWriteBarrierS(MacroAssembler& masm,
-                      Register string, FieldToBarrier field,
+                      Register holder, size_t offset,
                       Register prev, Register next,
                       LiveGeneralRegisterSet& liveVolatiles)
 {
     Label exit;
     Label checkRemove, putCell;
 
     // if (next && (buffer = next->storeBuffer()))
     // but we never pass in nullptr for next.
@@ -1343,26 +1325,26 @@ EmitPostWriteBarrierS(MacroAssembler& ma
 
     // if (prev && prev->storeBuffer())
     masm.branchPtr(Assembler::Equal, prev, ImmWord(0), &putCell);
     masm.loadStoreBuffer(prev, prev);
     masm.branchPtr(Assembler::NotEqual, prev, ImmWord(0), &exit);
 
     // buffer->putCell(cellp)
     masm.bind(&putCell);
-    EmitStoreBufferMutation(masm, string, field, storebuffer, liveVolatiles,
+    EmitStoreBufferMutation(masm, holder, offset, storebuffer, liveVolatiles,
                             JSString::addCellAddressToStoreBuffer);
     masm.jump(&exit);
 
     // if (prev && (buffer = prev->storeBuffer()))
     masm.bind(&checkRemove);
     masm.branchPtr(Assembler::Equal, prev, ImmWord(0), &exit);
     masm.loadStoreBuffer(prev, storebuffer);
     masm.branchPtr(Assembler::Equal, storebuffer, ImmWord(0), &exit);
-    EmitStoreBufferMutation(masm, string, field, storebuffer, liveVolatiles,
+    EmitStoreBufferMutation(masm, holder, offset, storebuffer, liveVolatiles,
                             JSString::removeCellAddressFromStoreBuffer);
 
     masm.bind(&exit);
 }
 
 typedef JSObject* (*CloneRegExpObjectFn)(JSContext*, Handle<RegExpObject*>);
 static const VMFunction CloneRegExpObjectInfo =
     FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject, "CloneRegExpObject");
@@ -1409,16 +1391,17 @@ RegExpPairCountAddress(MacroAssembler& m
 // If the RegExp was successfully executed and matched the input, fallthrough,
 // otherwise jump to notFound or failure.
 static bool
 PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Register input,
                         Register lastIndex,
                         Register temp1, Register temp2, Register temp3,
                         size_t inputOutputDataStartOffset,
                         RegExpShared::CompilationMode mode,
+                        bool stringsCanBeInNursery,
                         Label* notFound, Label* failure)
 {
     size_t matchPairsStartOffset = inputOutputDataStartOffset + sizeof(irregexp::InputOutputData);
     size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
 
     Address inputStartAddress(masm.getStackPointer(),
         inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, inputStart));
     Address inputEndAddress(masm.getStackPointer(),
@@ -1604,31 +1587,36 @@ PrepareAndExecuteRegExp(JSContext* cx, M
     Address matchesInputAddress(temp1, RegExpStatics::offsetOfMatchesInput());
     Address lazySourceAddress(temp1, RegExpStatics::offsetOfLazySource());
     Address lazyIndexAddress(temp1, RegExpStatics::offsetOfLazyIndex());
 
     masm.guardedCallPreBarrier(pendingInputAddress, MIRType::String);
     masm.guardedCallPreBarrier(matchesInputAddress, MIRType::String);
     masm.guardedCallPreBarrier(lazySourceAddress, MIRType::String);
 
-    if (temp1.volatile_())
-        volatileRegs.add(temp1);
-
-    // Writing into RegExpStatics tenured memory; must post-barrier.
-    masm.loadPtr(pendingInputAddress, temp2);
-    masm.storePtr(input, pendingInputAddress);
-    masm.movePtr(input, temp3);
-    EmitPostWriteBarrierS(masm, temp1, FieldToBarrier::REGEXP_PENDING_INPUT,
-                          temp2 /* prev */, temp3 /* next */, volatileRegs);
-
-    masm.loadPtr(matchesInputAddress, temp2);
-    masm.storePtr(input, matchesInputAddress);
-    masm.movePtr(input, temp3);
-    EmitPostWriteBarrierS(masm, temp1, FieldToBarrier::REGEXP_MATCHES_INPUT,
-                          temp2 /* prev */, temp3 /* next */, volatileRegs);
+    if (stringsCanBeInNursery) {
+        // Writing into RegExpStatics tenured memory; must post-barrier.
+        if (temp1.volatile_())
+            volatileRegs.add(temp1);
+
+        masm.loadPtr(pendingInputAddress, temp2);
+        masm.storePtr(input, pendingInputAddress);
+        masm.movePtr(input, temp3);
+        EmitPostWriteBarrierS(masm, temp1, RegExpStatics::offsetOfPendingInput(),
+                              temp2 /* prev */, temp3 /* next */, volatileRegs);
+
+        masm.loadPtr(matchesInputAddress, temp2);
+        masm.storePtr(input, matchesInputAddress);
+        masm.movePtr(input, temp3);
+        EmitPostWriteBarrierS(masm, temp1, RegExpStatics::offsetOfMatchesInput(),
+                              temp2 /* prev */, temp3 /* next */, volatileRegs);
+    } else {
+        masm.storePtr(input, pendingInputAddress);
+        masm.storePtr(input, matchesInputAddress);
+    }
 
     masm.storePtr(lastIndex, Address(temp1, RegExpStatics::offsetOfLazyIndex()));
     masm.store32(Imm32(1), Address(temp1, RegExpStatics::offsetOfPendingLazyEvaluation()));
 
     masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp2);
     masm.loadPtr(Address(temp2, RegExpShared::offsetOfSource()), temp3);
     masm.storePtr(temp3, lazySourceAddress);
     masm.load32(Address(temp2, RegExpShared::offsetOfFlags()), temp3);
@@ -1659,28 +1647,30 @@ class CreateDependentString
     };
     mozilla::EnumeratedArray<FallbackKind, FallbackKind::Count, Label> fallbacks_, joins_;
 
 public:
     // Generate code that creates DependentString.
     // Caller should call generateFallback after masm.ret(), to generate
     // fallback path.
     void generate(MacroAssembler& masm, const JSAtomState& names,
+                  CompileRuntime* runtime,
                   bool latin1, Register string,
                   Register base, Register temp1, Register temp2,
                   BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
                   bool stringsCanBeInNursery,
                   Label* failure);
 
     // Generate fallback path for creating DependentString.
     void generateFallback(MacroAssembler& masm, LiveRegisterSet regsToSave);
 };
 
 void
 CreateDependentString::generate(MacroAssembler& masm, const JSAtomState& names,
+                                CompileRuntime* runtime,
                                 bool latin1, Register string,
                                 Register base, Register temp1, Register temp2,
                                 BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
                                 bool stringsCanBeInNursery,
                                 Label* failure)
 {
     string_ = string;
     temp_ = temp2;
@@ -1797,24 +1787,33 @@ CreateDependentString::generate(MacroAss
         masm.and32(Imm32(JSString::TYPE_FLAGS_MASK), temp2);
         masm.branch32(Assembler::NotEqual, temp2, Imm32(JSString::DEPENDENT_FLAGS), &noBase);
         masm.loadDependentStringBase(base, temp1);
         masm.storeDependentStringBase(temp1, string);
         masm.bind(&noBase);
 
         // Post-barrier the base store, whether it was the direct or indirect
         // base (both will end up in temp1 here).
-        masm.movePtr(ImmWord(0), temp2);
-        LiveGeneralRegisterSet saveRegs(GeneralRegisterSet::Volatile());
-        if (temp1.volatile_())
-            saveRegs.takeUnchecked(temp1);
-        if (temp2.volatile_())
-            saveRegs.takeUnchecked(temp2);
-        EmitPostWriteBarrierS(masm, string, FieldToBarrier::DEPENDENT_STRING_BASE,
-                              temp2 /* prev */, temp1 /* next */, saveRegs);
+        masm.branchPtrInNurseryChunk(Assembler::NotEqual, temp1, temp2, &done);
+
+        LiveRegisterSet regsToSave(RegisterSet::Volatile());
+        regsToSave.takeUnchecked(temp1);
+        regsToSave.takeUnchecked(temp2);
+        regsToSave.addUnchecked(string);
+
+        masm.PushRegsInMask(regsToSave);
+
+        masm.mov(ImmPtr(runtime), temp1);
+
+        masm.setupUnalignedABICall(temp2);
+        masm.passABIArg(temp1);
+        masm.passABIArg(string);
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
+
+        masm.PopRegsInMask(regsToSave);
     }
 
     masm.bind(&done);
 }
 
 static void*
 AllocateString(JSContext* cx)
 {
@@ -1942,17 +1941,17 @@ JitCompartment::generateRegExpMatcherStu
     StackMacroAssembler masm(cx);
 
     // The InputOutputData is placed above the return address on the stack.
     size_t inputOutputDataStartOffset = sizeof(void*);
 
     Label notFound, oolEntry;
     if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
                                  temp1, temp2, temp5, inputOutputDataStartOffset,
-                                 RegExpShared::Normal, &notFound, &oolEntry))
+                                 RegExpShared::Normal, stringsCanBeInNursery, &notFound, &oolEntry))
     {
         return nullptr;
     }
 
     // Construct the result.
     Register object = temp1;
     Label matchResultFallback, matchResultJoin;
     TemplateObject templateObj(templateObject);
@@ -2028,17 +2027,19 @@ JitCompartment::generateRegExpMatcherStu
                 masm.bind(&isLatin1);
 
             Label matchLoop;
             masm.bind(&matchLoop);
 
             Label isUndefined, storeDone;
             masm.branch32(Assembler::LessThan, stringIndexAddress, Imm32(0), &isUndefined);
 
-            depStr[isLatin].generate(masm, cx->names(), isLatin, temp3, input, temp4, temp5,
+            depStr[isLatin].generate(masm, cx->names(),
+                                     CompileRuntime::get(cx->runtime()),
+                                     isLatin, temp3, input, temp4, temp5,
                                      stringIndexAddress, stringLimitAddress,
                                      stringsCanBeInNursery,
                                      failure);
 
             masm.storeValue(JSVAL_TYPE_STRING, temp3, stringAddress);
             // Storing into nursery-allocated results object's elements; no post barrier.
             masm.jump(&storeDone);
             masm.bind(&isUndefined);
@@ -2249,17 +2250,18 @@ JitCompartment::generateRegExpSearcherSt
     StackMacroAssembler masm(cx);
 
     // The InputOutputData is placed above the return address on the stack.
     size_t inputOutputDataStartOffset = sizeof(void*);
 
     Label notFound, oolEntry;
     if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
                                  temp1, temp2, temp3, inputOutputDataStartOffset,
-                                 RegExpShared::Normal, &notFound, &oolEntry))
+                                 RegExpShared::Normal, stringsCanBeInNursery,
+                                 &notFound, &oolEntry))
     {
         return nullptr;
     }
 
     size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
     Address stringIndexAddress(masm.getStackPointer(),
                                pairsVectorStartOffset + offsetof(MatchPair, start));
     Address stringLimitAddress(masm.getStackPointer(),
@@ -2401,17 +2403,18 @@ JitCompartment::generateRegExpTesterStub
     Register temp2 = regs.takeAny();
     Register temp3 = regs.takeAny();
 
     masm.reserveStack(sizeof(irregexp::InputOutputData));
 
     Label notFound, oolEntry;
     if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
                                  temp1, temp2, temp3, 0,
-                                 RegExpShared::MatchOnly, &notFound, &oolEntry))
+                                 RegExpShared::MatchOnly, stringsCanBeInNursery,
+                                 &notFound, &oolEntry))
     {
         return nullptr;
     }
 
     Label done;
 
     // temp3 contains endIndex.
     masm.move32(temp3, result);
@@ -3972,21 +3975,23 @@ EmitPostWriteBarrier(MacroAssembler& mas
         EmitStoreBufferCheckForConstant(masm, &maybeConstant->asTenured(), regs, &exit, &callVM);
 
     // Call into the VM to barrier the write.
     masm.bind(&callVM);
 
     Register runtimereg = regs.takeAny();
     masm.mov(ImmPtr(runtime), runtimereg);
 
-    void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier;
     masm.setupUnalignedABICall(regs.takeAny());
     masm.passABIArg(runtimereg);
     masm.passABIArg(objreg);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
+    if (isGlobal)
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostGlobalWriteBarrier));
+    else
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
 
     masm.bind(&exit);
 }
 
 void
 CodeGenerator::emitPostWriteBarrier(const LAllocation* obj)
 {
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -684,21 +684,21 @@ GetDynamicName(JSContext* cx, JSObject* 
         if (FetchNameNoGC(pobj, prop, MutableHandleValue::fromMarkedLocation(vp)))
             return;
     }
 
     vp->setUndefined();
 }
 
 void
-PostWriteBarrier(JSRuntime* rt, JSObject* obj)
+PostWriteBarrier(JSRuntime* rt, js::gc::Cell* cell)
 {
     AutoUnsafeCallWithABI unsafe;
-    MOZ_ASSERT(!IsInsideNursery(obj));
-    rt->gc.storeBuffer().putWholeCell(obj);
+    MOZ_ASSERT(!IsInsideNursery(cell));
+    rt->gc.storeBuffer().putWholeCell(cell);
 }
 
 static const size_t MAX_WHOLE_CELL_BUFFER_SIZE = 4096;
 
 template <IndexInBounds InBounds>
 void
 PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index)
 {
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -20,16 +20,22 @@ namespace js {
 
 class NamedLambdaObject;
 class WithScope;
 class InlineTypedObject;
 class GeneratorObject;
 class RegExpObject;
 class TypedArrayObject;
 
+namespace gc {
+
+struct Cell;
+
+}
+
 namespace jit {
 
 enum DataType : uint8_t {
     Type_Void,
     Type_Bool,
     Type_Int32,
     Type_Double,
     Type_Pointer,
@@ -739,17 +745,17 @@ bool OperatorInI(JSContext* cx, uint32_t
 MOZ_MUST_USE bool
 GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rval);
 
 MOZ_MUST_USE bool
 CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval);
 
 void GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp);
 
-void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
+void PostWriteBarrier(JSRuntime* rt, js::gc::Cell* cell);
 void PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj);
 
 enum class IndexInBounds { Yes, Maybe };
 
 template <IndexInBounds InBounds>
 void PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index);
 
 // If |str| is an index in the range [0, INT32_MAX], return it. If the string
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -44,29 +44,28 @@ MemoryReportingSundriesThreshold()
 {
     return 8 * 1024;
 }
 
 template <typename CharT>
 static uint32_t
 HashStringChars(JSString* s)
 {
-    ScopedJSFreePtr<CharT> ownedChars;
-    const CharT* chars;
-    JS::AutoCheckCannotGC nogc;
+    uint32_t hash = 0;
     if (s->isLinear()) {
-        chars = s->asLinear().chars<CharT>(nogc);
+        JS::AutoCheckCannotGC nogc;
+        const CharT* chars = s->asLinear().chars<CharT>(nogc);
+        hash = mozilla::HashString(chars, s->length());
     } else {
-        // Slowest hash function evar!
-        if (!s->asRope().copyChars<CharT>(/* tcx */ nullptr, ownedChars))
+        // Use rope's non-copying hash function.
+        if (!s->asRope().hash(&hash))
             MOZ_CRASH("oom");
-        chars = ownedChars;
     }
 
-    return mozilla::HashString(chars, s->length());
+    return hash;
 }
 
 /* static */ HashNumber
 InefficientNonFlatteningStringHashPolicy::hash(const Lookup& l)
 {
     return l->hasLatin1Chars()
            ? HashStringChars<Latin1Char>(l)
            : HashStringChars<char16_t>(l);
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 #include "vm/StringType-inl.h"
 
 #include "mozilla/FloatingPoint.h"
+#include "mozilla/HashFunctions.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/RangedPtr.h"
 #include "mozilla/TextUtils.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Unused.h"
 
@@ -340,16 +341,63 @@ JSRope::copyCharsInternal(JSContext* cx,
     MOZ_ASSERT(end == out);
 
     if (nullTerminate)
         out[n] = 0;
 
     return true;
 }
 
+template <typename CharT>
+void AddStringToHash(uint32_t* hash, const CharT* chars, size_t len)
+{
+    // It's tempting to use |HashString| instead of this loop, but that's
+    // slightly different than our existing implementation for non-ropes. We
+    // want to pretend we have a contiguous set of chars so we need to
+    // accumulate char by char rather than generate a new hash for substring
+    // and then accumulate that.
+    for (size_t i = 0; i < len; i++) {
+        *hash = mozilla::AddToHash(*hash, chars[i]);
+    }
+}
+
+void AddStringToHash(uint32_t* hash, const JSString* str)
+{
+    AutoCheckCannotGC nogc;
+    const auto& s = str->asLinear();
+    if (s.hasLatin1Chars())
+        AddStringToHash(hash, s.latin1Chars(nogc), s.length());
+    else
+        AddStringToHash(hash, s.twoByteChars(nogc), s.length());
+}
+
+bool
+JSRope::hash(uint32_t* outHash) const
+{
+    Vector<const JSString*, 8, SystemAllocPolicy> nodeStack;
+    const JSString* str = this;
+
+    *outHash = 0;
+
+    while (true) {
+        if (str->isRope()) {
+            if (!nodeStack.append(str->asRope().rightChild()))
+                return false;
+            str = str->asRope().leftChild();
+        } else {
+            AddStringToHash(outHash, str);
+            if (nodeStack.empty())
+                break;
+            str = nodeStack.popCopy();
+        }
+    }
+
+    return true;
+}
+
 #ifdef DEBUG
 void
 JSRope::dumpRepresentation(js::GenericPrinter& out, int indent) const
 {
     dumpRepresentationHeader(out, "JSRope");
     indent += 2;
 
     out.printf("%*sleft:  ", indent, "");
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -695,16 +695,23 @@ class JSRope : public JSString
 
     bool copyLatin1CharsZ(JSContext* cx,
                           js::ScopedJSFreePtr<JS::Latin1Char>& out) const;
     bool copyTwoByteCharsZ(JSContext* cx, js::ScopedJSFreePtr<char16_t>& out) const;
 
     template <typename CharT>
     bool copyChars(JSContext* cx, js::ScopedJSFreePtr<CharT>& out) const;
 
+    // Hash function specific for ropes that avoids allocating a temporary
+    // string. There are still allocations internally so it's technically
+    // fallible.
+    //
+    // Returns the same value as if this were a linear string being hashed.
+    MOZ_MUST_USE bool hash(uint32_t* outhHash) const;
+
     JSString* leftChild() const {
         MOZ_ASSERT(isRope());
         return d.s.u2.left;
     }
 
     JSString* rightChild() const {
         MOZ_ASSERT(isRope());
         return d.s.u3.right;
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -301,19 +301,20 @@ SharedArrayRawBufferRefs::releaseAll()
 // Note that it contains a full JSStructuredCloneData object, which holds the
 // callbacks necessary to read/write/transfer/free the data. For the purpose of
 // this class, only the freeTransfer callback is relevant; the rest of the callbacks
 // are used by the higher-level JSStructuredCloneWriter interface.
 struct SCOutput {
   public:
     using Iter = BufferIterator<uint64_t, SystemAllocPolicy>;
 
-    explicit SCOutput(JSContext* cx);
+    SCOutput(JSContext* cx, JS::StructuredCloneScope scope);
 
     JSContext* context() const { return cx; }
+    JS::StructuredCloneScope scope() const { return buf.scope(); }
 
     MOZ_MUST_USE bool write(uint64_t u);
     MOZ_MUST_USE bool writePair(uint32_t tag, uint32_t data);
     MOZ_MUST_USE bool writeDouble(double d);
     MOZ_MUST_USE bool writeBytes(const void* p, size_t nbytes);
     MOZ_MUST_USE bool writeChars(const Latin1Char* p, size_t nchars);
     MOZ_MUST_USE bool writeChars(const char16_t* p, size_t nchars);
     MOZ_MUST_USE bool writePtr(const void*);
@@ -458,17 +459,17 @@ struct JSStructuredCloneReader {
 struct JSStructuredCloneWriter {
   public:
     explicit JSStructuredCloneWriter(JSContext* cx,
                                      JS::StructuredCloneScope scope,
                                      JS::CloneDataPolicy cloneDataPolicy,
                                      const JSStructuredCloneCallbacks* cb,
                                      void* cbClosure,
                                      const Value& tVal)
-        : out(cx), scope(scope), objs(out.context()),
+        : out(cx, scope), objs(out.context()),
           counts(out.context()), entries(out.context()),
           memory(out.context()),
           transferable(out.context(), tVal),
           transferableObjects(out.context(), GCHashSet<JSObject*>(cx)),
           cloneDataPolicy(cloneDataPolicy)
     {
         out.setCallbacks(cb, cbClosure, OwnTransferablePolicy::NoTransferables);
     }
@@ -486,18 +487,16 @@ struct JSStructuredCloneWriter {
     bool write(HandleValue v);
 
     SCOutput& output() { return out; }
 
     void extractBuffer(JSStructuredCloneData* newData) {
         out.extractBuffer(newData);
     }
 
-    JS::StructuredCloneScope cloneScope() const { return scope; }
-
   private:
     JSStructuredCloneWriter() = delete;
     JSStructuredCloneWriter(const JSStructuredCloneWriter&) = delete;
 
     JSContext* context() { return out.context(); }
 
     bool writeHeader();
     bool writeTransferMap();
@@ -519,19 +518,16 @@ struct JSStructuredCloneWriter {
 
     bool parseTransferable();
     bool transferOwnership();
 
     inline void checkStack();
 
     SCOutput out;
 
-    // The (address space, thread) scope within which this clone is valid.
-    JS::StructuredCloneScope scope;
-
     // Vector of objects with properties remaining to be written.
     //
     // NB: These can span multiple compartments, so the compartment must be
     // entered before any manipulation is performed.
     AutoValueVector objs;
 
     // counts[i] is the number of entries of objs[i] remaining to be written.
     // counts.length() == objs.length() and sum(counts) == entries.length().
@@ -628,91 +624,16 @@ ReadStructuredClone(JSContext* cx, JSStr
                     JS::StructuredCloneScope scope, MutableHandleValue vp,
                     const JSStructuredCloneCallbacks* cb, void* cbClosure)
 {
     SCInput in(cx, data);
     JSStructuredCloneReader r(in, scope, cb, cbClosure);
     return r.read(vp);
 }
 
-// If the given buffer contains Transferables, free them. Note that custom
-// Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to
-// delete their transferables.
-template<typename AllocPolicy>
-static void
-DiscardTransferables(mozilla::BufferList<AllocPolicy>& buffer,
-                     const JSStructuredCloneCallbacks* cb, void* cbClosure)
-{
-    auto point = BufferIterator<uint64_t, AllocPolicy>(buffer);
-    if (point.done())
-        return; // Empty buffer
-
-    uint32_t tag, data;
-    MOZ_RELEASE_ASSERT(point.canPeek());
-    SCInput::getPair(point.peek(), &tag, &data);
-    point.next();
-
-    if (tag == SCTAG_HEADER) {
-        if (point.done())
-            return;
-
-        MOZ_RELEASE_ASSERT(point.canPeek());
-        SCInput::getPair(point.peek(), &tag, &data);
-        point.next();
-    }
-
-    if (tag != SCTAG_TRANSFER_MAP_HEADER)
-        return;
-
-    if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
-        return;
-
-    // freeTransfer should not GC
-    JS::AutoSuppressGCAnalysis nogc;
-
-    if (point.done())
-        return;
-
-    uint64_t numTransferables = NativeEndian::swapFromLittleEndian(point.peek());
-    point.next();
-    while (numTransferables--) {
-        if (!point.canPeek())
-            return;
-
-        uint32_t ownership;
-        SCInput::getPair(point.peek(), &tag, &ownership);
-        point.next();
-        MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY);
-        if (!point.canPeek())
-            return;
-
-        void* content;
-        SCInput::getPtr(point.peek(), &content);
-        point.next();
-        if (!point.canPeek())
-            return;
-
-        uint64_t extraData = NativeEndian::swapFromLittleEndian(point.peek());
-        point.next();
-
-        if (ownership < JS::SCTAG_TMO_FIRST_OWNED)
-            continue;
-
-        if (ownership == JS::SCTAG_TMO_ALLOC_DATA) {
-            js_free(content);
-        } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) {
-            JS_ReleaseMappedArrayBufferContents(content, extraData);
-        } else if (cb && cb->freeTransfer) {
-            cb->freeTransfer(tag, JS::TransferableOwnership(ownership), content, extraData, cbClosure);
-        } else {
-            MOZ_ASSERT(false, "unknown ownership");
-        }
-    }
-}
-
 static bool
 StructuredCloneHasTransferObjects(const JSStructuredCloneData& data)
 {
     if (data.Size() < sizeof(uint64_t))
         return false;
 
     uint64_t u;
     BufferIterator<uint64_t, SystemAllocPolicy> iter(data);
@@ -892,18 +813,18 @@ SCInput::readPtr(void** p)
 {
     uint64_t u;
     if (!readNativeEndian(&u))
         return false;
     *p = reinterpret_cast<void*>(NativeEndian::swapFromLittleEndian(u));
     return true;
 }
 
-SCOutput::SCOutput(JSContext* cx)
-    : cx(cx)
+SCOutput::SCOutput(JSContext* cx, JS::StructuredCloneScope scope)
+  : cx(cx), buf(scope)
 {
 }
 
 bool
 SCOutput::write(uint64_t u)
 {
     uint64_t v = NativeEndian::swapToLittleEndian(u);
     if (!buf.AppendBytes(reinterpret_cast<char*>(&v), sizeof(u))) {
@@ -1014,23 +935,102 @@ void
 SCOutput::discardTransferables()
 {
     buf.discardTransferables();
 }
 
 } // namespace js
 
 
+// If the buffer contains Transferables, free them. Note that custom
+// Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to
+// delete their transferables.
 void
 JSStructuredCloneData::discardTransferables()
 {
     if (!Size())
         return;
-    if (ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
-        DiscardTransferables(bufList_, callbacks_, closure_);
+
+    if (ownTransferables_ != OwnTransferablePolicy::OwnsTransferablesIfAny)
+        return;
+
+    // DifferentProcess clones cannot contain pointers, so nothing needs to be
+    // released.
+    if (scope_ == JS::StructuredCloneScope::DifferentProcess)
+        return;
+
+    FreeTransferStructuredCloneOp freeTransfer = nullptr;
+    if (callbacks_)
+        freeTransfer = callbacks_->freeTransfer;
+
+    auto point = BufferIterator<uint64_t, SystemAllocPolicy>(*this);
+    if (point.done())
+        return; // Empty buffer
+
+    uint32_t tag, data;
+    MOZ_RELEASE_ASSERT(point.canPeek());
+    SCInput::getPair(point.peek(), &tag, &data);
+    point.next();
+
+    if (tag == SCTAG_HEADER) {
+        if (point.done())
+            return;
+
+        MOZ_RELEASE_ASSERT(point.canPeek());
+        SCInput::getPair(point.peek(), &tag, &data);
+        point.next();
+    }
+
+    if (tag != SCTAG_TRANSFER_MAP_HEADER)
+        return;
+
+    if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
+        return;
+
+    // freeTransfer should not GC
+    JS::AutoSuppressGCAnalysis nogc;
+
+    if (point.done())
+        return;
+
+    uint64_t numTransferables = NativeEndian::swapFromLittleEndian(point.peek());
+    point.next();
+    while (numTransferables--) {
+        if (!point.canPeek())
+            return;
+
+        uint32_t ownership;
+        SCInput::getPair(point.peek(), &tag, &ownership);
+        point.next();
+        MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY);
+        if (!point.canPeek())
+            return;
+
+        void* content;
+        SCInput::getPtr(point.peek(), &content);
+        point.next();
+        if (!point.canPeek())
+            return;
+
+        uint64_t extraData = NativeEndian::swapFromLittleEndian(point.peek());
+        point.next();
+
+        if (ownership < JS::SCTAG_TMO_FIRST_OWNED)
+            continue;
+
+        if (ownership == JS::SCTAG_TMO_ALLOC_DATA) {
+            js_free(content);
+        } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) {
+            JS_ReleaseMappedArrayBufferContents(content, extraData);
+        } else if (freeTransfer) {
+            freeTransfer(tag, JS::TransferableOwnership(ownership), content, extraData, closure_);
+        } else {
+            MOZ_ASSERT(false, "unknown ownership");
+        }
+    }
 }
 
 JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
 
 JSStructuredCloneWriter::~JSStructuredCloneWriter()
 {
     // Free any transferable data left lying around in the buffer
     if (out.count())
@@ -1255,17 +1255,17 @@ JSStructuredCloneWriter::writeSharedArra
                                   "SharedArrayBuffer");
         return false;
     }
 
     // We must not transmit SAB pointers (including for WebAssembly.Memory)
     // cross-process.  The cloneDataPolicy should have guarded against this;
     // since it did not then throw, with a very explicit message.
 
-    if (scope > JS::StructuredCloneScope::SameProcessDifferentThread) {
+    if (output().scope() > JS::StructuredCloneScope::SameProcessDifferentThread) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SHMEM_POLICY);
         return false;
     }
 
     Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
     SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject();
 
     if (!out.buf.refsHeld_.acquire(context(), rawbuf))
@@ -1600,17 +1600,17 @@ JSStructuredCloneWriter::startWrite(Hand
     }
 
     return reportDataCloneError(JS_SCERR_UNSUPPORTED_TYPE);
 }
 
 bool
 JSStructuredCloneWriter::writeHeader()
 {
-    return out.writePair(SCTAG_HEADER, (uint32_t)scope);
+    return out.writePair(SCTAG_HEADER, (uint32_t)output().scope());
 }
 
 bool
 JSStructuredCloneWriter::writeTransferMap()
 {
     if (transferableObjects.empty())
         return true;
 
@@ -1658,16 +1658,17 @@ JSStructuredCloneWriter::transferOwnersh
     MOZ_ASSERT(uint32_t(NativeEndian::swapFromLittleEndian(point.peek()) >> 32) == SCTAG_TRANSFER_MAP_HEADER);
     point++;
     MOZ_RELEASE_ASSERT(point.canPeek());
     MOZ_ASSERT(NativeEndian::swapFromLittleEndian(point.peek()) == transferableObjects.count());
     point++;
 
     JSContext* cx = context();
     RootedObject obj(cx);
+    JS::StructuredCloneScope scope = output().scope();
     for (auto tr = transferableObjects.all(); !tr.empty(); tr.popFront()) {
         obj = tr.front();
 
         uint32_t tag;
         JS::TransferableOwnership ownership;
         void* content;
         uint64_t extraData;
 
@@ -2804,17 +2805,17 @@ JS_StructuredClone(JSContext* cx, Handle
                 return false;
         }
     }
 
     return buf.read(cx, vp, callbacks, closure);
 }
 
 JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other)
-    : scope_(other.scope_)
+  : scope_(other.scope()), data_(other.scope())
 {
     data_.ownTransferables_ = other.data_.ownTransferables_;
     other.steal(&data_, &version_, &data_.callbacks_, &data_.closure_);
 }
 
 JSAutoStructuredCloneBuffer&
 JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other)
 {
@@ -2970,10 +2971,10 @@ JS_ObjectNotWritten(JSStructuredCloneWri
     w->memory.remove(w->memory.lookup(obj));
 
     return true;
 }
 
 JS_PUBLIC_API(JS::StructuredCloneScope)
 JS_GetStructuredCloneScope(JSStructuredCloneWriter* w)
 {
-    return w->cloneScope();
+    return w->output().scope();
 }
--- a/layout/forms/nsColorControlFrame.cpp
+++ b/layout/forms/nsColorControlFrame.cpp
@@ -135,18 +135,8 @@ nsColorControlFrame::AttributeChanged(in
                                                     aModType);
 }
 
 nsContainerFrame*
 nsColorControlFrame::GetContentInsertionFrame()
 {
   return this;
 }
-
-Element*
-nsColorControlFrame::GetPseudoElement(CSSPseudoElementType aType)
-{
-  if (aType == CSSPseudoElementType::mozColorSwatch) {
-    return mColorContent;
-  }
-
-  return nsContainerFrame::GetPseudoElement(aType);
-}
--- a/layout/forms/nsColorControlFrame.h
+++ b/layout/forms/nsColorControlFrame.h
@@ -42,18 +42,16 @@ public:
                                         uint32_t aFilter) override;
 
   // nsIFrame
   virtual nsresult AttributeChanged(int32_t  aNameSpaceID,
                                     nsAtom* aAttribute,
                                     int32_t  aModType) override;
   virtual nsContainerFrame* GetContentInsertionFrame() override;
 
-  virtual Element* GetPseudoElement(CSSPseudoElementType aType) override;
-
   // Refresh the color swatch, using associated input's value
   nsresult UpdateColor();
 
 private:
   explicit nsColorControlFrame(ComputedStyle* aStyle);
 
   nsCOMPtr<Element> mColorContent;
 };
--- a/layout/forms/nsMeterFrame.cpp
+++ b/layout/forms/nsMeterFrame.cpp
@@ -266,18 +266,8 @@ nsMeterFrame::ShouldUseNativeStyle() con
   return StyleDisplay()->mAppearance == NS_THEME_METERBAR &&
          !PresContext()->HasAuthorSpecifiedRules(this,
                                                  NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND) &&
          barFrame &&
          barFrame->StyleDisplay()->mAppearance == NS_THEME_METERCHUNK &&
          !PresContext()->HasAuthorSpecifiedRules(barFrame,
                                                  NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND);
 }
-
-Element*
-nsMeterFrame::GetPseudoElement(CSSPseudoElementType aType)
-{
-  if (aType == CSSPseudoElementType::mozMeterBar) {
-    return mBarDiv;
-  }
-
-  return nsContainerFrame::GetPseudoElement(aType);
-}
--- a/layout/forms/nsMeterFrame.h
+++ b/layout/forms/nsMeterFrame.h
@@ -67,18 +67,16 @@ public:
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   /**
    * Returns whether the frame and its child should use the native style.
    */
   bool ShouldUseNativeStyle() const;
 
-  virtual Element* GetPseudoElement(mozilla::CSSPseudoElementType aType) override;
-
 protected:
   // Helper function which reflow the anonymous div frame.
   void ReflowBarFrame(nsIFrame*                aBarFrame,
                       nsPresContext*           aPresContext,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus&          aStatus);
   /**
    * The div used to show the meter bar.
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -738,44 +738,15 @@ nsNumberControlFrame::AnonTextControlIsE
   if (!mTextField) {
     return true;
   }
   nsAutoString value;
   HTMLInputElement::FromNode(mTextField)->GetValue(value, CallerType::System);
   return value.IsEmpty();
 }
 
-Element*
-nsNumberControlFrame::GetPseudoElement(CSSPseudoElementType aType)
-{
-  if (aType == CSSPseudoElementType::mozNumberWrapper) {
-    return mOuterWrapper;
-  }
-
-  if (aType == CSSPseudoElementType::mozNumberText) {
-    return mTextField;
-  }
-
-  if (aType == CSSPseudoElementType::mozNumberSpinBox) {
-    // Might be null.
-    return mSpinBox;
-  }
-
-  if (aType == CSSPseudoElementType::mozNumberSpinUp) {
-    // Might be null.
-    return mSpinUp;
-  }
-
-  if (aType == CSSPseudoElementType::mozNumberSpinDown) {
-    // Might be null.
-    return mSpinDown;
-  }
-
-  return nsContainerFrame::GetPseudoElement(aType);
-}
-
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsNumberControlFrame::AccessibleType()
 {
   return a11y::eHTMLSpinnerType;
 }
 #endif
--- a/layout/forms/nsNumberControlFrame.h
+++ b/layout/forms/nsNumberControlFrame.h
@@ -152,18 +152,16 @@ public:
 
   void HandleFocusEvent(WidgetEvent* aEvent);
 
   /**
    * Our element had HTMLInputElement::Select() called on it.
    */
   void HandleSelectCall();
 
-  virtual Element* GetPseudoElement(CSSPseudoElementType aType) override;
-
   bool ShouldUseNativeStyleForSpinner() const;
 
 private:
 
   nsITextControlFrame* GetTextFieldFrame();
   nsresult MakeAnonymousElement(Element** aResult,
                                 nsTArray<ContentInfo>& aElements,
                                 nsAtom* aTagName,
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -279,18 +279,8 @@ nsProgressFrame::ShouldUseNativeStyle() 
   return StyleDisplay()->mAppearance == NS_THEME_PROGRESSBAR &&
          !PresContext()->HasAuthorSpecifiedRules(this,
                                                  NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND) &&
          barFrame &&
          barFrame->StyleDisplay()->mAppearance == NS_THEME_PROGRESSCHUNK &&
          !PresContext()->HasAuthorSpecifiedRules(barFrame,
                                                  NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND);
 }
-
-Element*
-nsProgressFrame::GetPseudoElement(CSSPseudoElementType aType)
-{
-  if (aType == CSSPseudoElementType::mozProgressBar) {
-    return mBarDiv;
-  }
-
-  return nsContainerFrame::GetPseudoElement(aType);
-}
--- a/layout/forms/nsProgressFrame.h
+++ b/layout/forms/nsProgressFrame.h
@@ -74,18 +74,16 @@ public:
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   /**
    * Returns whether the frame and its child should use the native style.
    */
   bool ShouldUseNativeStyle() const;
 
-  virtual Element* GetPseudoElement(CSSPseudoElementType aType) override;
-
 protected:
   // Helper function to reflow a child frame.
   void ReflowChildFrame(nsIFrame*          aChild,
                         nsPresContext*     aPresContext,
                         const ReflowInput& aReflowInput,
                         nsReflowStatus&    aStatus);
 
   /**
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -883,34 +883,16 @@ nsRangeFrame::ShouldUseNativeStyle() con
          progressFrame &&
          !PresContext()->HasAuthorSpecifiedRules(progressFrame,
                                                  STYLES_DISABLING_NATIVE_THEMING) &&
          thumbFrame &&
          !PresContext()->HasAuthorSpecifiedRules(thumbFrame,
                                                  STYLES_DISABLING_NATIVE_THEMING);
 }
 
-Element*
-nsRangeFrame::GetPseudoElement(CSSPseudoElementType aType)
-{
-  if (aType == CSSPseudoElementType::mozRangeTrack) {
-    return mTrackDiv;
-  }
-
-  if (aType == CSSPseudoElementType::mozRangeThumb) {
-    return mThumbDiv;
-  }
-
-  if (aType == CSSPseudoElementType::mozRangeProgress) {
-    return mProgressDiv;
-  }
-
-  return nsContainerFrame::GetPseudoElement(aType);
-}
-
 ComputedStyle*
 nsRangeFrame::GetAdditionalComputedStyle(int32_t aIndex) const
 {
   // We only implement this so that SetAdditionalComputedStyle will be
   // called if style changes that would change the -moz-focus-outer
   // pseudo-element have occurred.
   if (aIndex != 0) {
     return nullptr;
--- a/layout/forms/nsRangeFrame.h
+++ b/layout/forms/nsRangeFrame.h
@@ -144,18 +144,16 @@ public:
    * Helper that's used when the value of the range changes to reposition the
    * thumb, resize the range-progress element, and schedule a repaint. (This
    * does not reflow, since the position and size of the thumb and
    * range-progress element do not affect the position or size of any other
    * frames.)
    */
   void UpdateForValueChange();
 
-  virtual Element* GetPseudoElement(CSSPseudoElementType aType) override;
-
 private:
 
   nsresult MakeAnonymousDiv(Element** aResult,
                             CSSPseudoElementType aPseudoType,
                             nsTArray<ContentInfo>& aElements);
 
   // Helper function which reflows the anonymous div frames.
   void ReflowAnonymousContent(nsPresContext*           aPresContext,
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -1412,26 +1412,16 @@ nsTextControlFrame::BuildDisplayList(nsD
           (kid->GetContent() == mPreviewDiv &&
            !txtCtrl->GetPreviewVisibility()))) {
       BuildDisplayListForChild(aBuilder, kid, set, 0);
     }
     kid = kid->GetNextSibling();
   }
 }
 
-mozilla::dom::Element*
-nsTextControlFrame::GetPseudoElement(CSSPseudoElementType aType)
-{
-  if (aType == CSSPseudoElementType::placeholder) {
-    return mPlaceholderDiv;
-  }
-
-  return nsContainerFrame::GetPseudoElement(aType);
-}
-
 NS_IMETHODIMP
 nsTextControlFrame::EditorInitializer::Run()
 {
   if (!mFrame) {
     return NS_OK;
   }
 
   // Need to block script to avoid bug 669767.
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -124,19 +124,16 @@ public:
                                         uint32_t aFilter) override;
 
   virtual void SetInitialChildList(ChildListID     aListID,
                                    nsFrameList&    aChildList) override;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsDisplayListSet& aLists) override;
 
-  virtual mozilla::dom::Element*
-  GetPseudoElement(mozilla::CSSPseudoElementType aType) override;
-
 //==== BEGIN NSIFORMCONTROLFRAME
   virtual void SetFocus(bool aOn , bool aRepaint) override;
   virtual nsresult SetFormProperty(nsAtom* aName, const nsAString& aValue) override;
 
 //==== END NSIFORMCONTROLFRAME
 
 //==== NSITEXTCONTROLFRAME
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -11012,34 +11012,16 @@ nsIFrame::IsStackingContext()
 {
   const nsStyleDisplay* disp = StyleDisplay();
   bool isPositioned = disp->IsAbsPosContainingBlock(this);
   bool isVisuallyAtomic = IsVisuallyAtomic(EffectSet::GetEffectSet(this),
                                            disp, StyleEffects());
   return IsStackingContext(disp, StylePosition(), isPositioned, isVisuallyAtomic);
 }
 
-Element*
-nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
-{
-  if (!mContent) {
-    return nullptr;
-  }
-
-  if (aType == CSSPseudoElementType::before) {
-    return nsLayoutUtils::GetBeforePseudo(mContent);
-  }
-
-  if (aType == CSSPseudoElementType::after) {
-    return nsLayoutUtils::GetAfterPseudo(mContent);
-  }
-
-  return nullptr;
-}
-
 static bool
 IsFrameScrolledOutOfView(nsIFrame* aTarget,
                          const nsRect& aTargetRect,
                          nsIFrame* aParent)
 {
   nsIScrollableFrame* scrollableFrame =
     nsLayoutUtils::GetNearestScrollableFrame(aParent,
       nsLayoutUtils::SCROLLABLE_SAME_DOC |
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -4000,24 +4000,16 @@ public:
    * Return whether this frame keeps track of overflow areas. (Frames for
    * non-display SVG elements -- e.g. <clipPath> -- do not maintain overflow
    * areas, because they're never painted.)
    */
   bool FrameMaintainsOverflow() const {
     return !HasAllStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
   }
 
-  /**
-   * Returns the content node within the anonymous content that this frame
-   * generated and which corresponds to the specified pseudo-element type,
-   * or nullptr if there is no such anonymous content.
-   */
-  virtual mozilla::dom::Element*
-  GetPseudoElement(mozilla::CSSPseudoElementType aType);
-
   /*
    * @param aStyleDisplay:  If the caller has this->StyleDisplay(), providing
    *   it here will improve performance.
    */
   bool BackfaceIsHidden(const nsStyleDisplay* aStyleDisplay) const {
     MOZ_ASSERT(aStyleDisplay == StyleDisplay());
     return aStyleDisplay->BackfaceIsHidden();
   }
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-6e4b0141df2f
+c8ee333b84a0
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -33,17 +33,17 @@
 #include "cert.h"
 #include "cryptohi.h"
 #include "secoid.h"
 #include "certdb.h"
 #include "nss.h"
 #include "certutil.h"
 
 #define MIN_KEY_BITS 512
-/* MAX_KEY_BITS should agree with MAX_RSA_MODULUS in freebl */
+/* MAX_KEY_BITS should agree with RSA_MAX_MODULUS_BITS in freebl */
 #define MAX_KEY_BITS 8192
 #define DEFAULT_KEY_BITS 2048
 
 #define GEN_BREAK(e) \
     rv = e;          \
     break;
 
 char *progName;
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/cpputil/scoped_ptrs.h
+++ b/security/nss/cpputil/scoped_ptrs.h
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef scoped_ptrs_h__
 #define scoped_ptrs_h__
 
 #include <memory>
 #include "cert.h"
 #include "keyhi.h"
+#include "p12.h"
 #include "pk11pub.h"
 #include "pkcs11uri.h"
 #include "sslexp.h"
 
 struct ScopedDelete {
   void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
   void operator()(CERTCertificateList* list) {
     CERT_DestroyCertificateList(list);
@@ -36,16 +37,19 @@ struct ScopedDelete {
   }
   void operator()(PK11URI* uri) { PK11URI_DestroyURI(uri); }
   void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
   void operator()(PK11Context* context) { PK11_DestroyContext(context, true); }
   void operator()(PK11GenericObject* obj) { PK11_DestroyGenericObject(obj); }
   void operator()(SSLResumptionTokenInfo* token) {
     SSL_DestroyResumptionTokenInfo(token);
   }
+  void operator()(SEC_PKCS12DecoderContext* dcx) {
+    SEC_PKCS12DecoderFinish(dcx);
+  }
 };
 
 template <class T>
 struct ScopedMaybeDelete {
   void operator()(T* ptr) {
     if (ptr) {
       ScopedDelete del;
       del(ptr);
@@ -68,12 +72,13 @@ SCOPED(SECItem);
 SCOPED(SECKEYPublicKey);
 SCOPED(SECKEYPrivateKey);
 SCOPED(SECKEYPrivateKeyList);
 SCOPED(PK11URI);
 SCOPED(PLArenaPool);
 SCOPED(PK11Context);
 SCOPED(PK11GenericObject);
 SCOPED(SSLResumptionTokenInfo);
+SCOPED(SEC_PKCS12DecoderContext);
 
 #undef SCOPED
 
 #endif  // scoped_ptrs_h__
--- a/security/nss/fuzz/tls_client_target.cc
+++ b/security/nss/fuzz/tls_client_target.cc
@@ -82,25 +82,22 @@ static void SetupCallbacks(PRFileDesc* f
   SECStatus rv = SSL_AuthCertificateHook(fd, AuthCertificateHook, config);
   assert(rv == SECSuccess);
 
   rv = SSL_SetCanFalseStartCallback(fd, CanFalseStartCallback, nullptr);
   assert(rv == SECSuccess);
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
-  static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
+  std::unique_ptr<NSSDatabase> db(new NSSDatabase());
   assert(db != nullptr);
 
   EnableAllProtocolVersions();
   std::unique_ptr<ClientConfig> config(new ClientConfig(data, len));
 
-  // Clear the cache. We never want to resume as we couldn't reproduce that.
-  SSL_ClearSessionCache();
-
   // Reset the RNG state.
   assert(RNG_RandomUpdate(NULL, 0) == SECSuccess);
 
   // Create and import dummy socket.
   std::unique_ptr<DummyPrSocket> socket(new DummyPrSocket(data, len));
   static PRDescIdentity id = PR_GetUniqueIdentity("fuzz-client");
   ScopedPRFileDesc fd(DummyIOLayerMethods::CreateFD(id, socket.get()));
   PRFileDesc* ssl_fd = ImportFD(nullptr, fd.get());
@@ -109,16 +106,19 @@ extern "C" int LLVMFuzzerTestOneInput(co
   // Probably not too important for clients.
   SSL_SetURL(ssl_fd, "server");
 
   SetSocketOptions(ssl_fd, config);
   EnableAllCipherSuites(ssl_fd);
   SetupCallbacks(ssl_fd, config.get());
   DoHandshake(ssl_fd, false);
 
+  // Release all SIDs.
+  SSL_ClearSessionCache();
+
   return 0;
 }
 
 extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
                                           size_t max_size, unsigned int seed) {
   using namespace TlsMutators;
   return CustomMutate({DropRecord, ShuffleRecords, DuplicateRecord,
                        TruncateRecord, FragmentRecord},
--- a/security/nss/gtests/der_gtest/der_gtest.gyp
+++ b/security/nss/gtests/der_gtest/der_gtest.gyp
@@ -8,23 +8,26 @@
   ],
   'targets': [
     {
       'target_name': 'der_gtest',
       'type': 'executable',
       'sources': [
         'der_getint_unittest.cc',
         'der_quickder_unittest.cc',
+        'p12_import_unittest.cc',
         '<(DEPTH)/gtests/common/gtests.cc'
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
         '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
         '<(DEPTH)/lib/util/util.gyp:nssutil3',
         '<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
         '<(DEPTH)/lib/nss/nss.gyp:nss3',
+        '<(DEPTH)/lib/pkcs12/pkcs12.gyp:pkcs12',
+        '<(DEPTH)/lib/pkcs7/pkcs7.gyp:pkcs7',
       ]
     }
   ],
   'variables': {
     'module': 'nss'
   }
 }
--- a/security/nss/gtests/der_gtest/manifest.mn
+++ b/security/nss/gtests/der_gtest/manifest.mn
@@ -4,16 +4,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 CORE_DEPTH = ../..
 DEPTH      = ../..
 MODULE = nss
 
 CPPSRCS = \
       der_getint_unittest.cc \
       der_quickder_unittest.cc \
+      p12_import_unittest.cc \
       $(NULL)
 
 INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
             -I$(CORE_DEPTH)/gtests/common \
             -I$(CORE_DEPTH)/cpputil
 
 REQUIRES = nspr gtest
 
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/der_gtest/p12_import_unittest.cc
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "nss.h"
+#include "p12.h"
+
+#include "gtest/gtest.h"
+#include "scoped_ptrs.h"
+
+namespace nss_test {
+
+static const uint8_t cert_p12[] = {
+    0x30, 0x82, 0x0a, 0x1f, 0x02, 0x01, 0x03, 0x30, 0x82, 0x09, 0xe5, 0x06,
+    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
+    0x09, 0xd6, 0x04, 0x82, 0x09, 0xd2, 0x30, 0x82, 0x09, 0xce, 0x30, 0x82,
+    0x04, 0x42, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
+    0x06, 0xa0, 0x82, 0x04, 0x33, 0x30, 0x82, 0x04, 0x2f, 0x02, 0x01, 0x00,
+    0x30, 0x82, 0x04, 0x28, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x07, 0x01, 0x30, 0x57, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x05, 0x0d, 0x30, 0x4a, 0x30, 0x29, 0x06, 0x09, 0x2a, 0x86,
+    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x1c, 0x04, 0x08, 0x05,
+    0x66, 0xc7, 0x5c, 0x27, 0x4e, 0x15, 0xd9, 0x02, 0x02, 0x08, 0x00, 0x30,
+    0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x09, 0x05,
+    0x00, 0x30, 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
+    0x01, 0x2a, 0x04, 0x10, 0x4e, 0x61, 0xa7, 0x23, 0xc4, 0x3b, 0x37, 0xea,
+    0xba, 0xe9, 0x9f, 0x44, 0x8e, 0x5e, 0xf7, 0xf2, 0x80, 0x82, 0x03, 0xc0,
+    0x76, 0x7d, 0x91, 0x89, 0xe1, 0x04, 0x59, 0x91, 0x0c, 0x72, 0x14, 0x93,
+    0xc4, 0x37, 0xe8, 0xd1, 0xbb, 0x49, 0xfc, 0x23, 0x49, 0x19, 0x6f, 0xc9,
+    0x05, 0x08, 0x52, 0xd8, 0x63, 0xdf, 0x27, 0x63, 0x24, 0x85, 0x73, 0x11,
+    0xfa, 0x6d, 0xca, 0xed, 0xb2, 0x91, 0x77, 0xc6, 0x1f, 0x0b, 0xdb, 0x4d,
+    0x66, 0x34, 0xb9, 0x51, 0xef, 0xf0, 0x8f, 0xf8, 0x71, 0x2b, 0x68, 0xf7,
+    0x5c, 0xdf, 0x99, 0x21, 0x7c, 0xb6, 0xa7, 0x45, 0xdb, 0x71, 0x69, 0x0b,
+    0xb3, 0x2e, 0xff, 0x84, 0xcd, 0xd1, 0xb8, 0x87, 0xe9, 0xaa, 0x3e, 0xcd,
+    0x11, 0x90, 0xcb, 0xd8, 0xe7, 0x08, 0x87, 0x32, 0x82, 0x26, 0x69, 0x9b,
+    0xa6, 0xb1, 0x76, 0xf2, 0x28, 0xe2, 0x6c, 0xf5, 0x50, 0x16, 0x2d, 0x13,
+    0x75, 0x73, 0xed, 0xd1, 0x40, 0x1b, 0xd9, 0x43, 0xf5, 0x1d, 0x60, 0x98,
+    0x33, 0x5e, 0x18, 0xb0, 0xba, 0xe0, 0x8a, 0xaa, 0xa4, 0x3b, 0x78, 0x49,
+    0x59, 0x5f, 0xa4, 0xd5, 0xb5, 0x10, 0xb8, 0x87, 0x46, 0x48, 0xff, 0x5e,
+    0x91, 0x3b, 0xf9, 0xef, 0x29, 0x92, 0x99, 0xfd, 0x22, 0x8c, 0xcd, 0x05,
+    0x2e, 0x0a, 0x24, 0xbf, 0xe4, 0x1b, 0x95, 0x86, 0x94, 0xf2, 0xd9, 0x8c,
+    0x4d, 0xac, 0xe8, 0xb8, 0x49, 0x93, 0x74, 0xcd, 0x79, 0x3f, 0xa4, 0x29,
+    0x09, 0x5a, 0x00, 0x44, 0xfe, 0x75, 0x53, 0x23, 0x7e, 0xe4, 0xf5, 0x71,
+    0xcf, 0x1e, 0x48, 0x1d, 0x89, 0x42, 0x67, 0xa6, 0x1d, 0x0d, 0x0b, 0xe0,
+    0x4a, 0x7a, 0x59, 0xe0, 0x88, 0x63, 0xfc, 0x72, 0x97, 0xc2, 0x9f, 0x5d,
+    0xc3, 0xb2, 0x75, 0x73, 0x25, 0x10, 0x6f, 0x40, 0x93, 0x4f, 0x7d, 0x69,
+    0x01, 0x2d, 0xf4, 0xbe, 0xa9, 0xd9, 0x3c, 0x83, 0x77, 0x92, 0xf4, 0xa1,
+    0x2a, 0x7d, 0x3e, 0xab, 0x2d, 0xa1, 0x53, 0x63, 0x98, 0xaf, 0xc6, 0x11,
+    0x78, 0x3d, 0x37, 0xa9, 0x3f, 0x9c, 0xa8, 0xce, 0xc1, 0x9f, 0xac, 0x45,
+    0x9a, 0x2e, 0x38, 0x9f, 0x08, 0xf9, 0x2d, 0x9e, 0xf5, 0xca, 0x4d, 0x33,
+    0x77, 0x89, 0x2b, 0xde, 0x32, 0x05, 0xe4, 0x39, 0x1a, 0x78, 0x06, 0x7f,
+    0x74, 0x28, 0xab, 0x07, 0xbc, 0x59, 0xd0, 0x52, 0x11, 0x1b, 0x6a, 0x98,
+    0x51, 0xed, 0x5c, 0xf7, 0x96, 0x59, 0xad, 0xb1, 0x48, 0x81, 0xc8, 0xde,
+    0xec, 0xb0, 0x16, 0x7d, 0x61, 0x09, 0xaf, 0x36, 0xe8, 0x2d, 0xd3, 0x88,
+    0x99, 0x35, 0xf2, 0x72, 0xa5, 0xfd, 0xd9, 0xbe, 0xf5, 0x6d, 0x52, 0x4f,
+    0xdb, 0x65, 0x1b, 0x06, 0xfd, 0x1f, 0x61, 0xb3, 0xae, 0x03, 0x96, 0x50,
+    0x96, 0xc4, 0x74, 0x28, 0x26, 0xda, 0x51, 0xc2, 0xd4, 0xff, 0xce, 0xc5,
+    0x26, 0xea, 0x8c, 0xfd, 0x1e, 0x22, 0x03, 0xf0, 0xcd, 0x00, 0xf2, 0x72,
+    0xf3, 0x81, 0x46, 0x1e, 0x95, 0xaf, 0xe1, 0xc1, 0x0a, 0x12, 0xfe, 0xb0,
+    0x97, 0x2d, 0x40, 0xe8, 0x6d, 0xde, 0xe0, 0x9c, 0x7f, 0xad, 0x85, 0x89,
+    0x28, 0x88, 0x4a, 0x64, 0xc1, 0xa4, 0x2f, 0xb6, 0x25, 0xae, 0x89, 0xb4,
+    0xab, 0x02, 0xea, 0xca, 0xd6, 0x05, 0x4f, 0x3a, 0x64, 0xd0, 0xbf, 0x2d,
+    0xba, 0x0a, 0x9c, 0x5a, 0xa5, 0x0b, 0xf5, 0xc7, 0x84, 0x6e, 0xb4, 0x5c,
+    0x0e, 0x43, 0x96, 0xac, 0xfe, 0xc1, 0xc5, 0x3d, 0x15, 0x2b, 0x4d, 0x67,
+    0x2a, 0x09, 0xd8, 0x64, 0x83, 0x13, 0x00, 0x10, 0xe1, 0x60, 0x76, 0x9b,
+    0xf0, 0xa0, 0xdc, 0x8c, 0x4b, 0x4f, 0xc5, 0x93, 0xa8, 0xf8, 0xef, 0xd9,
+    0x75, 0xdc, 0x62, 0xe9, 0xcf, 0xdf, 0x3f, 0x7b, 0x8d, 0x2c, 0x0e, 0x5a,
+    0x99, 0xc6, 0x38, 0x4c, 0xd9, 0xfb, 0xe6, 0xb5, 0x1b, 0x6e, 0xbd, 0xae,
+    0xef, 0x89, 0x71, 0x4e, 0xfd, 0x74, 0x46, 0x35, 0xf9, 0x48, 0x43, 0x11,
+    0x81, 0xcd, 0x6f, 0xdc, 0xf3, 0x2e, 0x92, 0x93, 0x9e, 0xca, 0xf8, 0xfa,
+    0xc6, 0x56, 0x75, 0x1e, 0x04, 0x89, 0x7d, 0x1c, 0x2e, 0xdb, 0xbd, 0x5b,
+    0xec, 0xc8, 0x2d, 0xa3, 0xe2, 0x05, 0xef, 0xe9, 0x5f, 0x05, 0x4b, 0x89,
+    0x82, 0x0c, 0x1e, 0x8c, 0x74, 0xe1, 0x5a, 0x67, 0xe4, 0x97, 0x9b, 0x22,
+    0xd7, 0xdc, 0xe2, 0x74, 0xcf, 0x93, 0xc1, 0xca, 0xc6, 0xde, 0xae, 0xc0,
+    0xd2, 0xf9, 0x57, 0xc5, 0x90, 0x96, 0x48, 0x0a, 0x25, 0x43, 0x75, 0xc1,
+    0x94, 0xa4, 0xd5, 0x14, 0xb2, 0x27, 0xf8, 0x45, 0xf1, 0x3c, 0x01, 0xd6,
+    0xb8, 0x73, 0x1c, 0xb6, 0x55, 0xc5, 0xc9, 0x10, 0x28, 0x2f, 0xba, 0x18,
+    0x36, 0x8d, 0xfe, 0x0b, 0x23, 0xf3, 0x9a, 0x98, 0xfb, 0x2f, 0x59, 0x52,
+    0x3a, 0x0f, 0x75, 0x60, 0xa0, 0x92, 0x0d, 0x78, 0xf0, 0xc7, 0x5d, 0x9d,
+    0x3a, 0x72, 0xd0, 0xd1, 0x30, 0x73, 0x9e, 0x3c, 0x03, 0x99, 0x4c, 0xe2,
+    0xe5, 0xd4, 0x77, 0xfe, 0x3a, 0x92, 0x08, 0x5b, 0x99, 0x51, 0x15, 0x57,
+    0x05, 0x13, 0x51, 0xc2, 0xf4, 0xb5, 0x2d, 0xae, 0x68, 0x9f, 0x4e, 0xbf,
+    0x00, 0x11, 0xc1, 0xe1, 0x48, 0xb3, 0xce, 0x36, 0x42, 0x6a, 0x74, 0xd7,
+    0xe7, 0x84, 0x1e, 0xf3, 0x47, 0xc4, 0xab, 0x59, 0x18, 0x15, 0x31, 0xa4,
+    0x28, 0x68, 0x16, 0xa3, 0x68, 0xbf, 0x6c, 0xfe, 0x7a, 0x36, 0xd9, 0xc1,
+    0x22, 0xd6, 0x5e, 0x2d, 0xbb, 0x9a, 0x1f, 0xb6, 0x8c, 0xa6, 0x65, 0x24,
+    0x3e, 0x01, 0x9c, 0x75, 0x5e, 0x17, 0x42, 0x12, 0x89, 0x85, 0x6f, 0x05,
+    0xac, 0x54, 0xd5, 0x02, 0xea, 0x1e, 0xc2, 0xe1, 0xcd, 0x61, 0x0e, 0x53,
+    0xd5, 0x9d, 0x3a, 0x67, 0x1b, 0x50, 0x9b, 0x90, 0x18, 0x66, 0x6d, 0xb2,
+    0x7f, 0x3a, 0x69, 0xc9, 0xef, 0x07, 0x17, 0x91, 0x8a, 0xe9, 0x15, 0x35,
+    0xed, 0x70, 0x9e, 0x74, 0x8c, 0xe7, 0xf4, 0xaa, 0xcf, 0xbe, 0xa3, 0x98,
+    0x89, 0x8d, 0x3c, 0x5e, 0xa4, 0x6b, 0x8f, 0x1b, 0x18, 0x04, 0x79, 0xd2,
+    0x11, 0x64, 0xb1, 0xc7, 0x68, 0xca, 0xaf, 0x44, 0xa1, 0x39, 0x29, 0x58,
+    0x70, 0x4e, 0xce, 0xb7, 0x7a, 0x3c, 0x4b, 0xdc, 0x32, 0x92, 0x76, 0x74,
+    0xab, 0x0a, 0x6f, 0x8b, 0x74, 0xf5, 0xfd, 0xed, 0x3b, 0x11, 0x95, 0xe8,
+    0x10, 0x74, 0x4c, 0xd8, 0xbe, 0x0f, 0x50, 0xee, 0xa0, 0xee, 0x39, 0xd8,
+    0x9f, 0xa1, 0xa0, 0x21, 0xa3, 0x47, 0x8c, 0xa6, 0xd9, 0xca, 0x8c, 0xb3,
+    0x8b, 0x86, 0x9e, 0x31, 0x3b, 0xcc, 0x7f, 0xea, 0x23, 0xb1, 0x25, 0x73,
+    0xfb, 0x66, 0x99, 0x28, 0xff, 0xf4, 0xe9, 0xb7, 0x19, 0x3e, 0xd5, 0xc6,
+    0x5d, 0xd1, 0xaa, 0x08, 0x6f, 0xf2, 0xff, 0xab, 0x39, 0x69, 0x1f, 0xd3,
+    0x6b, 0x20, 0xf3, 0x2f, 0xe4, 0xd5, 0xb8, 0x76, 0x3f, 0x6c, 0x8f, 0x05,
+    0x3c, 0xe0, 0x18, 0x81, 0x82, 0xca, 0x05, 0x7f, 0xc0, 0x8e, 0x87, 0x50,
+    0xfb, 0xb1, 0x65, 0xfa, 0x2f, 0xb7, 0xba, 0x20, 0x0b, 0x35, 0x5c, 0x87,
+    0xba, 0x90, 0x5a, 0x7f, 0xfc, 0xe9, 0xf2, 0x98, 0x5f, 0x6e, 0xb2, 0xcc,
+    0xef, 0x4b, 0x2d, 0xde, 0xdd, 0x6f, 0xd9, 0x8e, 0x79, 0x89, 0x45, 0xcd,
+    0x4c, 0xdf, 0x27, 0xf1, 0x26, 0x47, 0x9e, 0x83, 0xdb, 0x73, 0x4a, 0x20,
+    0x84, 0xde, 0x09, 0xe0, 0x58, 0xfe, 0x19, 0xcb, 0x92, 0xc4, 0x5b, 0x83,
+    0x30, 0x82, 0x05, 0x84, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x07, 0x01, 0xa0, 0x82, 0x05, 0x75, 0x04, 0x82, 0x05, 0x71, 0x30,
+    0x82, 0x05, 0x6d, 0x30, 0x82, 0x05, 0x69, 0x06, 0x0b, 0x2a, 0x86, 0x48,
+    0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x05, 0x31,
+    0x30, 0x82, 0x05, 0x2d, 0x30, 0x57, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x05, 0x0d, 0x30, 0x4a, 0x30, 0x29, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x1c, 0x04, 0x08,
+    0x5c, 0x72, 0x5e, 0xfb, 0xbc, 0x49, 0xaa, 0xa1, 0x02, 0x02, 0x08, 0x00,
+    0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x09,
+    0x05, 0x00, 0x30, 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+    0x04, 0x01, 0x2a, 0x04, 0x10, 0xcb, 0xa8, 0xda, 0x75, 0xba, 0x64, 0x22,
+    0x70, 0x39, 0x3c, 0x83, 0x35, 0x0b, 0x41, 0xc4, 0x49, 0x04, 0x82, 0x04,
+    0xd0, 0xb3, 0x3d, 0x9b, 0x03, 0x34, 0xdf, 0x62, 0x37, 0xb0, 0xbb, 0x37,
+    0x0d, 0x88, 0x8c, 0x6b, 0xf2, 0x46, 0x33, 0xa4, 0x4b, 0x48, 0x86, 0x0a,
+    0x36, 0x37, 0x24, 0x21, 0x08, 0x8e, 0x86, 0xbf, 0x4e, 0x9c, 0xe7, 0xa9,
+    0x56, 0x4a, 0x02, 0xb4, 0x74, 0x6a, 0x8a, 0x1e, 0x51, 0x91, 0xe3, 0x8f,
+    0xe3, 0xf6, 0xca, 0x0a, 0x2d, 0xe7, 0x09, 0x5e, 0x1e, 0x59, 0x46, 0x01,
+    0xda, 0xe9, 0x5b, 0xb9, 0xd8, 0x15, 0x7c, 0x05, 0xd9, 0x5f, 0x8c, 0x3d,
+    0xd4, 0xb2, 0xff, 0x25, 0x9d, 0xfe, 0x0e, 0xe3, 0x0c, 0xf0, 0x7f, 0x30,
+    0x25, 0x92, 0x0e, 0x44, 0xf4, 0x16, 0xc7, 0xa2, 0x22, 0xb2, 0x31, 0xfa,
+    0x55, 0x97, 0xf7, 0xd0, 0xd7, 0x58, 0x1f, 0x96, 0x81, 0x06, 0x86, 0xbb,
+    0x07, 0x30, 0x9d, 0x01, 0xb8, 0x15, 0xb2, 0x81, 0xa9, 0x35, 0x09, 0x2c,
+    0x97, 0xbc, 0x8e, 0x2e, 0x2e, 0x30, 0x20, 0x51, 0x94, 0x9d, 0x9f, 0xbd,
+    0x83, 0x48, 0x7b, 0x25, 0xfc, 0x95, 0x42, 0xd7, 0x29, 0xd5, 0x67, 0xcd,
+    0x48, 0xc6, 0x78, 0xe1, 0x6d, 0xdf, 0xf8, 0x0b, 0x3a, 0x95, 0xcc, 0xd0,
+    0x93, 0xfe, 0x23, 0x8d, 0x99, 0xd9, 0x8c, 0x67, 0x38, 0x9f, 0xd0, 0x4c,
+    0xff, 0x32, 0x45, 0x32, 0xa9, 0xe8, 0x9d, 0xbc, 0xbf, 0xaa, 0xb2, 0x49,
+    0xaa, 0x1d, 0xa0, 0x04, 0x53, 0x14, 0xa4, 0x77, 0x96, 0x3f, 0x17, 0xbb,
+    0x2e, 0x14, 0xbe, 0x39, 0x6b, 0x69, 0x16, 0x7a, 0x99, 0xb2, 0xf4, 0x16,
+    0x1a, 0xb7, 0xaa, 0x0a, 0x97, 0xd9, 0x1d, 0x62, 0xbe, 0xfc, 0x38, 0x00,
+    0x6c, 0x65, 0x75, 0xe0, 0xb0, 0x65, 0x8f, 0xb6, 0x4b, 0xe7, 0x21, 0x41,
+    0x65, 0x65, 0x5a, 0x7c, 0x5b, 0xe8, 0x70, 0x83, 0x71, 0xd6, 0x65, 0x7c,
+    0x4f, 0x00, 0x90, 0x55, 0xca, 0xff, 0xc9, 0x3f, 0x61, 0x1e, 0xc0, 0x41,
+    0x67, 0x0c, 0x71, 0xb2, 0xef, 0x12, 0x8e, 0xb1, 0xaa, 0xcf, 0xf1, 0x78,
+    0x9f, 0x5b, 0xb9, 0x7b, 0xbe, 0x04, 0x39, 0xf0, 0x87, 0xca, 0x3a, 0x77,
+    0x31, 0xab, 0x85, 0x8f, 0x4f, 0x06, 0xad, 0x45, 0xf2, 0xe2, 0xc2, 0x20,
+    0x74, 0xf1, 0xdc, 0x21, 0x3f, 0x79, 0x0d, 0xcc, 0xcf, 0x7f, 0xb9, 0x85,
+    0x9e, 0x1a, 0x1b, 0x84, 0xe2, 0x5b, 0xe3, 0x77, 0x27, 0x91, 0xcc, 0xf2,
+    0xe4, 0xf2, 0x19, 0xdd, 0x98, 0x64, 0x9d, 0xcb, 0xf1, 0xc5, 0xe6, 0x7b,
+    0x75, 0x55, 0x4e, 0xa5, 0xca, 0xe3, 0x5b, 0xbe, 0xc2, 0xcd, 0x83, 0x27,
+    0x92, 0xe1, 0x23, 0x3f, 0xd7, 0x3d, 0xb7, 0x3a, 0x8b, 0x3a, 0x26, 0xc1,
+    0xfb, 0xed, 0x69, 0x7a, 0xab, 0xec, 0x0a, 0xe5, 0xaa, 0x81, 0x9f, 0xdf,
+    0x97, 0x45, 0x64, 0x35, 0x7d, 0xad, 0x88, 0x4a, 0x75, 0x13, 0xc3, 0x13,
+    0xd6, 0x9a, 0xf3, 0xa2, 0x94, 0xf7, 0x96, 0x09, 0xa7, 0xbe, 0xb8, 0xe4,
+    0x29, 0x7d, 0xb0, 0xef, 0x4a, 0x5d, 0x0d, 0x02, 0xb4, 0x10, 0x54, 0x17,
+    0x62, 0xef, 0xe2, 0xad, 0x89, 0x6d, 0x91, 0x51, 0x7e, 0x35, 0x28, 0xb4,
+    0xe7, 0x02, 0xbb, 0xcb, 0x03, 0x37, 0xa6, 0xeb, 0x55, 0x51, 0xc0, 0xc2,
+    0x21, 0x7a, 0x78, 0x44, 0x44, 0x70, 0x06, 0xb0, 0x5d, 0x19, 0xaa, 0xcb,
+    0xf1, 0x9f, 0xaa, 0xd3, 0x5a, 0x29, 0xc4, 0xc7, 0x7a, 0x36, 0x1d, 0x65,
+    0x21, 0x52, 0xf9, 0xe2, 0xc7, 0x60, 0xd4, 0x32, 0x03, 0xdf, 0x03, 0xcc,
+    0xe5, 0x7c, 0xf9, 0x15, 0xe3, 0xe6, 0x46, 0xeb, 0xa8, 0xa8, 0x6f, 0xe7,
+    0x46, 0x03, 0xc7, 0x5c, 0x29, 0xf6, 0xac, 0x61, 0x2d, 0xbe, 0xa0, 0xda,
+    0xdc, 0xca, 0x29, 0x35, 0x3b, 0xa0, 0x43, 0x22, 0x22, 0x61, 0x65, 0x8f,
+    0x2d, 0x13, 0xce, 0x61, 0x7c, 0x27, 0x45, 0x9d, 0x9b, 0x8d, 0xd6, 0xc1,
+    0xb5, 0x8c, 0x5b, 0xdb, 0xbb, 0xf6, 0x7e, 0x9a, 0xd4, 0x5c, 0x6b, 0x7e,
+    0xf3, 0x6d, 0x7e, 0x45, 0x2e, 0x55, 0x7d, 0x9f, 0x62, 0xc7, 0xf4, 0x03,
+    0x6f, 0xb9, 0x02, 0xcf, 0x3d, 0x07, 0xc5, 0xc8, 0xce, 0x9e, 0xac, 0x56,
+    0x43, 0x8b, 0xcc, 0xf0, 0x2d, 0xc5, 0x56, 0xfa, 0x61, 0xf9, 0xee, 0x1b,
+    0x89, 0xa9, 0xd6, 0xe8, 0x1e, 0xa2, 0xdf, 0xfd, 0x0d, 0x33, 0x03, 0x91,
+    0xd9, 0x30, 0x4d, 0xfb, 0x2d, 0x7e, 0x5b, 0xb0, 0xb5, 0x55, 0x1e, 0x9c,
+    0x13, 0x96, 0x5a, 0xa6, 0xab, 0x88, 0x79, 0xe7, 0x42, 0x31, 0xb2, 0x2d,
+    0xf8, 0x40, 0x89, 0xe4, 0x96, 0x4c, 0x42, 0xc9, 0x72, 0xd1, 0x8f, 0x3f,
+    0x2d, 0xee, 0x1d, 0x91, 0xe0, 0xfb, 0x1f, 0xb5, 0x94, 0x41, 0xce, 0x89,
+    0xed, 0xe7, 0xec, 0xa0, 0xb6, 0xb2, 0xa2, 0x5c, 0x72, 0xa1, 0x91, 0x40,
+    0x82, 0xde, 0x62, 0xba, 0x12, 0x12, 0xa1, 0xab, 0x31, 0x62, 0x38, 0x48,
+    0x4c, 0x49, 0x9e, 0x6c, 0xf3, 0xf1, 0x69, 0x3e, 0x8b, 0x6a, 0x24, 0x45,
+    0x99, 0x5c, 0x5a, 0xe3, 0x52, 0x24, 0xb7, 0xcf, 0xf0, 0xc8, 0x82, 0x5e,
+    0x9e, 0x10, 0x29, 0xcf, 0xda, 0x01, 0xd0, 0xc0, 0x81, 0xfd, 0x56, 0x15,
+    0x1c, 0x6b, 0xff, 0x78, 0x91, 0xaa, 0x47, 0x63, 0xb0, 0xe2, 0xbd, 0x67,
+    0x0d, 0x24, 0xc5, 0xfd, 0x1a, 0x6a, 0x6a, 0x71, 0x9b, 0xca, 0xc4, 0xb3,
+    0xc0, 0x07, 0x3d, 0xd7, 0x3b, 0xf4, 0xc0, 0xb7, 0xb5, 0xc4, 0x46, 0x85,
+    0x3d, 0x22, 0x03, 0x1b, 0xcf, 0xe6, 0xce, 0x2f, 0xae, 0x41, 0xcf, 0x67,
+    0x6b, 0xd3, 0x87, 0x3f, 0xca, 0x4c, 0xb7, 0x9f, 0x47, 0x36, 0xa5, 0xd7,
+    0xd3, 0x70, 0xf7, 0xc4, 0x9f, 0x7d, 0xbd, 0xe4, 0xc6, 0xec, 0x7b, 0x03,
+    0xca, 0xb0, 0x78, 0x06, 0xa3, 0xf1, 0xd0, 0x98, 0xdf, 0x1c, 0x60, 0x90,
+    0x61, 0xcb, 0x7b, 0x68, 0xd2, 0x8e, 0x24, 0x76, 0x7b, 0xf6, 0x2f, 0xf3,
+    0x7b, 0x96, 0x2d, 0x80, 0x6f, 0xae, 0xc5, 0x2b, 0xe9, 0xad, 0x78, 0x25,
+    0x78, 0x4e, 0xd7, 0x81, 0xb7, 0x60, 0x20, 0x0c, 0x20, 0x46, 0xb4, 0x88,
+    0xfe, 0x12, 0x0a, 0x8d, 0x7a, 0x9a, 0x0b, 0xdd, 0x6d, 0x37, 0xb3, 0xa5,
+    0x99, 0x1d, 0xf2, 0xd4, 0xa6, 0x79, 0x1e, 0x89, 0x1a, 0xda, 0xe8, 0x83,
+    0x24, 0xc9, 0xd9, 0x1f, 0x76, 0x82, 0xec, 0x64, 0x35, 0x6b, 0x9b, 0xfd,
+    0x91, 0x31, 0x96, 0xf2, 0x8b, 0x4f, 0x30, 0xbb, 0xd9, 0xcd, 0xe0, 0x66,
+    0x73, 0xfd, 0xd7, 0x05, 0x16, 0x7c, 0xed, 0x94, 0xc0, 0xa0, 0x73, 0x9e,
+    0xe7, 0x85, 0xac, 0x0e, 0x20, 0xd1, 0x5e, 0x66, 0x7a, 0xef, 0x93, 0x20,
+    0xd7, 0x3f, 0xb5, 0xbd, 0xb7, 0xb7, 0xcb, 0x64, 0xc8, 0xde, 0x2f, 0xd9,
+    0x92, 0x5f, 0xa1, 0xb6, 0xbd, 0xd0, 0xe6, 0xb4, 0x55, 0xf4, 0xa1, 0xa8,
+    0x51, 0x5e, 0x00, 0x6f, 0xaa, 0x09, 0xff, 0x56, 0xb4, 0xbc, 0xdf, 0xc1,
+    0x20, 0x13, 0xc4, 0x3c, 0x48, 0xb1, 0x6d, 0xeb, 0x19, 0xb8, 0xbf, 0x4f,
+    0x3d, 0x35, 0x96, 0x14, 0xc3, 0xc3, 0xef, 0x8e, 0x0b, 0x95, 0xbc, 0x78,
+    0x47, 0x6a, 0x6c, 0x24, 0x10, 0xbd, 0x06, 0x13, 0x5c, 0x69, 0x7b, 0xb5,
+    0x53, 0x43, 0xd1, 0x7a, 0x1d, 0x9a, 0x7f, 0x57, 0xcd, 0x81, 0xc5, 0x3f,
+    0xde, 0x98, 0xb5, 0x73, 0x95, 0xd2, 0x10, 0xcf, 0x4f, 0x6a, 0xce, 0xac,
+    0x35, 0x49, 0x4d, 0xf3, 0xbe, 0xbf, 0x38, 0xf2, 0xcf, 0x1b, 0x1c, 0x19,
+    0x27, 0xa3, 0x3f, 0xd9, 0x35, 0xfe, 0xc2, 0xe5, 0x49, 0x16, 0x28, 0xd0,
+    0x8e, 0xb9, 0x34, 0x6e, 0x8b, 0xa5, 0xe2, 0x9c, 0xbe, 0xad, 0xa1, 0x43,
+    0x61, 0x2e, 0x48, 0x65, 0xb3, 0x20, 0xe7, 0x1d, 0x65, 0x00, 0x9d, 0x6e,
+    0x71, 0xe7, 0x79, 0x44, 0xac, 0x0c, 0x38, 0x5a, 0x1d, 0x40, 0x06, 0x30,
+    0xd0, 0xe8, 0xbe, 0x95, 0x16, 0xaf, 0xd8, 0x5f, 0x67, 0xd3, 0xb0, 0x6a,
+    0xa3, 0x7c, 0xc1, 0x9b, 0x3f, 0xc7, 0xae, 0x27, 0xb1, 0xc1, 0xb5, 0xce,
+    0xdf, 0xbb, 0xa4, 0x4f, 0xb4, 0x58, 0xa1, 0xb9, 0x7c, 0x9c, 0x5f, 0x26,
+    0x4f, 0x13, 0xfa, 0x7c, 0x1a, 0xb7, 0x1b, 0x69, 0xd6, 0x0e, 0x1b, 0x92,
+    0x31, 0x4b, 0xb4, 0x71, 0x12, 0xc8, 0xc4, 0xbd, 0x99, 0xe3, 0xc8, 0x9d,
+    0x68, 0xb3, 0x38, 0x35, 0x3f, 0x16, 0xd8, 0xde, 0x01, 0x71, 0xf6, 0x66,
+    0x77, 0xcb, 0xbd, 0xe2, 0x97, 0x10, 0x91, 0x41, 0x00, 0xa1, 0x0d, 0x9d,
+    0x40, 0x0b, 0xfc, 0x25, 0xc8, 0x44, 0xc3, 0x78, 0xaa, 0x89, 0xd5, 0x59,
+    0xe4, 0xa2, 0x9e, 0xd0, 0x85, 0xa2, 0xdd, 0x80, 0x3b, 0x35, 0x5a, 0x50,
+    0x86, 0xcd, 0x72, 0xf4, 0x9d, 0x69, 0x0e, 0x2d, 0x97, 0x42, 0x09, 0x5e,
+    0xa6, 0x86, 0xf7, 0x35, 0xcf, 0x9b, 0x42, 0xa7, 0x60, 0xa0, 0x71, 0x41,
+    0x28, 0x35, 0x22, 0xd6, 0x55, 0xe1, 0xdb, 0xb3, 0x8e, 0x0d, 0x47, 0xb7,
+    0xd6, 0x02, 0x0f, 0xb1, 0xdf, 0xb8, 0xfb, 0xd8, 0x20, 0xcf, 0x6a, 0x47,
+    0x3f, 0x8a, 0x91, 0x08, 0x64, 0x08, 0xba, 0x19, 0x10, 0x1f, 0xcf, 0xe5,
+    0x34, 0xf1, 0x32, 0x49, 0x3b, 0xaf, 0x18, 0x67, 0x96, 0x47, 0x7f, 0x21,
+    0x8a, 0x37, 0x15, 0x5c, 0xc0, 0xe8, 0x7b, 0xd6, 0x08, 0x5b, 0x45, 0x10,
+    0x1f, 0x1c, 0x7f, 0xce, 0x3b, 0x88, 0xe5, 0x0e, 0xd9, 0x00, 0xce, 0xe5,
+    0x9b, 0x4b, 0x25, 0xc7, 0x11, 0x8a, 0x4f, 0x22, 0xa7, 0x31, 0x25, 0x30,
+    0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15,
+    0x31, 0x16, 0x04, 0x14, 0xad, 0x7f, 0xeb, 0xe6, 0xb2, 0x6c, 0xf4, 0xdc,
+    0x9f, 0x4d, 0x52, 0x40, 0x07, 0x15, 0xd9, 0xe8, 0xbc, 0x0d, 0x4e, 0xd7,
+    0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
+    0x1a, 0x05, 0x00, 0x04, 0x14, 0xa4, 0xac, 0xdb, 0xa8, 0x4c, 0xe9, 0x7a,
+    0x02, 0x9d, 0x07, 0x39, 0x21, 0xf0, 0x71, 0xae, 0x46, 0x5a, 0xd8, 0x13,
+    0x51, 0x04, 0x08, 0xa1, 0x52, 0xdd, 0x64, 0x46, 0xe9, 0x9e, 0x3e, 0x02,
+    0x02, 0x08, 0x00};
+
+class PK12ImportTest : public ::testing::Test {};
+
+TEST_F(PK12ImportTest, ImportPK12With2P7) {
+  SECItem password = {siBuffer, nullptr, 0};
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ScopedSEC_PKCS12DecoderContext dcx(
+      SEC_PKCS12DecoderStart(&password, slot.get(), nullptr, nullptr, nullptr,
+                             nullptr, nullptr, nullptr));
+  ASSERT_TRUE(dcx);
+  SECStatus rv = SEC_PKCS12DecoderUpdate(
+      dcx.get(), const_cast<uint8_t *>(cert_p12), sizeof(cert_p12));
+  ASSERT_EQ(SECSuccess, rv);
+  rv = SEC_PKCS12DecoderVerify(dcx.get());
+  // NSS can't properly decode this P12. But it shouldn't crash.
+  ASSERT_EQ(SECFailure, rv);
+}
+
+}  // namespace nss_test
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/rsa8193.h
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+//  openssl req -nodes -x509 -newkey rsa:8193 -out cert.pem -days 365
+static const uint8_t rsa8193[] = {
+    0x30, 0x82, 0x09, 0x61, 0x30, 0x82, 0x05, 0x48, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x09, 0x00, 0xaf, 0xff, 0x37, 0x91, 0x3e, 0x44, 0xae, 0x57,
+    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+    0x0b, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+    0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+    0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+    0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
+    0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+    0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
+    0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x35, 0x31, 0x37,
+    0x30, 0x39, 0x34, 0x32, 0x32, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x30,
+    0x35, 0x31, 0x37, 0x30, 0x39, 0x34, 0x32, 0x32, 0x39, 0x5a, 0x30, 0x45,
+    0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
+    0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a,
+    0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
+    0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74,
+    0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
+    0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x82, 0x04,
+    0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+    0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x04, 0x0f, 0x00, 0x30, 0x82, 0x04,
+    0x0a, 0x02, 0x82, 0x04, 0x01, 0x01, 0x77, 0xd6, 0xa9, 0x93, 0x4e, 0x15,
+    0xb5, 0x67, 0x70, 0x8e, 0xc3, 0x77, 0x4f, 0xc9, 0x8a, 0x06, 0xd9, 0xb9,
+    0xa6, 0x41, 0xb8, 0xfa, 0x4a, 0x13, 0x26, 0xdc, 0x2b, 0xc5, 0x82, 0xa0,
+    0x74, 0x8c, 0x1e, 0xe9, 0xc0, 0x70, 0x15, 0x56, 0xec, 0x1f, 0x7e, 0x91,
+    0x6e, 0x31, 0x42, 0x8b, 0xd5, 0xe2, 0x0e, 0x9c, 0xeb, 0xff, 0xbc, 0xf9,
+    0x42, 0xd3, 0xb9, 0x1c, 0x5e, 0x46, 0x80, 0x90, 0x5f, 0xe1, 0x59, 0x22,
+    0x13, 0x71, 0xd3, 0xd6, 0x66, 0x7a, 0xe0, 0x56, 0x04, 0x10, 0x59, 0x01,
+    0xb3, 0xb6, 0xd2, 0xc7, 0xa7, 0x3b, 0xbc, 0xe6, 0x38, 0x44, 0xd5, 0x71,
+    0x66, 0x1d, 0xb2, 0x63, 0x2f, 0xa9, 0x5e, 0x80, 0x92, 0x3c, 0x21, 0x0e,
+    0xe1, 0xda, 0xd6, 0x1d, 0xcb, 0xce, 0xac, 0xe1, 0x5f, 0x97, 0x45, 0x8f,
+    0xc1, 0x64, 0x16, 0xa6, 0x88, 0x2a, 0x36, 0x4a, 0x76, 0x64, 0x8f, 0x83,
+    0x7a, 0x1d, 0xd8, 0x91, 0x90, 0x7b, 0x58, 0xb8, 0x1c, 0x7f, 0x56, 0x57,
+    0x35, 0xfb, 0xf3, 0x1a, 0xcb, 0x7c, 0x66, 0x66, 0x04, 0x95, 0xee, 0x3a,
+    0x80, 0xf0, 0xd4, 0x12, 0x3a, 0x7e, 0x7e, 0x5e, 0xb8, 0x55, 0x29, 0x23,
+    0x06, 0xd3, 0x85, 0x0c, 0x99, 0x91, 0x42, 0xee, 0x5a, 0x30, 0x7f, 0x52,
+    0x20, 0xb3, 0xe2, 0xe7, 0x39, 0x69, 0xb6, 0xfc, 0x42, 0x1e, 0x98, 0xd3,
+    0x31, 0xa2, 0xfa, 0x81, 0x52, 0x69, 0x6d, 0x23, 0xf8, 0xc4, 0xc3, 0x3c,
+    0x9b, 0x48, 0x75, 0xa8, 0xc7, 0xe7, 0x61, 0x81, 0x1f, 0xf7, 0xce, 0x10,
+    0xaa, 0x13, 0xcb, 0x6e, 0x19, 0xc0, 0x4f, 0x6f, 0x90, 0xa8, 0x41, 0xea,
+    0x49, 0xdf, 0xe4, 0xef, 0x84, 0x54, 0xb5, 0x37, 0xaf, 0x12, 0x75, 0x1a,
+    0x11, 0x4b, 0x58, 0x7f, 0x63, 0x22, 0x33, 0xb1, 0xc8, 0x4d, 0xf2, 0x41,
+    0x10, 0xbc, 0x37, 0xb5, 0xd5, 0xb2, 0x21, 0x32, 0x35, 0x9d, 0xf3, 0x8d,
+    0xab, 0x66, 0x9d, 0x19, 0x12, 0x71, 0x45, 0xb3, 0x82, 0x5a, 0x5c, 0xff,
+    0x2d, 0xcf, 0xf4, 0x5b, 0x56, 0xb8, 0x08, 0xb3, 0xd2, 0x43, 0x8c, 0xac,
+    0xd2, 0xf8, 0xcc, 0x6d, 0x90, 0x97, 0xff, 0x12, 0x74, 0x97, 0xf8, 0xa4,
+    0xe3, 0x95, 0xae, 0x92, 0xdc, 0x7e, 0x9d, 0x2b, 0xb4, 0x94, 0xc3, 0x8d,
+    0x80, 0xe7, 0x77, 0x5c, 0x5b, 0xbb, 0x43, 0xdc, 0xa6, 0xe9, 0xbe, 0x20,
+    0xcc, 0x9d, 0x8e, 0xa4, 0x2b, 0xf2, 0x72, 0xdc, 0x44, 0x61, 0x0f, 0xad,
+    0x1a, 0x5e, 0xa5, 0x48, 0xe4, 0x42, 0xc5, 0xe4, 0xf1, 0x6d, 0x33, 0xdb,
+    0xb2, 0x1b, 0x9f, 0xb2, 0xff, 0x18, 0x0e, 0x62, 0x35, 0x99, 0xed, 0x22,
+    0x19, 0x4a, 0x5e, 0xb3, 0x3c, 0x07, 0x8f, 0x6e, 0x22, 0x5b, 0x16, 0x4a,
+    0x9f, 0xef, 0xf3, 0xe7, 0xd6, 0x48, 0xe1, 0xb4, 0x3b, 0xab, 0x1b, 0x9e,
+    0x53, 0xd7, 0x1b, 0xd9, 0x2d, 0x51, 0x8f, 0xe4, 0x1c, 0xab, 0xdd, 0xb9,
+    0xe2, 0xee, 0xe4, 0xdd, 0x60, 0x04, 0x86, 0x6b, 0x4e, 0x7a, 0xc8, 0x09,
+    0x51, 0xd1, 0x9b, 0x36, 0x9a, 0x36, 0x7f, 0xe8, 0x6b, 0x09, 0x6c, 0xee,
+    0xad, 0x3a, 0x2f, 0xa8, 0x63, 0x92, 0x23, 0x2f, 0x7e, 0x00, 0xe2, 0xd1,
+    0xbb, 0xd9, 0x5b, 0x5b, 0xfa, 0x4b, 0x83, 0x00, 0x19, 0x28, 0xfb, 0x7e,
+    0xfe, 0x58, 0xab, 0xb7, 0x33, 0x45, 0x8f, 0x75, 0x9a, 0x54, 0x3d, 0x77,
+    0x06, 0x75, 0x61, 0x4f, 0x5c, 0x93, 0xa0, 0xf9, 0xe8, 0xcf, 0xf6, 0x04,
+    0x14, 0xda, 0x1b, 0x2e, 0x79, 0x35, 0xb8, 0xb4, 0xfa, 0x08, 0x27, 0x9a,
+    0x03, 0x70, 0x78, 0x97, 0x8f, 0xae, 0x2e, 0xd5, 0x1c, 0xe0, 0x4d, 0x91,
+    0x3a, 0xfe, 0x1a, 0x64, 0xd8, 0x49, 0xdf, 0x6c, 0x66, 0xac, 0xc9, 0x57,
+    0x06, 0x72, 0xc0, 0xc0, 0x09, 0x71, 0x6a, 0xd0, 0xb0, 0x7d, 0x35, 0x3f,
+    0x53, 0x17, 0x49, 0x38, 0x92, 0x22, 0x55, 0xf6, 0x58, 0x56, 0xa2, 0x42,
+    0x77, 0x94, 0xb7, 0x28, 0x0a, 0xa0, 0xd2, 0xda, 0x25, 0xc1, 0xcc, 0x52,
+    0x51, 0xd6, 0xba, 0x18, 0x0f, 0x0d, 0xe3, 0x7d, 0xd1, 0xda, 0xd9, 0x0c,
+    0x5e, 0x3a, 0xca, 0xe9, 0xf1, 0xf5, 0x65, 0xfc, 0xc3, 0x99, 0x72, 0x25,
+    0xf2, 0xc0, 0xa1, 0x8c, 0x43, 0x9d, 0xb2, 0xc9, 0xb1, 0x1a, 0x24, 0x34,
+    0x57, 0xd8, 0xa7, 0x52, 0xa3, 0x39, 0x6e, 0x0b, 0xec, 0xbd, 0x5e, 0xc9,
+    0x1f, 0x74, 0xed, 0xae, 0xe6, 0x4e, 0x49, 0xe8, 0x87, 0x3e, 0x46, 0x0d,
+    0x40, 0x30, 0xda, 0x9d, 0xcf, 0xf5, 0x03, 0x1f, 0x38, 0x29, 0x3b, 0x66,
+    0xe5, 0xc0, 0x89, 0x4c, 0xfc, 0x09, 0x62, 0x37, 0x01, 0xf9, 0x01, 0xab,
+    0x8d, 0x53, 0x9c, 0x36, 0x5d, 0x36, 0x66, 0x8d, 0x87, 0xf4, 0xab, 0x37,
+    0xb7, 0xf7, 0xe3, 0xdf, 0xc1, 0x52, 0xc0, 0x1d, 0x09, 0x92, 0x21, 0x47,
+    0x49, 0x9a, 0x19, 0x38, 0x05, 0x62, 0xf3, 0x47, 0x80, 0x89, 0x1e, 0x70,
+    0xa1, 0x57, 0xb7, 0x72, 0xd0, 0x41, 0x7a, 0x5c, 0x6a, 0x13, 0x8b, 0x6c,
+    0xda, 0xdf, 0x6b, 0x01, 0x15, 0x20, 0xfa, 0xc8, 0x67, 0xee, 0xb2, 0x13,
+    0xd8, 0x5f, 0x84, 0x30, 0x44, 0x8e, 0xf9, 0x2a, 0xae, 0x17, 0x53, 0x49,
+    0xaa, 0x34, 0x31, 0x12, 0x31, 0xec, 0xf3, 0x25, 0x27, 0x53, 0x6b, 0xb5,
+    0x63, 0xa6, 0xbc, 0xf1, 0x77, 0xd4, 0xb4, 0x77, 0xd1, 0xee, 0xad, 0x62,
+    0x9d, 0x2c, 0x2e, 0x11, 0x0a, 0xd1, 0x87, 0xfe, 0xef, 0x77, 0x0e, 0xd1,
+    0x38, 0xfe, 0xcc, 0x88, 0xaa, 0x1c, 0x06, 0x93, 0x25, 0x56, 0xfe, 0x0c,
+    0x52, 0xe9, 0x7f, 0x4c, 0x3b, 0x2a, 0xfb, 0x40, 0x62, 0x29, 0x0a, 0x1d,
+    0x58, 0x78, 0x8b, 0x09, 0x25, 0xaa, 0xc6, 0x8f, 0x66, 0x8f, 0xd1, 0x93,
+    0x5a, 0xd6, 0x68, 0x35, 0x69, 0x13, 0x5d, 0x42, 0x35, 0x95, 0xcb, 0xc4,
+    0xec, 0x17, 0x92, 0x96, 0xcb, 0x4a, 0xb9, 0x8f, 0xe5, 0xc4, 0x4a, 0xe7,
+    0x54, 0x52, 0x4c, 0x64, 0x06, 0xac, 0x2f, 0x13, 0x32, 0x02, 0x47, 0x13,
+    0x5c, 0xa2, 0x66, 0xdc, 0x36, 0x0c, 0x4f, 0xbb, 0x89, 0x58, 0x85, 0x16,
+    0xf1, 0xf1, 0xff, 0xd2, 0x86, 0x54, 0x29, 0xb3, 0x7e, 0x2a, 0xbd, 0xf9,
+    0x53, 0x8c, 0xa0, 0x60, 0x60, 0xb2, 0x90, 0x7f, 0x3a, 0x11, 0x5f, 0x2a,
+    0x50, 0x74, 0x2a, 0xd1, 0x68, 0x78, 0xdb, 0x31, 0x1b, 0x8b, 0xee, 0xee,
+    0x18, 0x97, 0xf3, 0x50, 0x84, 0xc1, 0x8f, 0xe1, 0xc6, 0x01, 0xb4, 0x16,
+    0x65, 0x25, 0x0c, 0x03, 0xab, 0xed, 0x4f, 0xd6, 0xe6, 0x16, 0x23, 0xcc,
+    0x42, 0x93, 0xff, 0xfa, 0x92, 0x63, 0x33, 0x9e, 0x36, 0xb0, 0xdc, 0x9a,
+    0xb6, 0xaa, 0xd7, 0x48, 0xfe, 0x27, 0x01, 0xcf, 0x67, 0xc0, 0x75, 0xa0,
+    0x86, 0x9a, 0xec, 0xa7, 0x2e, 0xb8, 0x7b, 0x00, 0x7f, 0xd4, 0xe3, 0xb3,
+    0xfc, 0x48, 0xab, 0x50, 0x20, 0xd4, 0x0d, 0x58, 0x26, 0xc0, 0x3c, 0x09,
+    0x0b, 0x80, 0x9e, 0xaf, 0x14, 0x3c, 0x0c, 0x6e, 0x69, 0xbc, 0x6c, 0x4e,
+    0x50, 0x33, 0xb0, 0x07, 0x64, 0x6e, 0x77, 0x96, 0xc2, 0xe6, 0x3b, 0xd7,
+    0xfe, 0xdc, 0xa4, 0x2f, 0x18, 0x5b, 0x53, 0xe5, 0xdd, 0xb6, 0xce, 0xeb,
+    0x16, 0xb4, 0x25, 0xc6, 0xcb, 0xf2, 0x65, 0x3c, 0x4f, 0x94, 0xa5, 0x11,
+    0x18, 0xeb, 0x7b, 0x62, 0x1d, 0xd5, 0x02, 0x35, 0x76, 0xf6, 0xb5, 0x20,
+    0x27, 0x21, 0x9b, 0xab, 0xf4, 0xb6, 0x8f, 0x1a, 0x70, 0x1d, 0x12, 0xe3,
+    0xb9, 0x8e, 0x29, 0x52, 0x25, 0xf4, 0xba, 0xb4, 0x25, 0x2c, 0x91, 0x11,
+    0xf2, 0xae, 0x7b, 0xbe, 0xb6, 0x67, 0xd6, 0x08, 0xf8, 0x6f, 0xe7, 0xb0,
+    0x16, 0xc5, 0xf6, 0xd5, 0xfb, 0x07, 0x71, 0x5b, 0x0e, 0xe1, 0x02, 0x03,
+    0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55,
+    0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xaa, 0xe7, 0x7f, 0xcf, 0xf8, 0xb4,
+    0xe0, 0x8d, 0x39, 0x9a, 0x1d, 0x4f, 0x86, 0xa2, 0xac, 0x56, 0x32, 0xd9,
+    0x58, 0xe3, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
+    0x16, 0x80, 0x14, 0xaa, 0xe7, 0x7f, 0xcf, 0xf8, 0xb4, 0xe0, 0x8d, 0x39,
+    0x9a, 0x1d, 0x4f, 0x86, 0xa2, 0xac, 0x56, 0x32, 0xd9, 0x58, 0xe3, 0x30,
+    0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+    0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x04, 0x02, 0x00,
+    0x00, 0x0a, 0x0a, 0x81, 0xb5, 0x2e, 0xac, 0x52, 0xab, 0x0f, 0xeb, 0xad,
+    0x96, 0xd6, 0xd6, 0x59, 0x8f, 0x55, 0x15, 0x56, 0x70, 0xda, 0xd5, 0x75,
+    0x47, 0x12, 0x9a, 0x0e, 0xd1, 0x65, 0x68, 0xe0, 0x51, 0x89, 0x59, 0xcc,
+    0xe3, 0x5a, 0x1b, 0x85, 0x14, 0xa3, 0x1d, 0x9b, 0x3f, 0xd1, 0xa4, 0x42,
+    0xb0, 0x89, 0x12, 0x93, 0xd3, 0x54, 0x19, 0x04, 0xa2, 0xaf, 0xaa, 0x60,
+    0xca, 0x03, 0xc2, 0xae, 0x62, 0x8c, 0xb6, 0x31, 0x03, 0xd6, 0xa5, 0xf3,
+    0x5e, 0x8d, 0x5c, 0x69, 0x4c, 0x7d, 0x81, 0x49, 0x20, 0x25, 0x41, 0xa4,
+    0x2a, 0x95, 0x87, 0x36, 0xa3, 0x9b, 0x9e, 0x9f, 0xed, 0x85, 0xf3, 0xb1,
+    0xf1, 0xe9, 0x1b, 0xbb, 0xe3, 0xbc, 0x3b, 0x11, 0x36, 0xca, 0xb9, 0x5f,
+    0xee, 0x64, 0xde, 0x2a, 0x99, 0x27, 0x91, 0xc0, 0x54, 0x9e, 0x7a, 0xd4,
+    0x89, 0x8c, 0xa0, 0xe3, 0xfd, 0x44, 0x6f, 0x02, 0x38, 0x3c, 0xee, 0x52,
+    0x48, 0x1b, 0xd4, 0x25, 0x2b, 0xcb, 0x8e, 0xa8, 0x1b, 0x09, 0xd6, 0x30,
+    0x51, 0x15, 0x6c, 0x5c, 0x03, 0x76, 0xad, 0x64, 0x45, 0x50, 0xa2, 0xe1,
+    0x3c, 0x5a, 0x67, 0x87, 0xff, 0x8c, 0xed, 0x9a, 0x8d, 0x04, 0xc1, 0xac,
+    0xf9, 0xca, 0xf5, 0x2a, 0x05, 0x9c, 0xdd, 0x78, 0xce, 0x99, 0x78, 0x7b,
+    0xcd, 0x43, 0x10, 0x40, 0xf7, 0xb5, 0x27, 0x12, 0xec, 0xe9, 0xb2, 0x3f,
+    0xf4, 0x5d, 0xd9, 0xbb, 0xf8, 0xc4, 0xc9, 0xa4, 0x46, 0x20, 0x41, 0x7f,
+    0xeb, 0x79, 0xb0, 0x51, 0x8c, 0xf7, 0xc3, 0x2c, 0x16, 0xfe, 0x42, 0x59,
+    0x77, 0xfe, 0x53, 0xfe, 0x19, 0x57, 0x58, 0x44, 0x6d, 0x12, 0xe2, 0x95,
+    0xd0, 0xd3, 0x5a, 0xb5, 0x2d, 0xe5, 0x7e, 0xb4, 0xb3, 0xa9, 0xcc, 0x7d,
+    0x53, 0x77, 0x81, 0x01, 0x0f, 0x0a, 0xf6, 0x86, 0x3c, 0x7d, 0xb5, 0x2c,
+    0xbf, 0x62, 0xc3, 0xf5, 0x38, 0x89, 0x13, 0x84, 0x1f, 0x44, 0x2d, 0x87,
+    0x5c, 0x23, 0x9e, 0x05, 0x62, 0x56, 0x3d, 0x71, 0x4d, 0xd0, 0xe3, 0x15,
+    0xe9, 0x09, 0x9c, 0x1a, 0xc0, 0x9a, 0x19, 0x8b, 0x9c, 0xe9, 0xae, 0xde,
+    0x62, 0x05, 0x23, 0xe2, 0xd0, 0x3f, 0xf5, 0xef, 0x04, 0x96, 0x4c, 0x87,
+    0x34, 0x2f, 0xd5, 0x90, 0xde, 0xbf, 0x4b, 0x56, 0x12, 0x5f, 0xc6, 0xdc,
+    0xa4, 0x1c, 0xc4, 0x53, 0x0c, 0xf9, 0xb4, 0xe4, 0x2c, 0xe7, 0x48, 0xbd,
+    0xb1, 0xac, 0xf1, 0xc1, 0x8d, 0x53, 0x47, 0x84, 0xc0, 0x78, 0x0a, 0x5e,
+    0xc2, 0x16, 0xff, 0xef, 0x97, 0x5b, 0x33, 0x85, 0x92, 0xcd, 0xd4, 0xbb,
+    0x64, 0xee, 0xed, 0x17, 0x18, 0x43, 0x32, 0x99, 0x32, 0x36, 0x25, 0xf4,
+    0x21, 0x3c, 0x2f, 0x55, 0xdc, 0x16, 0x06, 0x4d, 0x86, 0xa3, 0xa9, 0x34,
+    0x22, 0xd5, 0xc3, 0xc8, 0x64, 0x3c, 0x4e, 0x3a, 0x69, 0xbd, 0xcf, 0xd7,
+    0xee, 0x3f, 0x0d, 0x15, 0xeb, 0xfb, 0xbd, 0x91, 0x7f, 0xef, 0x48, 0xec,
+    0x86, 0xb2, 0x78, 0xf7, 0x53, 0x90, 0x38, 0xb5, 0x04, 0x9c, 0xb7, 0xd7,
+    0x9e, 0xaa, 0x15, 0xf7, 0xcd, 0xc2, 0x17, 0xd5, 0x8f, 0x82, 0x98, 0xa3,
+    0xaf, 0x59, 0xf1, 0x71, 0xda, 0x6e, 0xaf, 0x97, 0x6d, 0x77, 0x72, 0xfd,
+    0xa8, 0x80, 0x25, 0xce, 0x46, 0x04, 0x6e, 0x40, 0x15, 0x24, 0xc0, 0xf9,
+    0xbf, 0x13, 0x16, 0x72, 0xcb, 0xb7, 0x10, 0xc7, 0x0a, 0xd6, 0x66, 0x96,
+    0x5b, 0x27, 0x4d, 0x66, 0xc4, 0x2f, 0x21, 0x90, 0x9f, 0x8c, 0x24, 0xa0,
+    0x0e, 0xa2, 0x89, 0x92, 0xd2, 0x44, 0x63, 0x06, 0xb2, 0xab, 0x07, 0x26,
+    0xde, 0x03, 0x1d, 0xdb, 0x2a, 0x42, 0x5b, 0x4c, 0xf6, 0xfe, 0x53, 0xfa,
+    0x80, 0x45, 0x8d, 0x75, 0xf6, 0x0e, 0x1d, 0xcc, 0x4c, 0x3b, 0xb0, 0x80,
+    0x6d, 0x4c, 0xed, 0x7c, 0xe0, 0xd2, 0xe7, 0x62, 0x59, 0xb1, 0x5a, 0x5d,
+    0x3a, 0xec, 0x86, 0x04, 0xfe, 0x26, 0xd1, 0x18, 0xed, 0x56, 0x7d, 0x67,
+    0x56, 0x24, 0x6d, 0x7c, 0x6e, 0x8f, 0xc8, 0xa0, 0xba, 0x42, 0x0a, 0x33,
+    0x38, 0x7a, 0x09, 0x03, 0xc2, 0xbf, 0x9b, 0x01, 0xdd, 0x03, 0x5a, 0xba,
+    0x76, 0x04, 0xb1, 0xc3, 0x40, 0x23, 0x53, 0xbd, 0x64, 0x4e, 0x0f, 0xe7,
+    0xc3, 0x4e, 0x48, 0xea, 0x19, 0x2b, 0x1c, 0xe4, 0x3d, 0x93, 0xd8, 0xf6,
+    0xfb, 0xda, 0x3d, 0xeb, 0xed, 0xc2, 0xbd, 0x14, 0x57, 0x40, 0xde, 0xd1,
+    0x74, 0x54, 0x1b, 0xa8, 0x39, 0xda, 0x73, 0x56, 0xd4, 0xbe, 0xab, 0xec,
+    0xc7, 0x17, 0x4f, 0x91, 0xb6, 0xf6, 0xcb, 0x24, 0xc6, 0x1c, 0x07, 0xc4,
+    0xf3, 0xd0, 0x5e, 0x8d, 0xfa, 0x44, 0x98, 0x5c, 0x87, 0x36, 0x75, 0xb6,
+    0xa5, 0x31, 0xaa, 0xab, 0x7d, 0x38, 0x66, 0xb3, 0x18, 0x58, 0x65, 0x97,
+    0x06, 0xfd, 0x61, 0x81, 0x71, 0xc5, 0x17, 0x8b, 0x19, 0x03, 0xc8, 0x58,
+    0xec, 0x05, 0xca, 0x7b, 0x0f, 0xec, 0x9d, 0xb4, 0xbc, 0xa3, 0x20, 0x2e,
+    0xf8, 0xe4, 0xb1, 0x82, 0xdc, 0x5a, 0xd2, 0x92, 0x9c, 0x43, 0x5d, 0x16,
+    0x5b, 0x90, 0x80, 0xe4, 0xfb, 0x6e, 0x24, 0x6b, 0x8c, 0x1a, 0x35, 0xab,
+    0xbd, 0x77, 0x7f, 0xf9, 0x61, 0x80, 0xa5, 0xab, 0xa3, 0x39, 0xc2, 0xc9,
+    0x69, 0x3c, 0xfc, 0xb3, 0x9a, 0x05, 0x45, 0x03, 0x88, 0x8f, 0x8e, 0x23,
+    0xf2, 0x0c, 0x4c, 0x54, 0xb9, 0x40, 0x3a, 0x31, 0x1a, 0x22, 0x67, 0x43,
+    0x4a, 0x3e, 0xa0, 0x8c, 0x2d, 0x4d, 0x4f, 0xfc, 0xb5, 0x9b, 0x1f, 0xe1,
+    0xef, 0x02, 0x54, 0xab, 0x8d, 0x75, 0x4d, 0x93, 0xba, 0x76, 0xe1, 0xbc,
+    0x42, 0x7f, 0x6c, 0xcb, 0xf5, 0x47, 0xd6, 0x8a, 0xac, 0x5d, 0xe9, 0xbb,
+    0x3a, 0x65, 0x2c, 0x81, 0xe5, 0xff, 0x27, 0x7e, 0x60, 0x64, 0x80, 0x42,
+    0x8d, 0x36, 0x6b, 0x07, 0x76, 0x6a, 0xf1, 0xdf, 0x96, 0x17, 0x93, 0x21,
+    0x5d, 0xe4, 0x6c, 0xce, 0x1c, 0xb9, 0x82, 0x45, 0x05, 0x61, 0xe2, 0x41,
+    0x96, 0x03, 0x7d, 0x10, 0x8b, 0x3e, 0xc7, 0xe5, 0xcf, 0x08, 0xeb, 0x81,
+    0xd3, 0x82, 0x1b, 0x04, 0x96, 0x93, 0x5a, 0xe2, 0x8c, 0x8e, 0x50, 0x33,
+    0xf6, 0xf9, 0xf0, 0xfb, 0xb1, 0xd7, 0xc6, 0x97, 0xaa, 0xef, 0x0b, 0x87,
+    0xe1, 0x34, 0x97, 0x78, 0x2e, 0x7c, 0x46, 0x11, 0xd5, 0x3c, 0xec, 0x38,
+    0x70, 0x59, 0x14, 0x65, 0x4d, 0x0e, 0xd1, 0xeb, 0x49, 0xb3, 0x99, 0x6f,
+    0x87, 0xf1, 0x79, 0x21, 0xd9, 0x5c, 0x37, 0xb2, 0xfe, 0xc4, 0x7a, 0xc1,
+    0x67, 0xbd, 0x02, 0xfc, 0x02, 0xab, 0x2f, 0xf5, 0x0f, 0xa7, 0xae, 0x90,
+    0xc2, 0xaf, 0xdb, 0xd1, 0x96, 0xb2, 0x92, 0x5a, 0xfb, 0xca, 0x28, 0x74,
+    0x17, 0xed, 0xda, 0x2c, 0x9f, 0xb4, 0x2d, 0xf5, 0x71, 0x20, 0x64, 0x2d,
+    0x44, 0xe5, 0xa3, 0xa0, 0x94, 0x6f, 0x20, 0xb3, 0x73, 0x96, 0x40, 0x06,
+    0x9b, 0x25, 0x47, 0x4b, 0xe0, 0x63, 0x91, 0xd9, 0xda, 0xf3, 0xc3, 0xe5,
+    0x3a, 0x3c, 0xb7, 0x5f, 0xab, 0x1e, 0x51, 0x17, 0x4f, 0xec, 0xc1, 0x6d,
+    0x82, 0x79, 0x8e, 0xba, 0x7c, 0x47, 0x8e, 0x99, 0x00, 0x17, 0x9e, 0xda,
+    0x10, 0x42, 0x70, 0x25, 0x42, 0x84, 0xc8, 0xb1, 0x95, 0x56, 0xb2, 0x08,
+    0xa0, 0x4f, 0xdc, 0xcd, 0x9e, 0x31, 0x4b, 0x0c, 0x0b, 0x03, 0x5d, 0x2c,
+    0x26, 0xbc, 0xa9, 0x4b, 0x19, 0xdf, 0x90, 0x01, 0x9a, 0xe0, 0x06, 0x05,
+    0x13, 0x34, 0x9d, 0x34, 0xb8, 0xef, 0x13, 0x3a, 0x20, 0xf5, 0x74, 0x02,
+    0x70, 0x3b, 0x41, 0x60, 0x1f, 0x5e, 0x76, 0x0a, 0xb1, 0x17, 0xd5, 0xcf,
+    0x79, 0xef, 0xf7, 0xab, 0xe7, 0xd6, 0x0f, 0xad, 0x85, 0x2c, 0x52, 0x67,
+    0xb5, 0xa0, 0x4a, 0xfd, 0xaf};
\ No newline at end of file
--- a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
@@ -470,16 +470,55 @@ TEST_P(TlsConnectTls13, NamedGroupMismat
   server_->ConfigNamedGroups(server_groups);
   client_->ConfigNamedGroups(client_groups);
 
   ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
+// Replace the key share in the server key exchange message with one that's
+// larger than 8192 bits.
+class TooLongDHEServerKEXFilter : public TlsHandshakeFilter {
+ public:
+  TooLongDHEServerKEXFilter(const std::shared_ptr<TlsAgent>& server)
+      : TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}) {}
+
+ protected:
+  virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+                                               const DataBuffer& input,
+                                               DataBuffer* output) {
+    // Replace the server key exchange message very large DH shares that are
+    // not supported by NSS.
+    const uint32_t share_len = 0x401;
+    const uint8_t zero_share[share_len] = {0x80};
+    size_t offset = 0;
+    // Write dh_p.
+    offset = output->Write(offset, share_len, 2);
+    offset = output->Write(offset, zero_share, share_len);
+    // Write dh_g.
+    offset = output->Write(offset, share_len, 2);
+    offset = output->Write(offset, zero_share, share_len);
+    // Write dh_Y.
+    offset = output->Write(offset, share_len, 2);
+    offset = output->Write(offset, zero_share, share_len);
+
+    return CHANGE;
+  }
+};
+
+TEST_P(TlsConnectGenericPre13, TooBigDHGroup) {
+  EnableOnlyDheCiphers();
+  MakeTlsFilter<TooLongDHEServerKEXFilter>(server_);
+  client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_FALSE);
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+  client_->CheckErrorCode(SSL_ERROR_DH_KEY_TOO_LONG);
+}
+
 // Even though the client doesn't have DHE groups enabled the server assumes it
 // does. The client requires named groups and thus does not accept FF3072 as
 // custom group in contrast to the previous test.
 TEST_P(TlsConnectGenericPre13, RequireNamedGroupsMismatchPre13) {
   EnableOnlyDheCiphers();
   client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE);
   static const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ffdhe_3072};
   static const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_secp256r1,
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -316,17 +316,25 @@ TEST_P(TlsExtensionTestGeneric, AlpnMiss
   EnableAlpn();
   // This will leave the length of the second entry, but no value.
   ClientHelloErrorTest(std::make_shared<TlsExtensionTruncator>(
       client_, ssl_app_layer_protocol_xtn, 5));
 }
 
 TEST_P(TlsExtensionTestGeneric, AlpnZeroLength) {
   EnableAlpn();
-  const uint8_t val[] = {0x01, 0x61, 0x00};
+  const uint8_t val[] = {0x00, 0x03, 0x01, 0x61, 0x00};
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      client_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnLengthOverflow) {
+  EnableAlpn();
+  const uint8_t val[] = {0x00, 0x03, 0x01, 0x61, 0x01};
   DataBuffer extension(val, sizeof(val));
   ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
       client_, ssl_app_layer_protocol_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestGeneric, AlpnMismatch) {
   const uint8_t client_alpn[] = {0x01, 0x61};
   client_->EnableAlpn(client_alpn, sizeof(client_alpn));
--- a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
@@ -612,16 +612,78 @@ TEST_P(TlsConnectTls13, RetryStatefulDro
   MakeTlsFilter<TlsExtensionDropper>(client_, ssl_tls13_cookie_xtn);
 
   ExpectAlert(server_, kTlsAlertMissingExtension);
   Handshake();
   client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
   server_->CheckErrorCode(SSL_ERROR_MISSING_COOKIE_EXTENSION);
 }
 
+class TruncateHrrCookie : public TlsExtensionFilter {
+ public:
+  TruncateHrrCookie(const std::shared_ptr<TlsAgent>& a)
+      : TlsExtensionFilter(a) {}
+  virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
+                                               const DataBuffer& input,
+                                               DataBuffer* output) {
+    if (extension_type != ssl_tls13_cookie_xtn) {
+      return KEEP;
+    }
+
+    // Claim a zero-length cookie.
+    output->Allocate(2);
+    output->Write(0, static_cast<uint32_t>(0), 2);
+    return CHANGE;
+  }
+};
+
+TEST_P(TlsConnectTls13, RetryCookieEmpty) {
+  ConfigureSelfEncrypt();
+  EnsureTlsSetup();
+
+  TriggerHelloRetryRequest(client_, server_);
+  MakeTlsFilter<TruncateHrrCookie>(client_);
+
+  ExpectAlert(server_, kTlsAlertHandshakeFailure);
+  Handshake();
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+  server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
+class AddJunkToCookie : public TlsExtensionFilter {
+ public:
+  AddJunkToCookie(const std::shared_ptr<TlsAgent>& a) : TlsExtensionFilter(a) {}
+  virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
+                                               const DataBuffer& input,
+                                               DataBuffer* output) {
+    if (extension_type != ssl_tls13_cookie_xtn) {
+      return KEEP;
+    }
+
+    *output = input;
+    // Add junk after the cookie.
+    static const uint8_t junk[2] = {1, 2};
+    output->Append(DataBuffer(junk, sizeof(junk)));
+    return CHANGE;
+  }
+};
+
+TEST_P(TlsConnectTls13, RetryCookieWithExtras) {
+  ConfigureSelfEncrypt();
+  EnsureTlsSetup();
+
+  TriggerHelloRetryRequest(client_, server_);
+  MakeTlsFilter<AddJunkToCookie>(client_);
+
+  ExpectAlert(server_, kTlsAlertHandshakeFailure);
+  Handshake();
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+  server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
 // Stream only because DTLS drops bad packets.
 TEST_F(TlsConnectStreamTls13, RetryStatelessDamageFirstClientHello) {
   ConfigureSelfEncrypt();
   EnsureTlsSetup();
 
   auto damage_ch =
       MakeTlsFilter<TlsExtensionInjector>(client_, 0xfff3, DataBuffer());
 
--- a/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
@@ -16,16 +16,17 @@ extern "C" {
 #include "libssl_internals.h"
 }
 
 #include "gtest_utils.h"
 #include "scoped_ptrs.h"
 #include "tls_connect.h"
 #include "tls_filter.h"
 #include "tls_parser.h"
+#include "rsa8193.h"
 
 namespace nss_test {
 
 const uint8_t kBogusClientKeyExchange[] = {
     0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -95,9 +96,44 @@ TEST_P(TlsConnectStreamPre13,
        ConnectExtendedMasterSecretStaticRSABogusPMSVersionIgnore) {
   EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
   MakeTlsFilter<TlsClientHelloVersionChanger>(client_, server_);
   server_->SetOption(SSL_ROLLBACK_DETECTION, PR_FALSE);
   Connect();
 }
 
+// Replace the server certificate with one that uses 8193-bit RSA.
+class TooLargeRSACertFilter : public TlsHandshakeFilter {
+ public:
+  TooLargeRSACertFilter(const std::shared_ptr<TlsAgent> &server)
+      : TlsHandshakeFilter(server, {kTlsHandshakeCertificate}) {}
+
+ protected:
+  virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
+                                               const DataBuffer &input,
+                                               DataBuffer *output) {
+    const uint32_t cert_len = sizeof(rsa8193);
+    const uint32_t outer_len = cert_len + 3;
+    size_t offset = 0;
+    offset = output->Write(offset, outer_len, 3);
+    offset = output->Write(offset, cert_len, 3);
+    offset = output->Write(offset, rsa8193, cert_len);
+
+    return CHANGE;
+  }
+};
+
+TEST_P(TlsConnectGenericPre13, TooLargeRSAKeyInCert) {
+  EnableOnlyStaticRsaCiphers();
+  MakeTlsFilter<TooLargeRSACertFilter>(server_);
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+  client_->CheckErrorCode(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+TEST_P(TlsConnectGeneric, ServerAuthBiggestRsa) {
+  Reset(TlsAgent::kRsa8192);
+  Connect();
+  CheckKeys();
+}
+
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc
@@ -431,9 +431,25 @@ TEST_F(TlsConnectDatagram13, CompatModeD
               server_records->record(i).header.content_type());
   }
 
   uint32_t session_id_len = 0;
   EXPECT_TRUE(server_hello->buffer().Read(2 + 32, 1, &session_id_len));
   EXPECT_EQ(0U, session_id_len);
 }
 
+TEST_F(Tls13CompatTest, ConnectWith12ThenAttemptToResume13CompatMode) {
+  ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
+  ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_2);
+  Connect();
+
+  Reset();
+  ExpectResumption(RESUME_NONE);
+  version_ = SSL_LIBRARY_VERSION_TLS_1_3;
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  EnableCompatMode();
+  Connect();
+}
+
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -28,16 +28,17 @@ extern "C" {
 extern std::string g_working_dir_path;
 
 namespace nss_test {
 
 const char* TlsAgent::states[] = {"INIT", "CONNECTING", "CONNECTED", "ERROR"};
 
 const std::string TlsAgent::kClient = "client";    // both sign and encrypt
 const std::string TlsAgent::kRsa2048 = "rsa2048";  // bigger
+const std::string TlsAgent::kRsa8192 = "rsa8192";  // biggest allowed
 const std::string TlsAgent::kServerRsa = "rsa";    // both sign and encrypt
 const std::string TlsAgent::kServerRsaSign = "rsa_sign";
 const std::string TlsAgent::kServerRsaPss = "rsa_pss";
 const std::string TlsAgent::kServerRsaDecrypt = "rsa_decrypt";
 const std::string TlsAgent::kServerEcdsa256 = "ecdsa256";
 const std::string TlsAgent::kServerEcdsa384 = "ecdsa384";
 const std::string TlsAgent::kServerEcdsa521 = "ecdsa521";
 const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -64,16 +64,17 @@ static const uint8_t kD13 = TLS_1_3_DRAF
 
 class TlsAgent : public PollTarget {
  public:
   enum Role { CLIENT, SERVER };
   enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED, STATE_ERROR };
 
   static const std::string kClient;     // the client key is sign only
   static const std::string kRsa2048;    // bigger sign and encrypt for either
+  static const std::string kRsa8192;    // biggest sign and encrypt for either
   static const std::string kServerRsa;  // both sign and encrypt
   static const std::string kServerRsaSign;
   static const std::string kServerRsaPss;
   static const std::string kServerRsaDecrypt;
   static const std::string kServerEcdsa256;
   static const std::string kServerEcdsa384;
   static const std::string kServerEcdsa521;
   static const std::string kServerEcdhEcdsa;
--- a/security/nss/lib/pkcs12/p12d.c
+++ b/security/nss/lib/pkcs12/p12d.c
@@ -808,16 +808,17 @@ sec_pkcs12_decoder_asafes_notify(void *a
 
     if (!before) {
         /* if one is being decoded, finish the decode */
         if (p12dcx->currentASafeP7Dcx != NULL) {
             SEC_PKCS7ContentInfo *cinfo;
             unsigned int cnt = p12dcx->safeContentsCnt - 1;
             safeContentsCtx = p12dcx->safeContentsList[cnt];
             if (safeContentsCtx->safeContentsA1Dcx) {
+                SEC_ASN1DecoderClearFilterProc(p12dcx->aSafeA1Dcx);
                 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
                 safeContentsCtx->safeContentsA1Dcx = NULL;
             }
             cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
             p12dcx->currentASafeP7Dcx = NULL;
             if (!cinfo) {
                 p12dcx->errorValue = PORT_GetError();
                 goto loser;
--- a/security/nss/lib/pkcs7/p7decode.c
+++ b/security/nss/lib/pkcs7/p7decode.c
@@ -555,16 +555,17 @@ sec_pkcs7_decoder_start_decrypt(SEC_PKCS
                                  (PRBool)(p7dcx->cb != NULL));
 
     p7dcx->worker.depth = depth;
     p7dcx->worker.decryptobj = decryptobj;
 
     return SECSuccess;
 
 no_decryption:
+    PK11_FreeSymKey(bulkkey);
     /*
      * For some reason (error set already, if appropriate), we cannot
      * decrypt the content.  I am not sure what exactly is the right
      * thing to do here; in some cases we want to just stop, and in
      * others we want to let the decoding finish even though we cannot
      * decrypt the content.  My current thinking is that if the caller
      * set up a content callback, then they are really interested in
      * getting (decrypted) content, and if they cannot they will want
@@ -1026,16 +1027,21 @@ SEC_PKCS7DecoderStart(SEC_PKCS7DecoderCo
  * again in case that is the easiest route for our caller to take.
  * We simply detect it and do not do anything except keep setting
  * that error in case our caller has not noticed it yet...
  */
 SECStatus
 SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
                        const char *buf, unsigned long len)
 {
+    if (!p7dcx) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
     if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) {
         PORT_Assert(p7dcx->error == 0);
         if (p7dcx->error == 0) {
             if (SEC_ASN1DecoderUpdate(p7dcx->dcx, buf, len) != SECSuccess) {
                 p7dcx->error = PORT_GetError();
                 PORT_Assert(p7dcx->error);
                 if (p7dcx->error == 0)
                     p7dcx->error = -1;
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -544,8 +544,11 @@ ER3(SSL_ERROR_TOO_MANY_KEY_UPDATES, (SSL
 ER3(SSL_ERROR_HANDSHAKE_FAILED, (SSL_ERROR_BASE + 172),
     "SSL handshake has already failed. No more operations possible.")
 
 ER3(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR, (SSL_ERROR_BASE + 173),
     "SSL received an invalid resumption token.")
 
 ER3(SSL_ERROR_RX_MALFORMED_DTLS_ACK, (SSL_ERROR_BASE + 174),
     "SSL received a malformed DTLS ACK")
+
+ER3(SSL_ERROR_DH_KEY_TOO_LONG, (SSL_ERROR_BASE + 175),
+    "SSL received a DH key share that's too long (>8192 bit).")
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -5567,23 +5567,30 @@ ssl3_SendRSAClientKeyExchange(sslSocket 
     pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.pwSpec, NULL);
     ssl_ReleaseSpecWriteLock(ss);
     if (pms == NULL) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
     /* Get the wrapped (encrypted) pre-master secret, enc_pms */
-    enc_pms.len = SECKEY_PublicKeyStrength(svrPubKey);
+    unsigned int svrPubKeyBits = SECKEY_PublicKeyStrengthInBits(svrPubKey);
+    enc_pms.len = (svrPubKeyBits + 7) / 8;
+    /* Check that the RSA key isn't larger than 8k bit. */
+    if (svrPubKeyBits > SSL_MAX_RSA_KEY_BITS) {
+        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+        goto loser;
+    }
     enc_pms.data = (unsigned char *)PORT_Alloc(enc_pms.len);
     if (enc_pms.data == NULL) {
         goto loser; /* err set by PORT_Alloc */
     }
 
-    /* wrap pre-master secret in server's public key. */
+    /* Wrap pre-master secret in server's public key. */
     rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, pms, &enc_pms);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
 #ifdef TRACE
     if (ssl_trace >= 100) {
@@ -5676,17 +5683,17 @@ ssl3_SendDHClientKeyExchange(sslSocket *
     const ssl3DHParams *params;
     ssl3DHParams customParams;
     const sslNamedGroupDef *groupDef;
     static const sslNamedGroupDef customGroupDef = {
         ssl_grp_ffdhe_custom, 0, ssl_kea_dh, SEC_OID_TLS_DHE_CUSTOM, PR_FALSE
     };
     sslEphemeralKeyPair *keyPair = NULL;
     SECKEYPublicKey *pubKey;
-    PRUint8 dhData[1026]; /* Enough for the 8192-bit group. */
+    PRUint8 dhData[SSL_MAX_DH_KEY_BITS / 8 + 2];
     sslBuffer dhBuf = SSL_BUFFER(dhData);
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
 
     /* Copy DH parameters from server key */
@@ -6159,38 +6166,48 @@ ssl_ClientSetCipherSuite(sslSocket *ss, 
 
 /* Check that session ID we received from the server, if any, matches our
  * expectations, depending on whether we're in compat mode and whether we
  * negotiated TLS 1.3+ or TLS 1.2-.
  */
 static PRBool
 ssl_CheckServerSessionIdCorrectness(sslSocket *ss, SECItem *sidBytes)
 {
-    PRBool sid_match = PR_FALSE;
-    PRBool sent_fake_sid = ss->opt.enableTls13CompatMode && !IS_DTLS(ss);
-
-    /* If in compat mode and we received a session ID with the right length
-     * then compare it to the fake one we sent in the ClientHello. */
-    if (sent_fake_sid && sidBytes->len == SSL3_SESSIONID_BYTES) {
-        PRUint8 buf[SSL3_SESSIONID_BYTES];
-        ssl_MakeFakeSid(ss, buf);
-        sid_match = PORT_Memcmp(buf, sidBytes->data, sidBytes->len) == 0;
-    }
-
-    /* TLS 1.2: SessionID shouldn't match the fake one. */
+    sslSessionID *sid = ss->sec.ci.sid;
+    PRBool sidMatch = PR_FALSE;
+    PRBool sentFakeSid = PR_FALSE;
+    PRBool sentRealSid = sid && sid->version < SSL_LIBRARY_VERSION_TLS_1_3;
+
+    /* If attempting to resume a TLS 1.2 connection, the session ID won't be a
+     * fake. Check for the real value. */
+    if (sentRealSid) {
+        sidMatch = (sidBytes->len == sid->u.ssl3.sessionIDLength) &&
+                   PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes->data, sidBytes->len) == 0;
+    } else {
+        /* Otherwise, the session ID was a fake if TLS 1.3 compat mode is
+         * enabled.  If so, check for the fake value. */
+        sentFakeSid = ss->opt.enableTls13CompatMode && !IS_DTLS(ss);
+        if (sentFakeSid && sidBytes->len == SSL3_SESSIONID_BYTES) {
+            PRUint8 buf[SSL3_SESSIONID_BYTES];
+            ssl_MakeFakeSid(ss, buf);
+            sidMatch = PORT_Memcmp(buf, sidBytes->data, sidBytes->len) == 0;
+        }
+    }
+
+    /* TLS 1.2: Session ID shouldn't match if we sent a fake. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        return !sid_match;
-    }
-
-    /* TLS 1.3: [Compat Mode] Session ID should match the fake one. */
-    if (sent_fake_sid) {
-        return sid_match;
-    }
-
-    /* TLS 1.3: [Non-Compat Mode] Server shouldn't send a session ID. */
+        return !sentFakeSid || !sidMatch;
+    }
+
+    /* TLS 1.3: We sent a session ID.  The server's should match. */
+    if (sentRealSid || sentFakeSid) {
+        return sidMatch;
+    }
+
+    /* TLS 1.3: The server shouldn't send a session ID. */
     return sidBytes->len == 0;
 }
 
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 ServerHello message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
@@ -6713,16 +6730,20 @@ ssl_HandleDHServerKeyExchange(sslSocket 
     if (rv != SECSuccess || minDH <= 0) {
         minDH = SSL_DH_MIN_P_BITS;
     }
     dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p);
     if (dh_p_bits < (unsigned)minDH) {
         errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
         goto alert_loser;
     }
+    if (dh_p_bits > SSL_MAX_DH_KEY_BITS) {
+        errCode = SSL_ERROR_DH_KEY_TOO_LONG;
+        goto alert_loser;
+    }
     rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* malformed. */
     }
     /* Abort if dh_g is 0, 1, or obviously too big. */
     dh_g_bits = SECKEY_BigIntegerBitLength(&dh_g);
     if (dh_g_bits > dh_p_bits || dh_g_bits <= 1) {
         goto alert_loser;
--- a/security/nss/lib/ssl/sslcert.c
+++ b/security/nss/lib/ssl/sslcert.c
@@ -251,17 +251,18 @@ ssl_PopulateKeyPair(sslServerCert *sc, s
                 /* Unsupported curve. */
                 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
                 return SECFailure;
             }
         }
 
         /* Get the size of the cert's public key, and remember it. */
         sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
-        if (sc->serverKeyBits == 0) {
+        if (sc->serverKeyBits == 0 ||
+            (keyType == rsaKey && sc->serverKeyBits > SSL_MAX_RSA_KEY_BITS)) {
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             return SECFailure;
         }
 
         SECKEY_CacheStaticFlags(keyPair->privKey);
         sc->serverKeyPair = ssl_GetKeyPairRef(keyPair);
 
         if (SSL_CERT_IS(sc, ssl_auth_rsa_decrypt)) {
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -258,15 +258,16 @@ typedef enum {
     SSL_ERROR_MISSING_COOKIE_EXTENSION = (SSL_ERROR_BASE + 168),
 
     SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE = (SSL_ERROR_BASE + 169),
     SSL_ERROR_RX_MALFORMED_KEY_UPDATE = (SSL_ERROR_BASE + 170),
     SSL_ERROR_TOO_MANY_KEY_UPDATES = (SSL_ERROR_BASE + 171),
     SSL_ERROR_HANDSHAKE_FAILED = (SSL_ERROR_BASE + 172),
     SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR = (SSL_ERROR_BASE + 173),
     SSL_ERROR_RX_MALFORMED_DTLS_ACK = (SSL_ERROR_BASE + 174),
+    SSL_ERROR_DH_KEY_TOO_LONG = (SSL_ERROR_BASE + 175),
     SSL_ERROR_END_OF_LIST   /* let the c compiler determine the value of this. */
 } SSLErrorCodes;
 #endif /* NO_SECURITY_ERROR_ENUM */
 
 /* clang-format on */
 
 #endif /* __SSL_ERR_H_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -116,16 +116,20 @@ typedef enum { SSLAppOpRead = 0,
 /* The maximum time to wait between retransmissions. */
 #define DTLS_RETRANSMIT_MAX_MS 10000
 /* Time to wait in FINISHED state for retransmissions. */
 #define DTLS_RETRANSMIT_FINISHED_MS 30000
 
 /* default number of entries in namedGroupPreferences */
 #define SSL_NAMED_GROUP_COUNT 31
 
+/* The maximum DH and RSA bit-length supported. */
+#define SSL_MAX_DH_KEY_BITS 8192
+#define SSL_MAX_RSA_KEY_BITS 8192
+
 /* Types and names of elliptic curves used in TLS */
 typedef enum {
     ec_type_explicitPrime = 1,      /* not supported */
     ec_type_explicitChar2Curve = 2, /* not supported */
     ec_type_named = 3
 } ECType;
 
 typedef enum {
@@ -806,17 +810,17 @@ typedef struct {
 
 struct ssl3DHParamsStr {
     SSLNamedGroup name;
     SECItem prime; /* p */
     SECItem base;  /* g */
 };
 
 typedef struct SSLWrappedSymWrappingKeyStr {
-    PRUint8 wrappedSymmetricWrappingkey[512];
+    PRUint8 wrappedSymmetricWrappingkey[SSL_MAX_RSA_KEY_BITS / 8];
     CK_MECHANISM_TYPE symWrapMechanism;
     /* unwrapped symmetric wrapping key uses this mechanism */
     CK_MECHANISM_TYPE asymWrapMechanism;
     /* mechanism used to wrap the SymmetricWrappingKey using
      * server's public and/or private keys. */
     PRInt16 wrapMechIndex;
     PRUint16 wrapKeyIndex;
     PRUint16 wrappedSymKeyLen;
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -855,22 +855,22 @@ tls13_ServerHandleCookieXtn(const sslSoc
 
     rv = ssl3_ExtConsumeHandshakeVariable(ss, &xtnData->cookie, 2,
                                           &data->data, &data->len);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     if (xtnData->cookie.len == 0) {
-        PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
 
     if (data->len) {
-        PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
     xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_cookie_xtn;
 
     return SECSuccess;
 }
--- a/security/nss/lib/util/secasn1d.c
+++ b/security/nss/lib/util/secasn1d.c
@@ -170,17 +170,17 @@ static int /* bool */
             sprintf(buf, " %s", type_names[k]);
             if ((k == SEC_ASN1_SET || k == SEC_ASN1_SEQUENCE) &&
                 (kind & SEC_ASN1_GROUP)) {
                 buf += strlen(buf);
                 sprintf(buf, "_OF");
             }
         }
     } else {
-        sprintf(buf, " [%d]", k);
+        sprintf(buf, " [%lu]", k);
     }
     buf += strlen(buf);
 
     for (k = kind >> 8, i = 0; k; k >>= 1, ++i) {
         if (k & 1) {
             sprintf(buf, " %s", flag_names[i]);
             buf += strlen(buf);
         }
@@ -977,17 +977,17 @@ sec_asn1d_prepare_for_contents(sec_asn1d
 {
     SECItem *item;
     PLArenaPool *poolp;
     unsigned long alloc_len;
     sec_asn1d_state *parent;
 
 #ifdef DEBUG_ASN1D_STATES
     {
-        printf("Found Length %d %s\n", state->contents_length,
+        printf("Found Length %lu %s\n", state->contents_length,
                state->indefinite ? "indefinite" : "");
     }
 #endif
 
     /**
      * The maximum length for a child element should be constrained to the
      * length remaining in the first definite length element in the ancestor
      * stack. If there is no definite length element in the ancestor stack,
@@ -2712,26 +2712,25 @@ dump_states(SEC_ASN1DecoderContext *cx)
 
     for (; state; state = state->child) {
         int i;
         for (i = 0; i < state->depth; i++) {
             printf("  ");
         }
 
         i = formatKind(state->theTemplate->kind, kindBuf);
-        printf("%s: tmpl %08x, kind%s",
+        printf("%s: tmpl kind %s",
                (state == cx->current) ? "STATE" : "State",
-               state->theTemplate,
                kindBuf);
         printf(" %s", (state->place >= 0 && state->place <= notInUse) ? place_names[state->place] : "(undefined)");
         if (!i)
-            printf(", expect 0x%02x",
+            printf(", expect 0x%02lx",
                    state->expect_tag_number | state->expect_tag_modifiers);
 
-        printf("%s%s%s %d\n",
+        printf("%s%s%s %lu\n",
                state->indefinite ? ", indef" : "",
                state->missing ? ", miss" : "",
                state->endofcontents ? ", EOC" : "",
                state->pending);
     }
 
     return;
 }
@@ -2749,17 +2748,17 @@ SEC_ASN1DecoderUpdate(SEC_ASN1DecoderCon
     if (cx->status == needBytes)
         cx->status = keepGoing;
 
     while (cx->status == keepGoing) {
         state = cx->current;
         what = SEC_ASN1_Contents;
         consumed = 0;
 #ifdef DEBUG_ASN1D_STATES
-        printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n",
+        printf("\nPLACE = %s, next byte = 0x%02x, %p[%lu]\n",
                (state->place >= 0 && state->place <= notInUse) ? place_names[state->place] : "(undefined)",
                len ? (unsigned int)((unsigned char *)buf)[consumed] : 0,
                buf, consumed);
         dump_states(cx);
 #endif /* DEBUG_ASN1D_STATES */
         switch (state->place) {
             case beforeIdentifier:
                 consumed = sec_asn1d_parse_identifier(state, buf, len);
@@ -2972,17 +2971,17 @@ SEC_ASN1DecoderUpdate(SEC_ASN1DecoderCon
     return SECSuccess;
 }
 
 SECStatus
 SEC_ASN1DecoderFinish(SEC_ASN1DecoderContext *cx)
 {
     SECStatus rv;
 
-    if (cx->status == needBytes) {
+    if (!cx || cx->status == needBytes) {
         PORT_SetError(SEC_ERROR_BAD_DER);
         rv = SECFailure;
     } else {
         rv = SECSuccess;
     }
 
     /*
      * XXX anything else that needs to be finished?
--- a/security/nss/tests/ssl_gtests/ssl_gtests.sh
+++ b/security/nss/tests/ssl_gtests/ssl_gtests.sh
@@ -42,16 +42,17 @@ certscript() {
 make_cert() {
   name=$1
   type=$2
   unset type_args trust sign
   case $type in
     dsa) type_args='-g 1024' ;;
     rsa) type_args='-g 1024' ;;
     rsa2048) type_args='-g 2048';type=rsa ;;
+    rsa8192) type_args='-g 8192';type=rsa ;;
     rsapss) type_args='-g 1024 --pss';type=rsa ;;
     p256) type_args='-q nistp256';type=ec ;;
     p384) type_args='-q secp384r1';type=ec ;;
     p521) type_args='-q secp521r1';type=ec ;;
     rsa_ca) type_args='-g 1024';trust='CT,CT,CT';type=rsa ;;
     rsa_chain) type_args='-g 1024';sign='-c rsa_ca';type=rsa;;
     rsapss_ca) type_args='-g 1024 --pss';trust='CT,CT,CT';type=rsa ;;
     rsapss_chain) type_args='-g 1024';sign='-c rsa_pss_ca';type=rsa;;
@@ -78,16 +79,17 @@ ssl_gtest_certs() {
 
   ${BINDIR}/certutil -N -d "${PROFILEDIR}" --empty-password 2>&1
   html_msg $? 0 "create ssl_gtest database"
 
   counter=0
   make_cert client rsa sign
   make_cert rsa rsa sign kex
   make_cert rsa2048 rsa2048 sign kex
+  make_cert rsa8192 rsa8192 sign kex
   make_cert rsa_sign rsa sign
   make_cert rsa_pss rsapss sign
   make_cert rsa_decrypt rsa kex
   make_cert ecdsa256 p256 sign
   make_cert ecdsa384 p384 sign
   make_cert ecdsa521 p521 sign
   make_cert ecdh_ecdsa p256 kex
   make_cert rsa_ca rsa_ca ca
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -660,17 +660,17 @@ impl<'le> GeckoElement<'le> {
             );
             binding_parent
         }
     }
 
     fn non_xul_xbl_binding_parent_raw_content(&self) -> *mut nsIContent {
         debug_assert!(!self.is_xul_element());
         self.extended_slots()
-            .map_or(ptr::null_mut(), |slots| slots._base.mBindingParent)
+            .map_or(ptr::null_mut(), |slots| slots._base.mBindingParent.raw::<nsIContent>())
     }
 
     #[inline]
     fn namespace_id(&self) -> i32 {
         self.as_node().node_info().mInner.mNamespaceID
     }
 
     #[inline]
--- a/xpcom/ds/Observer.h
+++ b/xpcom/ds/Observer.h
@@ -52,32 +52,52 @@ public:
   }
 
   /**
    * Remove the observer from the observer list.
    * @return Whether the observer has been found in the list.
    */
   bool RemoveObserver(Observer<T>* aObserver)
   {
-    return mObservers.RemoveElement(aObserver);
+    if (mObservers.RemoveElement(aObserver)) {
+      if (!mBroadcastCopy.IsEmpty()) {
+        // Annoyingly, someone could RemoveObserver() an item on the list
+        // while we're in a Broadcast()'s Notify() call.
+        auto i = mBroadcastCopy.IndexOf(aObserver);
+        MOZ_ASSERT(i != mBroadcastCopy.NoIndex);
+        mBroadcastCopy[i] = nullptr;
+      }
+      return true;
+    }
+    return false;
   }
 
   uint32_t Length()
   {
     return mObservers.Length();
   }
 
+  /**
+   * Call Notify() on each item in the list.
+   * Handles the case of Notify() calling RemoveObserver()
+   */
   void Broadcast(const T& aParam)
   {
-    nsTArray<Observer<T>*> observersCopy(mObservers);
-    uint32_t size = observersCopy.Length();
+    MOZ_ASSERT(mBroadcastCopy.IsEmpty());
+    mBroadcastCopy = mObservers;
+    uint32_t size = mBroadcastCopy.Length();
     for (uint32_t i = 0; i < size; ++i) {
-      observersCopy[i]->Notify(aParam);
+      // nulled if Removed during Broadcast
+      if (mBroadcastCopy[i]) {
+        mBroadcastCopy[i]->Notify(aParam);
+      }
     }
+    mBroadcastCopy.Clear();
   }
 
 protected:
   nsTArray<Observer<T>*> mObservers;
+  nsTArray<Observer<T>*> mBroadcastCopy;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_Observer_h