From 96244ab710ace7e051346bbf2c02fb6a86117986 Mon Sep 17 00:00:00 2001 From: Roy Tam Date: Wed, 20 Jun 2018 17:23:40 +0800 Subject: [PATCH] cherry-picked mozilla upstream changes: bug1378147, bug1364984, bug1334338, bug1379538, bug1356812, bug1379444, bug1372467, bug1372383, bug1383002, bug1308908, bug1347667, bug1367128, bug1377016, bug1359058, bug1379537 --- accessible/atk/AccessibleWrap.cpp | 3 +- accessible/base/nsAccCache.h | 17 ---- accessible/generic/DocAccessible.cpp | 12 ++- dom/html/ImageDocument.cpp | 8 +- dom/ipc/ContentChild.cpp | 1 + dom/media/fmp4/MP4Demuxer.cpp | 36 +++++---- gfx/thebes/gfxDWriteFontList.cpp | 20 +---- gfx/thebes/gfxDWriteFontList.h | 15 ++-- gfx/thebes/gfxMacPlatformFontList.h | 13 ++-- gfx/thebes/gfxMacPlatformFontList.mm | 20 +---- gfx/thebes/gfxPlatformFontList.cpp | 12 +++ gfx/thebes/gfxPlatformFontList.h | 24 ++++-- js/public/CharacterEncoding.h | 16 ++-- js/public/Utility.h | 2 +- js/src/jsalloc.h | 2 + js/src/jscompartment.cpp | 21 +++-- media/libstagefright/binding/Index.cpp | 48 +++++++++++- media/libstagefright/binding/MoofParser.cpp | 19 ++++- .../binding/include/mp4_demuxer/Index.h | 8 +- .../binding/include/mp4_demuxer/MoofParser.h | 6 +- .../webrtc/signaling/src/sdp/sipcc/sdp_attr.c | 10 ++- netwerk/mime/nsMIMEHeaderParamImpl.cpp | 4 +- python/mozbuild/mozpack/manifests.py | 7 ++ toolkit/components/places/Database.cpp | 78 +++++++++++-------- toolkit/components/places/Database.h | 6 -- .../tests/unit/test_corrupt_telemetry.js | 31 ++++++++ .../components/places/tests/unit/xpcshell.ini | 2 + toolkit/components/telemetry/Histograms.json | 9 +++ .../test/xpcshell/test_subprocess.js | 6 +- xpcom/io/CocoaFileUtils.h | 1 + xpcom/io/CocoaFileUtils.mm | 7 ++ xpcom/io/SpecialSystemDirectory.cpp | 17 +++- xpcom/tests/unit/test_file_equality.js | 4 + xpfe/appshell/nsXULWindow.cpp | 3 +- 34 files changed, 330 insertions(+), 158 deletions(-) create mode 100644 toolkit/components/places/tests/unit/test_corrupt_telemetry.js diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp index 8b33b5af1..0350af775 100644 --- a/accessible/atk/AccessibleWrap.cpp +++ b/accessible/atk/AccessibleWrap.cpp @@ -613,8 +613,7 @@ static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName) { NS_ConvertUTF16toUTF8 newNameUTF8(aNewName); - if (aAtkObj->name && - !strncmp(aAtkObj->name, newNameUTF8.get(), newNameUTF8.Length())) + if (aAtkObj->name && !strcmp(aAtkObj->name, newNameUTF8.get())) return; // Below we duplicate the functionality of atk_object_set_name(), diff --git a/accessible/base/nsAccCache.h b/accessible/base/nsAccCache.h index 4e97dbf2c..cb39accde 100644 --- a/accessible/base/nsAccCache.h +++ b/accessible/base/nsAccCache.h @@ -25,21 +25,4 @@ UnbindCacheEntriesFromDocument( } } -/** - * Clear the cache and shutdown the accessibles. - */ -template -static void -ClearCache(nsRefPtrHashtable, T>& aCache) -{ - for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) { - T* accessible = iter.Data(); - MOZ_ASSERT(accessible); - if (accessible && !accessible->IsDefunct()) { - accessible->Shutdown(); - } - iter.Remove(); - } -} - #endif diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index b917b8652..0418ad0ae 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -483,7 +483,17 @@ DocAccessible::Shutdown() mDependentIDsHash.Clear(); mNodeToAccessibleMap.Clear(); - ClearCache(mAccessibleCache); + + for (auto iter = mAccessibleCache.Iter(); !iter.Done(); iter.Next()) { + Accessible* accessible = iter.Data(); + MOZ_ASSERT(accessible); + if (accessible && !accessible->IsDefunct()) { + // Unlink parent to avoid its cleaning overhead in shutdown. + accessible->mParent = nullptr; + accessible->Shutdown(); + } + iter.Remove(); + } HyperTextAccessibleWrap::Shutdown(); diff --git a/dom/html/ImageDocument.cpp b/dom/html/ImageDocument.cpp index a3052d2dd..3191f1a48 100644 --- a/dom/html/ImageDocument.cpp +++ b/dom/html/ImageDocument.cpp @@ -339,7 +339,9 @@ ImageDocument::ShrinkToFit() // changed and we don't plan to adjust the image size to compensate. Since // mImageIsResized it has a "height" attribute set, and we can just get the // displayed image height by getting .height on the HTMLImageElement. - HTMLImageElement* img = HTMLImageElement::FromContent(mImageContent); + // + // Hold strong ref, because Height() can run script. + RefPtr img = HTMLImageElement::FromContent(mImageContent); uint32_t imageHeight = img->Height(); nsDOMTokenList* classList = img->ClassList(); ErrorResult ignored; @@ -622,7 +624,9 @@ ImageDocument::UpdateSizeFromLayout() return; } - nsIFrame* contentFrame = mImageContent->GetPrimaryFrame(FlushType::Frames); + // Need strong ref, because GetPrimaryFrame can run script. + nsCOMPtr imageContent = mImageContent; + nsIFrame* contentFrame = imageContent->GetPrimaryFrame(FlushType::Frames); if (!contentFrame) { return; } diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 40bc43dee..e8905ddd1 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1415,6 +1415,7 @@ StartMacOSContentSandbox() } nsAutoCString tempDirPath; + tempDir->Normalize(); rv = tempDir->GetNativePath(tempDirPath); if (NS_FAILED(rv)) { MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path"); diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index 93b67a6bf..8c06cab97 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -56,6 +56,8 @@ public: void BreakCycles() override; + void NotifyDataRemoved(); + private: friend class MP4Demuxer; void NotifyDataArrived(); @@ -198,7 +200,7 @@ void MP4Demuxer::NotifyDataRemoved() { for (uint32_t i = 0; i < mDemuxers.Length(); i++) { - mDemuxers[i]->NotifyDataArrived(); + mDemuxers[i]->NotifyDataRemoved(); } } @@ -295,21 +297,10 @@ MP4TrackDemuxer::Seek(const media::TimeUnit& aTime) mIterator->Seek(seekTime); // Check what time we actually seeked to. - RefPtr sample; - do { - sample = GetNextSample(); - if (!sample) { - return SeekPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__); - } - if (!sample->Size()) { - // This sample can't be decoded, continue searching. - continue; - } - if (sample->mKeyframe) { - mQueuedSample = sample; - seekTime = mQueuedSample->mTime; - } - } while (!mQueuedSample); + mQueuedSample = GetNextSample(); + if (mQueuedSample) { + seekTime = mQueuedSample->mTime; + } SetNextKeyFrameTime(); @@ -494,6 +485,19 @@ MP4TrackDemuxer::NotifyDataArrived() mNeedReIndex = true; } +void +MP4TrackDemuxer::NotifyDataRemoved() +{ + AutoPinned resource(mParent->mResource); + MediaByteRangeSet byteRanges; + nsresult rv = resource->GetCachedRanges(byteRanges); + if (NS_FAILED(rv)) { + return; + } + mIndex->UpdateMoofIndex(byteRanges, true /* can evict */); + mNeedReIndex = false; +} + void MP4TrackDemuxer::BreakCycles() { diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index 0b2fb6325..d159fddb1 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -1383,23 +1383,11 @@ IFACEMETHODIMP DWriteFontFallbackRenderer::DrawGlyphRun( } gfxFontEntry* -gfxDWriteFontList::GlobalFontFallback(const uint32_t aCh, - Script aRunScript, - const gfxFontStyle* aMatchStyle, - uint32_t& aCmapCount, - gfxFontFamily** aMatchedFamily) +gfxDWriteFontList::PlatformGlobalFontFallback(const uint32_t aCh, + Script aRunScript, + const gfxFontStyle* aMatchStyle, + gfxFontFamily** aMatchedFamily) { - bool useCmaps = IsFontFamilyWhitelistActive() || - gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); - - if (useCmaps) { - return gfxPlatformFontList::GlobalFontFallback(aCh, - aRunScript, - aMatchStyle, - aCmapCount, - aMatchedFamily); - } - HRESULT hr; RefPtr dwFactory = diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h index 553d67f49..4cde9050a 100644 --- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -388,6 +388,14 @@ protected: virtual gfxFontFamily* GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + // attempt to use platform-specific fallback for the given character, + // return null if no usable result found + gfxFontEntry* + PlatformGlobalFontFallback(const uint32_t aCh, + Script aRunScript, + const gfxFontStyle* aMatchStyle, + gfxFontFamily** aMatchedFamily) override; + private: friend class gfxDWriteFontFamily; @@ -395,13 +403,6 @@ private: void GetDirectWriteSubstitutes(); - // search fonts system-wide for a given character, null otherwise - virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh, - Script aRunScript, - const gfxFontStyle* aMatchStyle, - uint32_t& aCmapCount, - gfxFontFamily** aMatchedFamily); - virtual bool UsesSystemFallback() { return true; } void GetFontsFromCollection(IDWriteFontCollection* aCollection); diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index 03f850f39..781debbfe 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -149,12 +149,13 @@ private: const void *object, CFDictionaryRef userInfo); - // search fonts system-wide for a given character, null otherwise - gfxFontEntry* GlobalFontFallback(const uint32_t aCh, - Script aRunScript, - const gfxFontStyle* aMatchStyle, - uint32_t& aCmapCount, - gfxFontFamily** aMatchedFamily) override; + // attempt to use platform-specific fallback for the given character + // return null if no usable result found + gfxFontEntry* + PlatformGlobalFontFallback(const uint32_t aCh, + Script aRunScript, + const gfxFontStyle* aMatchStyle, + gfxFontFamily** aMatchedFamily) override; bool UsesSystemFallback() override { return true; } diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index a7fb4849b..f0cf98ad2 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -1040,23 +1040,11 @@ gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificatio } gfxFontEntry* -gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh, - Script aRunScript, - const gfxFontStyle* aMatchStyle, - uint32_t& aCmapCount, - gfxFontFamily** aMatchedFamily) +gfxMacPlatformFontList::PlatformGlobalFontFallback(const uint32_t aCh, + Script aRunScript, + const gfxFontStyle* aMatchStyle, + gfxFontFamily** aMatchedFamily) { - bool useCmaps = IsFontFamilyWhitelistActive() || - gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); - - if (useCmaps) { - return gfxPlatformFontList::GlobalFontFallback(aCh, - aRunScript, - aMatchStyle, - aCmapCount, - aMatchedFamily); - } - CFStringRef str; UniChar ch[2]; CFIndex length = 1; diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index 3fad73253..01394db14 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -645,6 +645,18 @@ gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh, uint32_t& aCmapCount, gfxFontFamily** aMatchedFamily) { + bool useCmaps = IsFontFamilyWhitelistActive() || + gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); + if (!useCmaps) { + // Allow platform-specific fallback code to try and find a usable font + gfxFontEntry* fe = + PlatformGlobalFontFallback(aCh, aRunScript, aMatchStyle, + aMatchedFamily); + if (fe) { + return fe; + } + } + // otherwise, try to find it among local fonts GlobalFontMatch data(aCh, aRunScript, aMatchStyle); diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index c23d97df5..c16994d8c 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -297,12 +297,24 @@ protected: const gfxFontStyle* aMatchStyle, gfxFontFamily** aMatchedFamily); - // search fonts system-wide for a given character, null otherwise - virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh, - Script aRunScript, - const gfxFontStyle* aMatchStyle, - uint32_t& aCmapCount, - gfxFontFamily** aMatchedFamily); + // Search fonts system-wide for a given character, null if not found. + gfxFontEntry* GlobalFontFallback(const uint32_t aCh, + Script aRunScript, + const gfxFontStyle* aMatchStyle, + uint32_t& aCmapCount, + gfxFontFamily** aMatchedFamily); + + // Platform-specific implementation of global font fallback, if any; + // this may return nullptr in which case the default cmap-based fallback + // will be performed. + virtual gfxFontEntry* + PlatformGlobalFontFallback(const uint32_t aCh, + Script aRunScript, + const gfxFontStyle* aMatchStyle, + gfxFontFamily** aMatchedFamily) + { + return nullptr; + } // whether system-based font fallback is used or not // if system fallback is used, no need to load all cmaps diff --git a/js/public/CharacterEncoding.h b/js/public/CharacterEncoding.h index fe39a415c..72bc27a98 100644 --- a/js/public/CharacterEncoding.h +++ b/js/public/CharacterEncoding.h @@ -236,7 +236,7 @@ template extern UTF8CharsZ CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx, const mozilla::Range chars); -uint32_t +JS_PUBLIC_API(uint32_t) Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length); /* @@ -245,13 +245,13 @@ Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length); * - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold * its length; the length value excludes the trailing null. */ -extern TwoByteCharsZ +extern JS_PUBLIC_API(TwoByteCharsZ) UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* * Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ. */ -extern TwoByteCharsZ +extern JS_PUBLIC_API(TwoByteCharsZ) UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); /* @@ -259,10 +259,10 @@ UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* * will be replaced by \uFFFD. No exception will be thrown for malformed UTF-8 * input. */ -extern TwoByteCharsZ +extern JS_PUBLIC_API(TwoByteCharsZ) LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); -extern TwoByteCharsZ +extern JS_PUBLIC_API(TwoByteCharsZ) LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); /* @@ -312,7 +312,7 @@ FindSmallestEncoding(UTF8Chars utf8); * report an error if the string contains non-Latin-1 codepoints. Returns * Latin1CharsZ() on failure. */ -extern Latin1CharsZ +extern JS_PUBLIC_API(Latin1CharsZ) UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* @@ -320,14 +320,14 @@ UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); * storing its length (excluding null terminator) in |*outlen|. Non-Latin-1 * codepoints are replaced by '?'. Returns Latin1CharsZ() on failure. */ -extern Latin1CharsZ +extern JS_PUBLIC_API(Latin1CharsZ) LossyUTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* * Returns true if all characters in the given null-terminated string are * ASCII, i.e. < 0x80, false otherwise. */ -extern bool +extern JS_PUBLIC_API(bool) StringIsASCII(const char* s); } // namespace JS diff --git a/js/public/Utility.h b/js/public/Utility.h index 6f3a9b1cc..249260610 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -77,7 +77,7 @@ enum ThreadType { # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) extern bool InitThreadType(void); extern void SetThreadType(ThreadType); -extern uint32_t GetThreadType(void); +extern JS_FRIEND_API(uint32_t) GetThreadType(void); # else inline bool InitThreadType(void) { return true; } inline void SetThreadType(ThreadType t) {}; diff --git a/js/src/jsalloc.h b/js/src/jsalloc.h index b9ae51901..dd27579d6 100644 --- a/js/src/jsalloc.h +++ b/js/src/jsalloc.h @@ -17,6 +17,8 @@ #include "js/TypeDecls.h" #include "js/Utility.h" +extern JS_PUBLIC_API(void) JS_ReportOutOfMemory(JSContext* cx); + namespace js { enum class AllocFunction { diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index f967269ad..3bc94aebd 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -550,10 +550,13 @@ JSCompartment::getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx, HandleOb return nullptr; } - // The key is the unwrapped dynamic scope, as we may be creating different - // WithEnvironmentObject wrappers each time. - MOZ_ASSERT(!enclosing->as().isSyntactic()); - RootedObject key(cx, &enclosing->as().object()); + // If a wrapped WithEnvironmentObject was passed in, unwrap it, as we may + // be creating different WithEnvironmentObject wrappers each time. + RootedObject key(cx, enclosing); + if (enclosing->is()) { + MOZ_ASSERT(!enclosing->as().isSyntactic()); + key = &enclosing->as().object(); + } RootedObject lexicalEnv(cx, nonSyntacticLexicalEnvironments_->lookup(key)); if (!lexicalEnv) { @@ -572,9 +575,13 @@ JSCompartment::getNonSyntacticLexicalEnvironment(JSObject* enclosing) const { if (!nonSyntacticLexicalEnvironments_) return nullptr; - if (!enclosing->is()) - return nullptr; - JSObject* key = &enclosing->as().object(); + // If a wrapped WithEnvironmentObject was passed in, unwrap it as in + // getOrCreateNonSyntacticLexicalEnvironment. + JSObject* key = enclosing; + if (enclosing->is()) { + MOZ_ASSERT(!enclosing->as().isSyntactic()); + key = &enclosing->as().object(); + } JSObject* lexicalEnv = nonSyntacticLexicalEnvironments_->lookup(key); if (!lexicalEnv) return nullptr; diff --git a/media/libstagefright/binding/Index.cpp b/media/libstagefright/binding/Index.cpp index 2d39f351b..eb039b5d6 100644 --- a/media/libstagefright/binding/Index.cpp +++ b/media/libstagefright/binding/Index.cpp @@ -82,6 +82,12 @@ SampleIterator::SampleIterator(Index* aIndex) , mCurrentMoof(0) , mCurrentSample(0) { + mIndex->RegisterIterator(this); +} + +SampleIterator::~SampleIterator() +{ + mIndex->UnregisterIterator(this); } already_AddRefed SampleIterator::GetNext() @@ -377,12 +383,37 @@ Index::~Index() {} void Index::UpdateMoofIndex(const MediaByteRangeSet& aByteRanges) +{ + UpdateMoofIndex(aByteRanges, false); +} + +void +Index::UpdateMoofIndex(const MediaByteRangeSet& aByteRanges, bool aCanEvict) { if (!mMoofParser) { return; } - - mMoofParser->RebuildFragmentedIndex(aByteRanges); + size_t moofs = mMoofParser->Moofs().Length(); + bool canEvict = aCanEvict && moofs > 1; + if (canEvict) { + // Check that we can trim the mMoofParser. We can only do so if all + // iterators have demuxed all possible samples. + for (const SampleIterator* iterator : mIterators) { + if ((iterator->mCurrentSample == 0 && iterator->mCurrentMoof == moofs) || + iterator->mCurrentMoof == moofs - 1) { + continue; + } + canEvict = false; + break; + } + } + mMoofParser->RebuildFragmentedIndex(aByteRanges, &canEvict); + if (canEvict) { + // The moofparser got trimmed. Adjust all registered iterators. + for (SampleIterator* iterator : mIterators) { + iterator->mCurrentMoof -= moofs - 1; + } + } } Microseconds @@ -550,4 +581,17 @@ Index::GetEvictionOffset(Microseconds aTime) } return offset; } + +void +Index::RegisterIterator(SampleIterator* aIterator) +{ + mIterators.AppendElement(aIterator); +} + +void +Index::UnregisterIterator(SampleIterator* aIterator) +{ + mIterators.RemoveElement(aIterator); +} + } diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index 11ab8c9a7..351cf7cb8 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -30,13 +30,28 @@ using namespace mozilla; const uint32_t kKeyIdSize = 16; bool -MoofParser::RebuildFragmentedIndex( - const MediaByteRangeSet& aByteRanges) +MoofParser::RebuildFragmentedIndex(const MediaByteRangeSet& aByteRanges) { BoxContext context(mSource, aByteRanges); return RebuildFragmentedIndex(context); } +bool +MoofParser::RebuildFragmentedIndex( + const MediaByteRangeSet& aByteRanges, bool* aCanEvict) +{ + MOZ_ASSERT(aCanEvict); + if (*aCanEvict && mMoofs.Length() > 1) { + MOZ_ASSERT(mMoofs.Length() == mMediaRanges.Length()); + mMoofs.RemoveElementsAt(0, mMoofs.Length() - 1); + mMediaRanges.RemoveElementsAt(0, mMediaRanges.Length() - 1); + *aCanEvict = true; + } else { + *aCanEvict = false; + } + return RebuildFragmentedIndex(aByteRanges); +} + bool MoofParser::RebuildFragmentedIndex(BoxContext& aContext) { diff --git a/media/libstagefright/binding/include/mp4_demuxer/Index.h b/media/libstagefright/binding/include/mp4_demuxer/Index.h index 768dedc5b..ca254f73d 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Index.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h @@ -26,10 +26,10 @@ class SampleIterator { public: explicit SampleIterator(Index* aIndex); + ~SampleIterator(); already_AddRefed GetNext(); void Seek(Microseconds aTime); Microseconds GetNextKeyframeTime(); - private: Sample* Get(); @@ -37,6 +37,7 @@ private: void Next(); RefPtr mIndex; + friend class Index; size_t mCurrentMoof; size_t mCurrentSample; }; @@ -97,6 +98,8 @@ public: uint32_t aTrackId, bool aIsAudio); + void UpdateMoofIndex(const mozilla::MediaByteRangeSet& aByteRanges, + bool aCanEvict); void UpdateMoofIndex(const mozilla::MediaByteRangeSet& aByteRanges); Microseconds GetEndCompositionIfBuffered( const mozilla::MediaByteRangeSet& aByteRanges); @@ -109,11 +112,14 @@ public: private: ~Index(); + void RegisterIterator(SampleIterator* aIterator); + void UnregisterIterator(SampleIterator* aIterator); Stream* mSource; FallibleTArray mIndex; FallibleTArray mDataOffset; nsAutoPtr mMoofParser; + nsTArray mIterators; // ConvertByteRangesToTimeRanges cache mozilla::MediaByteRangeSet mLastCachedRanges; diff --git a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h index 12cdc93f6..bb895555c 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h @@ -262,6 +262,11 @@ public: } bool RebuildFragmentedIndex( const mozilla::MediaByteRangeSet& aByteRanges); + // If *aCanEvict is set to true. then will remove all moofs already parsed + // from index then rebuild the index. *aCanEvict is set to true upon return if + // some moofs were removed. + bool RebuildFragmentedIndex( + const mozilla::MediaByteRangeSet& aByteRanges, bool* aCanEvict); bool RebuildFragmentedIndex(BoxContext& aContext); Interval GetCompositionRange( const mozilla::MediaByteRangeSet& aByteRanges); @@ -286,7 +291,6 @@ public: mozilla::MediaByteRange mInitRange; RefPtr mSource; uint64_t mOffset; - nsTArray mMoofOffsets; Mvhd mMvhd; Mdhd mMdhd; Trex mTrex; diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c index 7301d9298..e3afa2637 100644 --- a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c +++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c @@ -1190,6 +1190,9 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, temp = PL_strtok_r(NULL, ",", &strtok_state); iter++; } + } else { + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; } fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; @@ -1354,7 +1357,12 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, } } } - fmtp_ptr++; + if (*fmtp_ptr == '\n') { + // reached end of line, stop parsing + done = TRUE; + } else { + fmtp_ptr++; + } } else { done = TRUE; } diff --git a/netwerk/mime/nsMIMEHeaderParamImpl.cpp b/netwerk/mime/nsMIMEHeaderParamImpl.cpp index b799d2ed8..8d668f64f 100644 --- a/netwerk/mime/nsMIMEHeaderParamImpl.cpp +++ b/netwerk/mime/nsMIMEHeaderParamImpl.cpp @@ -824,8 +824,8 @@ nsMIMEHeaderParamImpl::DecodeRFC5987Param(const nsACString& aParamVal, nsAutoCString value; uint32_t delimiters = 0; - const char *encoded = PromiseFlatCString(aParamVal).get(); - const char *c = encoded; + const nsCString& encoded = PromiseFlatCString(aParamVal); + const char *c = encoded.get(); while (*c) { char tc = *c++; diff --git a/python/mozbuild/mozpack/manifests.py b/python/mozbuild/mozpack/manifests.py index 9ceeec47f..93bd6c2ca 100644 --- a/python/mozbuild/mozpack/manifests.py +++ b/python/mozbuild/mozpack/manifests.py @@ -410,3 +410,10 @@ class InstallManifestNoSymlinks(InstallManifest): source will be copied to dest. """ self.add_copy(source, dest) + + def add_pattern_symlink(self, base, pattern, dest): + """A wrapper that accepts symlink patterns and installs file copies. + + Files discovered with ``pattern`` will be copied to ``dest``. + """ + self.add_pattern_copy(base, pattern, dest) diff --git a/toolkit/components/places/Database.cpp b/toolkit/components/places/Database.cpp index 27a4048d7..673f564b5 100644 --- a/toolkit/components/places/Database.cpp +++ b/toolkit/components/places/Database.cpp @@ -5,6 +5,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" +#include "mozilla/ScopeExit.h" #include "Database.h" @@ -601,46 +602,55 @@ Database::BackupAndReplaceDatabaseFile(nsCOMPtr& aStorage) // If anything fails from this point on, we have a stale connection or // database file, and there's not much more we can do. // The only thing we can try to do is to replace the database on the next - // start, and enforce a crash, so it gets reported to us. + // startup, and report the problem through telemetry. + { + enum eCorruptDBReplaceStage : int8_t { + stage_closing = 0, + stage_removing, + stage_reopening, + stage_replaced + }; + eCorruptDBReplaceStage stage = stage_closing; + auto guard = MakeScopeExit([&]() { + if (stage != stage_replaced) { + // Reaching this point means the database is corrupt and we failed to + // replace it. For this session part of the application related to + // bookmarks and history will misbehave. The frontend may show a + // "locked" notification to the user though. + // Set up a pref to try replacing the database at the next startup. + Preferences::SetBool(PREF_FORCE_DATABASE_REPLACEMENT, true); + } + // Report the corruption through telemetry. + Telemetry::Accumulate(Telemetry::PLACES_DATABASE_CORRUPTION_HANDLING_STAGE, + static_cast(stage)); + }); - // Close database connection if open. - if (mMainConn) { - rv = mMainConn->Close(); - NS_ENSURE_SUCCESS(rv, ForceCrashAndReplaceDatabase( - NS_LITERAL_CSTRING("Unable to close the corrupt database."))); + // Close database connection if open. + if (mMainConn) { + rv = mMainConn->Close(); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Remove the broken database. + stage = stage_removing; + rv = databaseFile->Remove(false); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) { + return rv; + } + + // Create a new database file. + // Use an unshared connection, it will consume more memory but avoid shared + // cache contentions across threads. + stage = stage_reopening; + rv = aStorage->OpenUnsharedDatabase(databaseFile, getter_AddRefs(mMainConn)); + NS_ENSURE_SUCCESS(rv, rv); + + stage = stage_replaced; } - // Remove the broken database. - rv = databaseFile->Remove(false); - if (NS_FAILED(rv) && rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) { - return ForceCrashAndReplaceDatabase( - NS_LITERAL_CSTRING("Unable to remove the corrupt database file.")); - } - - // Create a new database file. - // Use an unshared connection, it will consume more memory but avoid shared - // cache contentions across threads. - rv = aStorage->OpenUnsharedDatabase(databaseFile, getter_AddRefs(mMainConn)); - NS_ENSURE_SUCCESS(rv, ForceCrashAndReplaceDatabase( - NS_LITERAL_CSTRING("Unable to open a new database connection."))); - return NS_OK; } -nsresult -Database::ForceCrashAndReplaceDatabase(const nsCString& aReason) -{ - Preferences::SetBool(PREF_FORCE_DATABASE_REPLACEMENT, true); - // Ensure that prefs get saved, or we could crash before storing them. - nsIPrefService* prefService = Preferences::GetService(); - if (prefService && NS_SUCCEEDED(prefService->SavePrefFile(nullptr))) { - // We could force an application restart here, but we'd like to get these - // cases reported to us, so let's force a crash instead. - MOZ_CRASH_UNSAFE_OOL(aReason.get()); - } - return NS_ERROR_FAILURE; -} - nsresult Database::InitSchema(bool* aDatabaseMigrated) { diff --git a/toolkit/components/places/Database.h b/toolkit/components/places/Database.h index 12cad2505..15fdcb7e4 100644 --- a/toolkit/components/places/Database.h +++ b/toolkit/components/places/Database.h @@ -224,12 +224,6 @@ protected: */ nsresult BackupAndReplaceDatabaseFile(nsCOMPtr& aStorage); - /** - * This should be used as a last resort in case the database is corrupt and - * there's no way to fix it in-place. - */ - nsresult ForceCrashAndReplaceDatabase(const nsCString& aReason); - /** * Initializes the database. This performs any necessary migrations for the * database. All migration is done inside a transaction that is rolled back diff --git a/toolkit/components/places/tests/unit/test_corrupt_telemetry.js b/toolkit/components/places/tests/unit/test_corrupt_telemetry.js new file mode 100644 index 000000000..cd9e9ec0c --- /dev/null +++ b/toolkit/components/places/tests/unit/test_corrupt_telemetry.js @@ -0,0 +1,31 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that history initialization correctly handles a request to forcibly +// replace the current database. + +add_task(function* () { + let profileDBPath = yield OS.Path.join(OS.Constants.Path.profileDir, "places.sqlite"); + yield OS.File.remove(profileDBPath, {ignoreAbsent: true}); + // Ensure that our database doesn't already exist. + Assert.ok(!(yield OS.File.exists(profileDBPath)), "places.sqlite shouldn't exist"); + let dir = yield OS.File.getCurrentDirectory(); + let src = OS.Path.join(dir, "corruptDB.sqlite"); + yield OS.File.copy(src, profileDBPath); + Assert.ok(yield OS.File.exists(profileDBPath), "places.sqlite should exist"); + + let count = Services.telemetry + .getHistogramById("PLACES_DATABASE_CORRUPTION_HANDLING_STAGE") + .snapshot() + .counts[3]; + Assert.equal(count, 0, "There should be no telemetry"); + + do_check_eq(PlacesUtils.history.databaseStatus, + PlacesUtils.history.DATABASE_STATUS_CORRUPT); + + count = Services.telemetry + .getHistogramById("PLACES_DATABASE_CORRUPTION_HANDLING_STAGE") + .snapshot() + .counts[3]; + Assert.equal(count, 1, "Telemetry should have been added"); +}); diff --git a/toolkit/components/places/tests/unit/xpcshell.ini b/toolkit/components/places/tests/unit/xpcshell.ini index c56c48af3..b4823f005 100644 --- a/toolkit/components/places/tests/unit/xpcshell.ini +++ b/toolkit/components/places/tests/unit/xpcshell.ini @@ -8,6 +8,7 @@ support-files = bookmarks.preplaces.html bookmarks_html_singleframe.html bug476292.sqlite + corruptDB.sqlite default.sqlite livemark.xml mobile_bookmarks_folder_import.json @@ -88,6 +89,7 @@ skip-if = (os == "win" && os_version == "5.1") # Bug 1158887 [test_browserhistory.js] [test_bug636917_isLivemark.js] [test_childlessTags.js] +[test_corrupt_telemetry.js] [test_crash_476292.js] [test_database_replaceOnStartup.js] [test_download_history.js] diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index b1b8f4b58..8807f001f 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -4345,6 +4345,15 @@ "kind": "boolean", "description": "Whether a document with a CSP policy (report-only or enforcing) contains a referrer directive ('true') or not ('false')." }, + "PLACES_DATABASE_CORRUPTION_HANDLING_STAGE": { + "alert_emails": ["firefox-dev@mozilla.org"], + "bug_numbers": [1356812], + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 6, + "releaseChannelCollection": "opt-out", + "description": "PLACES: stage reached when trying to fix a database corruption , see Places::Database::eCorruptDBReplaceStatus" + }, "PLACES_PAGES_COUNT": { "expires_in_version": "never", "kind": "exponential", diff --git a/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js b/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js index 2119ab9fb..ed5b5a7a1 100644 --- a/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js +++ b/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js @@ -528,7 +528,11 @@ add_task(function* test_subprocess_pathSearch() { add_task(function* test_subprocess_workdir() { let procDir = yield OS.File.getCurrentDirectory(); - let tmpDir = OS.Constants.Path.tmpDir; + let tmpDirFile = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + tmpDirFile.initWithPath(OS.Constants.Path.tmpDir); + tmpDirFile.normalize(); + let tmpDir = tmpDirFile.path; notEqual(procDir, tmpDir, "Current process directory must not be the current temp directory"); diff --git a/xpcom/io/CocoaFileUtils.h b/xpcom/io/CocoaFileUtils.h index 38137f520..7127cb65d 100644 --- a/xpcom/io/CocoaFileUtils.h +++ b/xpcom/io/CocoaFileUtils.h @@ -28,6 +28,7 @@ void AddQuarantineMetadataToFile(const CFStringRef filePath, const CFURLRef sourceURL, const CFURLRef referrerURL, const bool isFromWeb); +CFURLRef GetTemporaryFolderCFURLRef(); } // namespace CocoaFileUtils diff --git a/xpcom/io/CocoaFileUtils.mm b/xpcom/io/CocoaFileUtils.mm index 9ff8685d0..a02b82ac1 100644 --- a/xpcom/io/CocoaFileUtils.mm +++ b/xpcom/io/CocoaFileUtils.mm @@ -257,4 +257,11 @@ void AddQuarantineMetadataToFile(const CFStringRef filePath, ::CFRelease(mutQuarantineProps); } +CFURLRef GetTemporaryFolderCFURLRef() +{ + NSString* tempDir = ::NSTemporaryDirectory(); + return tempDir == nil ? NULL : (CFURLRef)[NSURL fileURLWithPath:tempDir + isDirectory:YES]; +} + } // namespace CocoaFileUtils diff --git a/xpcom/io/SpecialSystemDirectory.cpp b/xpcom/io/SpecialSystemDirectory.cpp index 873ad9556..eea021147 100644 --- a/xpcom/io/SpecialSystemDirectory.cpp +++ b/xpcom/io/SpecialSystemDirectory.cpp @@ -31,6 +31,9 @@ using mozilla::IsWin7OrLater; #include #include #include "prenv.h" +#if defined(MOZ_WIDGET_COCOA) +#include "CocoaFileUtils.h" +#endif #endif @@ -801,10 +804,20 @@ GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory, nsresult GetOSXFolderType(short aDomain, OSType aFolderType, nsIFile** aLocalFile) { - OSErr err; - FSRef fsRef; nsresult rv = NS_ERROR_FAILURE; + if (aFolderType == kTemporaryFolderType) { + NS_NewLocalFile(EmptyString(), true, aLocalFile); + nsCOMPtr localMacFile(do_QueryInterface(*aLocalFile)); + if (localMacFile) { + rv = localMacFile->InitWithCFURL( + CocoaFileUtils::GetTemporaryFolderCFURLRef()); + } + return rv; + } + + OSErr err; + FSRef fsRef; err = ::FSFindFolder(aDomain, aFolderType, kCreateFolder, &fsRef); if (err == noErr) { NS_NewLocalFile(EmptyString(), true, aLocalFile); diff --git a/xpcom/tests/unit/test_file_equality.js b/xpcom/tests/unit/test_file_equality.js index 4e98f7809..235792560 100644 --- a/xpcom/tests/unit/test_file_equality.js +++ b/xpcom/tests/unit/test_file_equality.js @@ -25,6 +25,10 @@ function test_normalized_vs_non_normalized() if (!exists) return; + // the test logic below assumes we're starting with a normalized path, but the + // default location on macos is a symbolic link, so resolve it before starting + tmp1.normalize(); + // this has the same exact path as tmp1, it should equal tmp1 var tmp2 = new LocalFile(tmp1.path); do_check_true(tmp1.equals(tmp2)); diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index 1b18966df..f52d85ad2 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -1711,7 +1711,8 @@ nsXULWindow::GetPrimaryTabParentSize(int32_t* aWidth, int32_t* aHeight) { TabParent* tabParent = TabParent::GetFrom(mPrimaryTabParent); - Element* element = tabParent->GetOwnerElement(); + // Need strong ref, since Client* can run script. + nsCOMPtr element = tabParent->GetOwnerElement(); NS_ENSURE_STATE(element); *aWidth = element->ClientWidth();