From 1bc1dd390db76a0fbe33c4fad0b8e23a77298a15 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sun, 16 Jul 2017 17:51:39 -0700 Subject: [PATCH] #416: M1374047 M1365413 M1369913 M1371424 M1346590 M1376087 M1322896 M1354796 M1365333 M1373970 M1355168 --- docshell/base/nsDocShell.cpp | 15 +++++ dom/base/DirectionalityUtils.cpp | 59 ++++++++++++++++--- dom/base/Element.cpp | 1 + dom/base/WebSocket.cpp | 18 ++++-- dom/base/nsImageLoadingContent.cpp | 13 +++- dom/bindings/TypedArray.h | 4 +- dom/canvas/CanvasRenderingContext2D.cpp | 15 +++-- dom/canvas/ImageBitmap.cpp | 9 ++- layout/base/nsDisplayList.cpp | 4 ++ netwerk/base/nsFileStreams.cpp | 4 ++ netwerk/protocol/http/nsHttpConnectionMgr.cpp | 4 +- 11 files changed, 120 insertions(+), 26 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index b9387dad5..f4ddc7647 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -11317,6 +11317,21 @@ nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel, nsISupports* aOwner, (void)AddToSessionHistory(aURI, aChannel, aOwner, aCloneSHChildren, getter_AddRefs(mLSHE)); } + } else if (mSessionHistory && mLSHE && mURIResultedInDocument) { + // Even if we don't add anything to SHistory, ensure the current index + // points to the same SHEntry as our mLSHE. + int32_t index = 0; + mSessionHistory->GetRequestedIndex(&index); + if (index == -1) { + mSessionHistory->GetIndex(&index); + } + nsCOMPtr currentSH; + mSessionHistory->GetEntryAtIndex(index, false, getter_AddRefs(currentSH)); + if (currentSH != mLSHE) { + nsCOMPtr shPrivate = + do_QueryInterface(mSessionHistory); + shPrivate->ReplaceEntry(index, mLSHE); + } } // If this is a POST request, we do not want to include this in global diff --git a/dom/base/DirectionalityUtils.cpp b/dom/base/DirectionalityUtils.cpp index 156f1b5e2..06877d0e9 100644 --- a/dom/base/DirectionalityUtils.cpp +++ b/dom/base/DirectionalityUtils.cpp @@ -209,6 +209,7 @@ #include "nsINode.h" #include "nsIContent.h" #include "nsIDocument.h" +#include "mozilla/AutoRestore.h" #include "mozilla/DebugOnly.h" #include "mozilla/dom/Element.h" #include "nsIDOMHTMLDocument.h" @@ -441,6 +442,7 @@ class nsTextNodeDirectionalityMap public: explicit nsTextNodeDirectionalityMap(nsINode* aTextNode) + : mElementToBeRemoved(nullptr) { MOZ_ASSERT(aTextNode, "Null text node"); MOZ_COUNT_CTOR(nsTextNodeDirectionalityMap); @@ -454,11 +456,28 @@ public: MOZ_COUNT_DTOR(nsTextNodeDirectionalityMap); } + static void + nsTextNodeDirectionalityMapPropertyDestructor(void* aObject, + nsIAtom* aProperty, + void* aPropertyValue, + void* aData) + { + nsTextNode* textNode = + static_cast(aPropertyValue); + nsTextNodeDirectionalityMap* map = GetDirectionalityMap(textNode); + if (map) { + map->RemoveEntryForProperty(static_cast(aObject)); + } + NS_RELEASE(textNode); + } + void AddEntry(nsINode* aTextNode, Element* aElement) { if (!mElements.Contains(aElement)) { mElements.Put(aElement); - aElement->SetProperty(nsGkAtoms::dirAutoSetBy, aTextNode); + NS_ADDREF(aTextNode); + aElement->SetProperty(nsGkAtoms::dirAutoSetBy, aTextNode, + nsTextNodeDirectionalityMapPropertyDestructor); aElement->SetHasDirAutoSet(); } } @@ -470,11 +489,21 @@ public: mElements.Remove(aElement); aElement->ClearHasDirAutoSet(); - aElement->UnsetProperty(nsGkAtoms::dirAutoSetBy); + aElement->DeleteProperty(nsGkAtoms::dirAutoSetBy); + } + + void RemoveEntryForProperty(Element* aElement) + { + if (mElementToBeRemoved != aElement) { + mElements.Remove(aElement); + } + aElement->ClearHasDirAutoSet(); } private: - nsCheapSet > mElements; + nsCheapSet> mElements; + // Only used for comparison. + Element* mElementToBeRemoved; static nsTextNodeDirectionalityMap* GetDirectionalityMap(nsINode* aTextNode) { @@ -498,18 +527,29 @@ private: return OpNext; } + struct nsTextNodeDirectionalityMapAndElement + { + nsTextNodeDirectionalityMap* mMap; + nsCOMPtr mNode; + }; + static nsCheapSetOperator ResetNodeDirection(nsPtrHashKey* aEntry, void* aData) { MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element"); // run the downward propagation algorithm // and remove the text node from the map - nsINode* oldTextNode = static_cast(aData); + nsTextNodeDirectionalityMapAndElement* data = + static_cast(aData); + nsINode* oldTextNode = data->mNode; Element* rootNode = aEntry->GetKey(); nsINode* newTextNode = nullptr; if (rootNode->GetParentNode() && rootNode->HasDirAuto()) { newTextNode = WalkDescendantsSetDirectionFromText(rootNode, true, oldTextNode); } + + AutoRestore restore(data->mMap->mElementToBeRemoved); + data->mMap->mElementToBeRemoved = rootNode; if (newTextNode) { nsINode* oldDirAutoSetBy = static_cast(rootNode->GetProperty(nsGkAtoms::dirAutoSetBy)); @@ -520,7 +560,7 @@ private: nsTextNodeDirectionalityMap::AddEntryToMap(newTextNode, rootNode); } else { rootNode->ClearHasDirAutoSet(); - rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy); + rootNode->DeleteProperty(nsGkAtoms::dirAutoSetBy); } return OpRemove; } @@ -529,7 +569,7 @@ private: { Element* rootNode = aEntry->GetKey(); rootNode->ClearHasDirAutoSet(); - rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy); + rootNode->DeleteProperty(nsGkAtoms::dirAutoSetBy); return OpRemove; } @@ -541,11 +581,13 @@ public: void ResetAutoDirection(nsINode* aTextNode) { - mElements.EnumerateEntries(ResetNodeDirection, aTextNode); + nsTextNodeDirectionalityMapAndElement data = { this, aTextNode }; + mElements.EnumerateEntries(ResetNodeDirection, &data); } void EnsureMapIsClear(nsINode* aTextNode) { + AutoRestore restore(mElementToBeRemoved); DebugOnly clearedEntries = mElements.EnumerateEntries(ClearEntry, aTextNode); MOZ_ASSERT(clearedEntries == 0, "Map should be empty already"); @@ -581,7 +623,8 @@ public: { MOZ_ASSERT(aTextNode->HasTextNodeDirectionalityMap(), "Map missing in ResetTextNodeDirection"); - GetDirectionalityMap(aTextNode)->ResetAutoDirection(aChangedTextNode); + RefPtr textNode = aTextNode; + GetDirectionalityMap(textNode)->ResetAutoDirection(aChangedTextNode); } static void EnsureMapIsClearFor(nsINode* aTextNode) diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 2f482091f..ba8d23263 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -3102,6 +3102,7 @@ static nsIAtom** sPropertiesToTraverseAndUnlink[] = &nsGkAtoms::itemprop, &nsGkAtoms::sandbox, &nsGkAtoms::sizes, + &nsGkAtoms::dirAutoSetBy, nullptr }; diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp index c60ec8801..57ecd7090 100644 --- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -10,6 +10,7 @@ #include "jsapi.h" #include "jsfriendapi.h" +#include "mozilla/CheckedInt.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/net/WebSocketChannel.h" #include "mozilla/dom/File.h" @@ -610,6 +611,10 @@ WebSocketImpl::Disconnect() AssertIsOnTargetThread(); + // DontKeepAliveAnyMore() and DisconnectInternal() can release the object. So + // hold a reference to this until the end of the method. + RefPtr kungfuDeathGrip = this; + // Disconnect can be called from some control event (such as Notify() of // WorkerFeature). This will be schedulated before any other sync/async // runnable. In order to prevent some double Disconnect() calls, we use this @@ -631,10 +636,6 @@ WebSocketImpl::Disconnect() rv.SuppressException(); } - // DontKeepAliveAnyMore() can release the object. So hold a reference to this - // until the end of the method. - RefPtr kungfuDeathGrip = this; - NS_ReleaseOnMainThread(mChannel); NS_ReleaseOnMainThread(static_cast(mService.forget().take())); @@ -2380,7 +2381,14 @@ WebSocket::Send(nsIInputStream* aMsgStream, } // Always increment outgoing buffer len, even if closed - mOutgoingBufferedAmount += aMsgLength; + CheckedUint32 size = mOutgoingBufferedAmount; + size += aMsgLength; + if (MOZ_UNLIKELY(!size.isValid())) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + + mOutgoingBufferedAmount = size.value(); if (readyState == CLOSING || readyState == CLOSED) { diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index e7336207d..92cbd4386 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -148,15 +148,22 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest, } { - nsAutoScriptBlocker scriptBlocker; - + // Calling Notify on observers can modify the list of observers so make + // a local copy. + nsAutoTArray, 2> observers; for (ImageObserver* observer = &mObserverList, *next; observer; observer = next) { next = observer->mNext; if (observer->mObserver) { - observer->mObserver->Notify(aRequest, aType, aData); + observers.AppendElement(observer->mObserver); } } + + nsAutoScriptBlocker scriptBlocker; + + for (auto& observer : observers) { + observer->Notify(aRequest, aType, aData); + } } if (aType == imgINotificationObserver::SIZE_AVAILABLE) { diff --git a/dom/bindings/TypedArray.h b/dom/bindings/TypedArray.h index 8690d8b63..9d5f9b0f0 100644 --- a/dom/bindings/TypedArray.h +++ b/dom/bindings/TypedArray.h @@ -44,11 +44,13 @@ protected: public: inline void TraceSelf(JSTracer* trc) { + // XXX: Until we implement something like bug 1235598 (and its successor + // bug 1238786), we need these null checks. if (mTypedObj) { JS_CallUnbarrieredObjectTracer(trc, &mTypedObj, "TypedArray.mTypedObj"); } if (mWrappedObj) { - JS_CallUnbarrieredObjectTracer(trc, &mTypedObj, "TypedArray.mWrappedObj"); + JS_CallUnbarrieredObjectTracer(trc, &mWrappedObj, "TypedArray.mWrappedObj"); } } diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 4ee48e06f..7cf67d04a 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -4822,7 +4822,17 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x, return; } + // Flush layout updates + if (!(flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH)) { + nsContentUtils::FlushLayoutForTree(&window); + } + EnsureTarget(); + + if (!IsTargetValid()) { + return; + } + // We can't allow web apps to call this until we fix at least the // following potential security issues: // -- rendering cross-domain IFRAMEs and then extracting the results @@ -4836,11 +4846,6 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x, return; } - // Flush layout updates - if (!(flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH)) { - nsContentUtils::FlushLayoutForTree(&window); - } - RefPtr presContext; nsIDocShell* docshell = window.GetDocShell(); if (docshell) { diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp index 1103f2423..1896e5bb1 100644 --- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/ImageBitmap.h" +#include "mozilla/CheckedInt.h" #include "mozilla/dom/ImageBitmapBinding.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/StructuredCloneTags.h" @@ -132,10 +133,14 @@ CropAndCopyDataSourceSurface(DataSourceSurface* aSurface, const IntRect& aCropRe + surfPortion.x * bytesPerPixel; uint8_t* dstBufferPtr = dstMap.GetData() + dest.y * dstMap.GetStride() + dest.x * bytesPerPixel; - const uint32_t copiedBytesPerRaw = surfPortion.width * bytesPerPixel; + CheckedInt copiedBytesPerRaw = + CheckedInt(surfPortion.width) * bytesPerPixel; + if (MOZ_UNLIKELY(!copiedBytesPerRaw.isValid())) { + return nullptr; + } for (int i = 0; i < surfPortion.height; ++i) { - memcpy(dstBufferPtr, srcBufferPtr, copiedBytesPerRaw); + memcpy(dstBufferPtr, srcBufferPtr, copiedBytesPerRaw.value()); srcBufferPtr += srcMap.GetStride(); dstBufferPtr += dstMap.GetStride(); } diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 23e5316d4..edad66c30 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -3328,6 +3328,10 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder, if (borderBoxHasRoundedCorners || (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) { mMaybeHitRegion.Or(mMaybeHitRegion, borderBox); + + // Avoid quadratic performance as a result of the region growing to include + // an arbitrarily large number of rects, which can happen on some pages. + mMaybeHitRegion.SimplifyOutward(8); } else { mHitRegion.Or(mHitRegion, borderBox); } diff --git a/netwerk/base/nsFileStreams.cpp b/netwerk/base/nsFileStreams.cpp index 17a87a76b..08c4f1f19 100644 --- a/netwerk/base/nsFileStreams.cpp +++ b/netwerk/base/nsFileStreams.cpp @@ -897,6 +897,10 @@ nsAtomicFileOutputStream::DoOpen() nsCOMPtr file; file.swap(mOpenParams.localFile); + if(MOZ_UNLIKELY(!file)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsresult rv = file->Exists(&mTargetFileExists); if (NS_FAILED(rv)) { NS_ERROR("Can't tell if target file exists"); diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index a7100f21c..200a067b8 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -2831,9 +2831,9 @@ nsHttpConnectionMgr::TimeoutTickCB(const nsACString &key, LOG(("Force timeout of half open to %s after %.2fms.\n", ent->mConnInfo->HashKey().get(), delta)); if (half->SocketTransport()) - half->SocketTransport()->Close(NS_ERROR_ABORT); + half->SocketTransport()->Close(NS_ERROR_NET_TIMEOUT); if (half->BackupTransport()) - half->BackupTransport()->Close(NS_ERROR_ABORT); + half->BackupTransport()->Close(NS_ERROR_NET_TIMEOUT); } // If this half open hangs around for 5 seconds after we've closed() it