diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 1de0a581a..50988de95 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1656,7 +1656,7 @@ nsGlobalWindow::ClearControllers() } void -nsGlobalWindow::FreeInnerObjects() +nsGlobalWindow::FreeInnerObjects(bool aForDocumentOpen) { NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window"); @@ -1709,8 +1709,10 @@ nsGlobalWindow::FreeInnerObjects() mDocumentURI = mDoc->GetDocumentURI(); mDocBaseURI = mDoc->GetDocBaseURI(); - while (mDoc->EventHandlingSuppressed()) { - mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false); + if (!aForDocumentOpen) { + while (mDoc->EventHandlingSuppressed()) { + mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false); + } } // Note: we don't have to worry about eAnimationsOnly suppressions because @@ -2522,6 +2524,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, nsCOMPtr wsh = do_QueryInterface(aState); NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?"); + bool handleDocumentOpen = false; + JS::Rooted newInnerGlobal(cx); if (reUseInnerWindow) { // We're reusing the current inner window. @@ -2604,6 +2608,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, if (currentInner && currentInner->GetWrapperPreserveColor()) { if (oldDoc == aDocument) { + handleDocumentOpen = true; // Move the navigator from the old inner window to the new one since // this is a document.write. This is safe from a same-origin point of // view because document.write can only be used by the same origin. @@ -2629,7 +2634,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, // Don't free objects on our current inner window if it's going to be // held in the bfcache. if (!currentInner->IsFrozen()) { - currentInner->FreeInnerObjects(); + currentInner->FreeInnerObjects(handleDocumentOpen); } } diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index e6361d7e9..6a7b0a6cc 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -1311,7 +1311,7 @@ protected: } } - void FreeInnerObjects(); + void FreeInnerObjects(bool aForDocumentOpen = false); nsGlobalWindow *CallerInnerWindow(); // Only to be called on an inner window. diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 86196998f..8f0188745 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -35,6 +35,7 @@ static const double TO_DOUBLE_HIGH_SCALE = 0x100000000; void MacroAssemblerX86::convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) { +#error check TenFourFox issue 526 and bug 1499198. may be safest to just always use the SSE2 routine // SUBPD needs SSE2, HADDPD needs SSE3. if (!HasSSE3()) { convertUInt32ToDouble(src.high, dest); diff --git a/netwerk/protocol/http/Http2Compression.cpp b/netwerk/protocol/http/Http2Compression.cpp index 154f48f09..e726d5b38 100644 --- a/netwerk/protocol/http/Http2Compression.cpp +++ b/netwerk/protocol/http/Http2Compression.cpp @@ -359,7 +359,7 @@ Http2Decompressor::DecodeHeaderBlock(const uint8_t *data, uint32_t datalen, nsresult rv = NS_OK; nsresult softfail_rv = NS_OK; - while (NS_SUCCEEDED(rv) && (mOffset < datalen)) { + while (NS_SUCCEEDED(rv) && (mOffset < mDataLen)) { bool modifiesTable = true; if (mData[mOffset] & 0x80) { rv = DoIndexed(); @@ -603,6 +603,11 @@ nsresult Http2Decompressor::DecodeFinalHuffmanCharacter(HuffmanIncomingTable *table, uint8_t &c, uint8_t &bitsLeft) { + MOZ_ASSERT(mOffset <= mDataLen); + if (MOZ_UNLIKELY(mOffset > mDataLen)) { + NS_WARNING("DecodeFinalHuffmanCharacter would read beyond end of buffer"); + return NS_ERROR_FAILURE; + } uint8_t mask = (1 << bitsLeft) - 1; uint8_t idx = mData[mOffset - 1] & mask; idx <<= (8 - bitsLeft); @@ -640,6 +645,7 @@ Http2Decompressor::DecodeFinalHuffmanCharacter(HuffmanIncomingTable *table, uint8_t Http2Decompressor::ExtractByte(uint8_t bitsLeft, uint32_t &bytesConsumed) { + MOZ_DIAGNOSTIC_ASSERT(mOffset < mDataLen); uint8_t rv; if (bitsLeft) { @@ -670,8 +676,8 @@ Http2Decompressor::DecodeHuffmanCharacter(HuffmanIncomingTable *table, HuffmanIncomingEntry *entry = &(table->mEntries[idx]); if (entry->mPtr) { - if (bytesConsumed >= mDataLen) { - if (!bitsLeft || (bytesConsumed > mDataLen)) { + if (mOffset >= mDataLen) { + if (MOZ_UNLIKELY(!bitsLeft || (mOffset > mDataLen))) { // TODO - does this get me into trouble in the new world? // No info left in input to try to consume, we're done LOG(("DecodeHuffmanCharacter all out of bits to consume, can't chain")); @@ -811,6 +817,13 @@ Http2Decompressor::DoLiteralInternal(nsACString &name, nsACString &value, return rv; } + // sanity check + if (MOZ_UNLIKELY(mOffset >= mDataLen)) { + NS_WARNING("Http2 Decompressor ran out of data"); + // This is session-fatal + return NS_ERROR_FAILURE; + } + bool isHuffmanEncoded; if (!index) { @@ -838,6 +851,13 @@ Http2Decompressor::DoLiteralInternal(nsACString &name, nsACString &value, return rv; } + // sanity check + if (MOZ_UNLIKELY(mOffset >= mDataLen)) { + NS_WARNING("Http2 Decompressor ran out of data"); + // This is session-fatal + return NS_ERROR_FAILURE; + } + // now the value uint32_t valueLen; isHuffmanEncoded = mData[mOffset] & (1 << 7); diff --git a/security/manager/ssl/nsNSSCertificate.cpp b/security/manager/ssl/nsNSSCertificate.cpp index 1507e4521..72cb2f867 100644 --- a/security/manager/ssl/nsNSSCertificate.cpp +++ b/security/manager/ssl/nsNSSCertificate.cpp @@ -1544,6 +1544,10 @@ void nsNSSCertList::destructorSafeDestroyNSSReference() NS_IMETHODIMP nsNSSCertList::AddCert(nsIX509Cert* aCert) { + if (!aCert) { + return NS_ERROR_INVALID_ARG; + } + nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) { return NS_ERROR_NOT_AVAILABLE; @@ -1698,17 +1702,19 @@ nsNSSCertList::Read(nsIObjectInputStream* aStream) nsCOMPtr certSupports; rv = aStream->ReadObject(true, getter_AddRefs(certSupports)); if (NS_FAILED(rv)) { - break; + return rv; } - nsCOMPtr cert = do_QueryInterface(certSupports); + if (!cert) { + return NS_ERROR_UNEXPECTED; + } rv = AddCert(cert); if (NS_FAILED(rv)) { - break; + return rv; } } - return rv; + return NS_OK; } NS_IMETHODIMP diff --git a/xpcom/glue/nsTArray-inl.h b/xpcom/glue/nsTArray-inl.h index 1e359a4c6..642e19ed3 100644 --- a/xpcom/glue/nsTArray-inl.h +++ b/xpcom/glue/nsTArray-inl.h @@ -108,6 +108,23 @@ nsTArray_base::UsesAutoArrayBuffer() const bool IsTwiceTheRequiredBytesRepresentableAsUint32(size_t aCapacity, size_t aElemSize); +template +template +typename ActualAlloc::ResultTypeProxy +nsTArray_base::ExtendCapacity(size_type aLength, + size_type aCount, + size_type aElemSize) +{ + mozilla::CheckedInt newLength = aLength; + newLength += aCount; + + if (!newLength.isValid()) { + return ActualAlloc::FailureResult(); + } + + return this->EnsureCapacity(newLength.value(), aElemSize); +} + template template typename ActualAlloc::ResultTypeProxy @@ -275,26 +292,22 @@ nsTArray_base::ShiftData(index_type aStart, template template -bool +typename ActualAlloc::ResultTypeProxy nsTArray_base::InsertSlotsAt(index_type aIndex, size_type aCount, size_type aElemSize, size_t aElemAlign) { MOZ_ASSERT(aIndex <= Length(), "Bogus insertion index"); - size_type newLen = Length() + aCount; - EnsureCapacity(newLen, aElemSize); - - // Check for out of memory conditions - if (Capacity() < newLen) { - return false; + if (!ActualAlloc::Successful(this->ExtendCapacity(Length(), aCount, aElemSize))) { + return ActualAlloc::FailureResult(); } // Move the existing elements as needed. Note that this will // change our mLength, so no need to call IncrementLength. ShiftData(aIndex, 0, aCount, aElemSize, aElemAlign); - return true; + return ActualAlloc::SuccessResult(); } // nsTArray_base::IsAutoArrayRestorer is an RAII class which takes diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index efae00283..ad80cab8d 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -12,6 +12,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/BinarySearch.h" +#include "mozilla/CheckedInt.h" #include "mozilla/fallible.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/MemoryReporting.h" @@ -383,6 +384,17 @@ protected: typename ActualAlloc::ResultTypeProxy EnsureCapacity(size_type aCapacity, size_type aElemSize); + // Extend the storage to accommodate aCount extra elements. + // @param aLength The current size of the array. + // @param aCount The number of elements to add. + // @param aElemSize The size of an array element. + // @return False if insufficient memory is available or the new length + // would overflow; true otherwise. + template + typename ActualAlloc::ResultTypeProxy ExtendCapacity(size_type aLength, + size_type aCount, + size_type aElemSize); + // Tries to resize the storage to the minimum required amount. If this fails, // the array is left as-is. // @param aElemSize The size of an array element. @@ -424,8 +436,9 @@ protected: // @param aElementSize the size of an array element. // @param aElemAlign the alignment in bytes of an array element. template - bool InsertSlotsAt(index_type aIndex, size_type aCount, - size_type aElementSize, size_t aElemAlign); + typename ActualAlloc::ResultTypeProxy + InsertSlotsAt(index_type aIndex, size_type aCount, + size_type aElementSize, size_t aElemAlign); template typename ActualAlloc::ResultTypeProxy @@ -1379,6 +1392,7 @@ protected: template elem_type* InsertElementAt(index_type aIndex) { + // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK. if (!ActualAlloc::Successful(this->template EnsureCapacity( Length() + 1, sizeof(elem_type)))) { return nullptr; @@ -1402,6 +1416,7 @@ protected: template elem_type* InsertElementAt(index_type aIndex, Item&& aItem) { + // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK. if (!ActualAlloc::Successful(this->template EnsureCapacity( Length() + 1, sizeof(elem_type)))) { return nullptr; @@ -1508,8 +1523,8 @@ protected: template elem_type* AppendElements(const Item* aArray, size_type aArrayLen) { - if (!ActualAlloc::Successful(this->template EnsureCapacity( - Length() + aArrayLen, sizeof(elem_type)))) { + if (!ActualAlloc::Successful(this->template ExtendCapacity( + Length(), aArrayLen, sizeof(elem_type)))) { return nullptr; } index_type len = Length(); @@ -1558,8 +1573,8 @@ protected: index_type len = Length(); index_type otherLen = aArray.Length(); - if (!Alloc::Successful(this->template EnsureCapacity( - len + otherLen, sizeof(elem_type)))) { + if (!Alloc::Successful(this->template ExtendCapacity( + len, otherLen, sizeof(elem_type)))) { return nullptr; } copy_type::CopyElements(Elements() + len, aArray.Elements(), otherLen, @@ -1584,6 +1599,7 @@ protected: template elem_type* AppendElement(Item&& aItem) { + // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK. if (!ActualAlloc::Successful(this->template EnsureCapacity( Length() + 1, sizeof(elem_type)))) { return nullptr; @@ -1609,8 +1625,8 @@ public: protected: template elem_type* AppendElements(size_type aCount) { - if (!ActualAlloc::Successful(this->template EnsureCapacity( - Length() + aCount, sizeof(elem_type)))) { + if (!ActualAlloc::Successful(this->template ExtendCapacity( + Length(), aCount, sizeof(elem_type)))) { return nullptr; } elem_type* elems = Elements() + Length(); @@ -1828,9 +1844,8 @@ protected: template elem_type* InsertElementsAt(index_type aIndex, size_type aCount) { - if (!base_type::template InsertSlotsAt(aIndex, aCount, - sizeof(elem_type), - MOZ_ALIGNOF(elem_type))) { + if (!ActualAlloc::Successful(this->template InsertSlotsAt( + aIndex, aCount, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) { return nullptr; } @@ -1864,9 +1879,8 @@ protected: elem_type* InsertElementsAt(index_type aIndex, size_type aCount, const Item& aItem) { - if (!base_type::template InsertSlotsAt(aIndex, aCount, - sizeof(elem_type), - MOZ_ALIGNOF(elem_type))) { + if (!ActualAlloc::Successful(this->template InsertSlotsAt( + aIndex, aCount, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) { return nullptr; } @@ -1952,11 +1966,11 @@ public: // Adds an element to the heap // @param aItem The item to add // @param aComp The Comparator used to sift-up the item - template + template elem_type* PushHeap(const Item& aItem, const Comparator& aComp) { - if (!base_type::template InsertSlotsAt(Length(), 1, sizeof(elem_type), - MOZ_ALIGNOF(elem_type))) { + if (!ActualAlloc::Successful(this->template InsertSlotsAt( + Length(), 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) { return nullptr; } // Sift up the new node