diff --git a/dom/html/TextTrackManager.cpp b/dom/html/TextTrackManager.cpp index 4b69675a0d..b68fdb6aca 100644 --- a/dom/html/TextTrackManager.cpp +++ b/dom/html/TextTrackManager.cpp @@ -211,6 +211,7 @@ TextTrackManager::AddCues(TextTrack* aTextTrack) for (uint32_t i = 0; i < cueList->Length(); ++i) { mNewCues->AddCue(*cueList->IndexedGetter(i, dummy)); } + RefPtr kungFuDeathGrip(this); DispatchTimeMarchesOn(); } } @@ -236,6 +237,7 @@ TextTrackManager::RemoveTextTrack(TextTrack* aTextTrack, bool aPendingListOnly) for (uint32_t i = 0; i < removeCueList->Length(); ++i) { mNewCues->RemoveCue(*((*removeCueList)[i])); } + RefPtr kungFuDeathGrip(this); DispatchTimeMarchesOn(); } } @@ -305,6 +307,7 @@ TextTrackManager::NotifyCueAdded(TextTrackCue& aCue) if (mNewCues) { mNewCues->AddCue(aCue); } + RefPtr kungFuDeathGrip(this); DispatchTimeMarchesOn(); } @@ -315,6 +318,7 @@ TextTrackManager::NotifyCueRemoved(TextTrackCue& aCue) if (mNewCues) { mNewCues->RemoveCue(aCue); } + RefPtr kungFuDeathGrip(this); DispatchTimeMarchesOn(); if (aCue.GetActive()) { // We remove an active cue, need to update the display. @@ -824,6 +828,7 @@ TextTrackManager::NotifyCueUpdated(TextTrackCue *aCue) { // TODO: Add/Reorder the cue to mNewCues if we have some optimization? WEBVTT_LOG("NotifyCueUpdated"); + RefPtr kungFuDeathGrip(this); DispatchTimeMarchesOn(); } diff --git a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp index 18c15df429..27a9e9bf8c 100644 --- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp @@ -83,7 +83,7 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames) #ifdef MOZ_SAMPLE_TYPE_FLOAT32 // Planar audio data. Pack it into something we can understand. AudioDataValue* tmp = audio.get(); - AudioDataValue** data = reinterpret_cast(aFrame->data); + AudioDataValue** data = reinterpret_cast(aFrame->extended_data); for (uint32_t frame = 0; frame < aNumAFrames; frame++) { for (uint32_t channel = 0; channel < aNumChannels; channel++) { *tmp++ = data[channel][frame]; @@ -121,7 +121,7 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames) // Planar audio data. Convert it from S16 to 32 bits float // and pack it into something we can understand. AudioDataValue* tmp = audio.get(); - int16_t** data = reinterpret_cast(aFrame->data); + int16_t** data = reinterpret_cast(aFrame->extended_data); for (uint32_t frame = 0; frame < aNumAFrames; frame++) { for (uint32_t channel = 0; channel < aNumChannels; channel++) { *tmp++ = AudioSampleToFloat(data[channel][frame]); @@ -140,7 +140,7 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames) // Planar audio data. Convert it from S32 to 32 bits float // and pack it into something we can understand. AudioDataValue* tmp = audio.get(); - int32_t** data = reinterpret_cast(aFrame->data); + int32_t** data = reinterpret_cast(aFrame->extended_data); for (uint32_t frame = 0; frame < aNumAFrames; frame++) { for (uint32_t channel = 0; channel < aNumChannels; channel++) { *tmp++ = AudioSampleToFloat(data[channel][frame]); diff --git a/gfx/ots/src/cmap.cc b/gfx/ots/src/cmap.cc index 72c2a20fc4..9cfd0039b6 100644 --- a/gfx/ots/src/cmap.cc +++ b/gfx/ots/src/cmap.cc @@ -314,8 +314,9 @@ bool OpenTypeCMAP::Parse31012(const uint8_t *data, size_t length, return Error("format 12 subtable group endCharCode before startCharCode (0x%4X < 0x%4X)", groups[i].end_range, groups[i].start_range); } + // Maximum glyph ID must be less than num_glyphs. if ((groups[i].end_range - groups[i].start_range) + - groups[i].start_glyph_id > num_glyphs) { + groups[i].start_glyph_id >= num_glyphs) { return Error("bad format 12 subtable group startGlyphID (%d)", groups[i].start_glyph_id); } } diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp index 7f05f9011f..23dddb604f 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -554,15 +554,17 @@ gfxHarfBuzzShaper::FindGlyf(hb_codepoint_t aGlyph, bool *aEmptyGlyf) const uint32_t len; const char* data = hb_blob_get_data(mLocaTable, &len); if (mLocaLongOffsets) { - if ((aGlyph + 1) * sizeof(AutoSwap_PRUint32) > len) { + // We read offsets[aGlyph] and offsets[aGlyph + 1], so require aGlyph + 2 entries. + if ((aGlyph + 2) * sizeof(AutoSwap_PRUint32) > len) { return nullptr; } const AutoSwap_PRUint32* offsets = reinterpret_cast(data); offset = offsets[aGlyph]; - *aEmptyGlyf = (offset == uint16_t(offsets[aGlyph + 1])); + *aEmptyGlyf = (offset == uint32_t(offsets[aGlyph + 1])); } else { - if ((aGlyph + 1) * sizeof(AutoSwap_PRUint16) > len) { + // Ditto aGlyph + 2 entries. + if ((aGlyph + 2) * sizeof(AutoSwap_PRUint16) > len) { return nullptr; } const AutoSwap_PRUint16* offsets = diff --git a/image/ImageWrapper.cpp b/image/ImageWrapper.cpp index c593521c9e..1e3bd3a2f0 100644 --- a/image/ImageWrapper.cpp +++ b/image/ImageWrapper.cpp @@ -252,7 +252,8 @@ ImageWrapper::RequestDiscard() NS_IMETHODIMP_(void) ImageWrapper::RequestRefresh(const TimeStamp& aTime) { - return mInnerImage->RequestRefresh(aTime); + RefPtr inner = mInnerImage; + return inner->RequestRefresh(aTime); } NS_IMETHODIMP diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index 31a6d7a991..af639f3386 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -94,6 +94,8 @@ RasterImage::RasterImage(ImageURL* aURI /* = nullptr */) : //****************************************************************************** RasterImage::~RasterImage() { + mIsBeingDestroyed = true; + // Make sure our SourceBuffer is marked as complete. This will ensure that any // outstanding decoders terminate. if (!mSourceBuffer->IsComplete()) { @@ -429,8 +431,11 @@ RasterImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) { MOZ_ASSERT(mProgressTracker); - bool animatedFramesDiscarded = - mAnimationState && aSurfaceKey.Playback() == PlaybackType::eAnimated; + if (mIsBeingDestroyed) { + return; + } + + bool animatedFramesDiscarded = aSurfaceKey.Playback() == PlaybackType::eAnimated; RefPtr image = this; NS_DispatchToMainThread(NS_NewRunnableFunction([=]() -> void { diff --git a/image/RasterImage.h b/image/RasterImage.h index e1a7cb1506..64596ff924 100644 --- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -17,6 +17,7 @@ #ifndef mozilla_image_RasterImage_h #define mozilla_image_RasterImage_h +#include "mozilla/Atomics.h" #include "Image.h" #include "nsCOMPtr.h" #include "imgIContainer.h" @@ -384,10 +385,10 @@ private: // data /// If this has a value, we're waiting for SetSize() to send the load event. Maybe mLoadProgress; - nsCOMPtr mProperties; + nsCOMPtr mProperties; /// If this image is animated, a FrameAnimator which manages its animation. - UniquePtr mFrameAnimator; + UniquePtr mFrameAnimator; /// Animation timeline and other state for animation images. Maybe mAnimationState; @@ -400,7 +401,9 @@ private: // data // How many times we've decoded this image. // This is currently only used for statistics - int32_t mDecodeCount; + int32_t mDecodeCount; + + Atomic mIsBeingDestroyed{false}; // A weak pointer to our ImageContainer, which stays alive only as long as // the layer system needs it. @@ -414,7 +417,7 @@ private: // data DrawResult mLastImageContainerDrawResult; #ifdef DEBUG - uint32_t mFramesNotified; + uint32_t mFramesNotified; #endif // The source data for this image. diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 35d5caedc3..a8bc678630 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -690,7 +690,7 @@ UnmappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleVal if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); - if (arg < argsobj->initialLength()) { + if (argsobj->isElement(arg)) { argsobj->setElement(cx, arg, vp); return result.succeed(); } diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 63dc044b0f..59097b710a 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -283,6 +283,20 @@ class ArgumentsObject : public NativeObject bool markElementDeleted(JSContext* cx, uint32_t i); + /* + * Return true if the index is a valid element index for this arguments + * object. + * + * Returning true here doesn't imply that the element value can be read + * through |ArgumentsObject::element()|. For example, unmapped arguments + * objects can have an element index property redefined without having marked + * the element as deleted. Instead, use |maybeGetElement()| or manually check + * for |hasOverriddenElement()|. + */ + bool isElement(uint32_t i) const { + return i < initialLength() && !isElementDeleted(i); + } + /* * An ArgumentsObject serves two roles: * - a real object, accessed through regular object operations, e.g.., diff --git a/js/src/vm/MatchPairs.h b/js/src/vm/MatchPairs.h index 07c545a7e5..7461ec1cb7 100644 --- a/js/src/vm/MatchPairs.h +++ b/js/src/vm/MatchPairs.h @@ -76,7 +76,10 @@ class MatchPairs virtual bool allocOrExpandArray(size_t pairCount) = 0; bool initArrayFrom(MatchPairs& copyFrom); - void forgetArray() { pairs_ = nullptr; } + void forgetArray() { + pairs_ = nullptr; + pairCount_ = 0; + } void checkAgainst(size_t inputLength) { #ifdef DEBUG diff --git a/js/src/vm/RegExpStatics.h b/js/src/vm/RegExpStatics.h index 686aa7be05..e3d978d4a8 100644 --- a/js/src/vm/RegExpStatics.h +++ b/js/src/vm/RegExpStatics.h @@ -351,6 +351,7 @@ RegExpStatics::updateFromMatchPairs(JSContext* cx, JSLinearString* input, MatchP if (!matches.initArrayFrom(newPairs)) { ReportOutOfMemory(cx); + clear(); return false; } diff --git a/media/ffvpx/libavcodec/vp9.c b/media/ffvpx/libavcodec/vp9.c index f2cf194243..e85e461722 100644 --- a/media/ffvpx/libavcodec/vp9.c +++ b/media/ffvpx/libavcodec/vp9.c @@ -207,8 +207,10 @@ static int update_size(AVCodecContext *avctx, int w, int h) *fmtp = AV_PIX_FMT_NONE; ret = ff_thread_get_format(avctx, pix_fmts); - if (ret < 0) + if (ret < 0) { + ff_set_dimensions(avctx, s->w, s->h); return ret; + } avctx->pix_fmt = ret; s->gf_fmt = s->pix_fmt; diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index 8bd423b901..0803a2b518 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -1015,6 +1015,9 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, nsIContent* table = *(mOne.node); nsIContent* stackParent = *(mTwo.node); nsIContent* fosterParent = GetFosterParent(table, stackParent); + if (fosterParent) { + aBuilder->HoldElement(do_AddRef(fosterParent)); + } *mThree.node = fosterParent; return NS_OK; } diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c index 4b080a0fb0..23b6a91537 100644 --- a/security/nss/lib/certhigh/certvfy.c +++ b/security/nss/lib/certhigh/certvfy.c @@ -725,7 +725,7 @@ cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert, certsList = tmpCertsList; } for (i = 0; i < subjectNameListLen; i++) { - certsList[namesCount + i] = subjectCert; + certsList[namesCount + i] = CERT_DupCertificate(subjectCert); } namesCount += subjectNameListLen; namesList = cert_CombineNamesLists(namesList, subjectNameList); @@ -972,6 +972,11 @@ loser: rv = SECFailure; done: if (certsList != NULL) { + for (int i = 0; i < namesCount; i++) { + if (certsList[i]) { + CERT_DestroyCertificate(certsList[i]); + } + } PORT_Free(certsList); } if (issuerCert) { diff --git a/security/nss/lib/pk11wrap/pk11pk12.c b/security/nss/lib/pk11wrap/pk11pk12.c index 4f8f9d2518..de86dbe752 100644 --- a/security/nss/lib/pk11wrap/pk11pk12.c +++ b/security/nss/lib/pk11wrap/pk11pk12.c @@ -650,12 +650,15 @@ PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, rv = PK11_ImportAndReturnPrivateKey(slot, lpk, nickname, publicValue, isPerm, isPrivate, keyUsage, privk, wincx); -loser: - if (arena != NULL) { - PORT_FreeArena(arena, PR_TRUE); + if (rv != SECSuccess) { + goto loser; } + PORT_FreeArena(arena, PR_TRUE); + return SECSuccess; - return rv; +loser: + PORT_FreeArena(arena, PR_TRUE); + return SECFailure; } SECStatus diff --git a/security/nss/lib/smime/cmsdecode.c b/security/nss/lib/smime/cmsdecode.c index 69965bdd7d..0edea07d43 100644 --- a/security/nss/lib/smime/cmsdecode.c +++ b/security/nss/lib/smime/cmsdecode.c @@ -529,8 +529,19 @@ nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, SECItem *dataItem = &decoderData->data; offset = dataItem->len; + /* Reject if accumulated size would exceed unsigned int storage. */ + if (len > (unsigned long)(PR_UINT32_MAX - dataItem->len)) { + p7dcx->error = SEC_ERROR_INPUT_LEN; + goto loser; + } if (dataItem->len + len > decoderData->totalBufferSize) { - int needLen = (dataItem->len + len) * 2; + /* Use size_t to avoid truncating the 64-bit sum to int. + * Double to amortize repeated reallocations across chunks. */ + size_t needLen = (size_t)dataItem->len + len; + /* Only double if the result still fits in unsigned int. */ + if (needLen <= PR_UINT32_MAX / 2) { + needLen *= 2; + } dest = (unsigned char *) PORT_ArenaAlloc(p7dcx->cmsg->poolp, needLen); if (dest == NULL) { @@ -541,7 +552,7 @@ nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, if (dataItem->len) { PORT_Memcpy(dest, dataItem->data, dataItem->len); } - decoderData->totalBufferSize = needLen; + decoderData->totalBufferSize = (unsigned int)needLen; dataItem->data = dest; }