diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index 0418ad0ae..a81ae1d23 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -2149,6 +2149,8 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner) if (MoveChild(child, aOwner, insertIdx)) { child->SetRelocated(true); + MOZ_ASSERT(owned == mARIAOwnsHash.Get(aOwner)); + owned = mARIAOwnsHash.LookupOrAdd(aOwner); owned->InsertElementAt(idx, child); idx++; } diff --git a/accessible/xul/XULTreeAccessible.cpp b/accessible/xul/XULTreeAccessible.cpp index b8f7e8408..88153dc2d 100644 --- a/accessible/xul/XULTreeAccessible.cpp +++ b/accessible/xul/XULTreeAccessible.cpp @@ -144,7 +144,7 @@ XULTreeAccessible::Value(nsString& aValue) void XULTreeAccessible::Shutdown() { - if (!mDoc->IsDefunct()) { + if (mDoc && !mDoc->IsDefunct()) { UnbindCacheEntriesFromDocument(mAccessibleCache); } diff --git a/accessible/xul/XULTreeGridAccessible.cpp b/accessible/xul/XULTreeGridAccessible.cpp index fd7c6b0b9..e9e3a0e8f 100644 --- a/accessible/xul/XULTreeGridAccessible.cpp +++ b/accessible/xul/XULTreeGridAccessible.cpp @@ -277,7 +277,7 @@ NS_IMPL_RELEASE_INHERITED(XULTreeGridRowAccessible, void XULTreeGridRowAccessible::Shutdown() { - if (!mDoc->IsDefunct()) { + if (mDoc && !mDoc->IsDefunct()) { UnbindCacheEntriesFromDocument(mAccessibleCache); } diff --git a/build/autoconf/nspr-build.m4 b/build/autoconf/nspr-build.m4 index bb4e630d2..dfaceb96c 100644 --- a/build/autoconf/nspr-build.m4 +++ b/build/autoconf/nspr-build.m4 @@ -179,11 +179,8 @@ AC_SUBST_LIST(NSPR_CFLAGS) AC_SUBST(NSPR_INCLUDE_DIR) AC_SUBST(NSPR_LIB_DIR) -NSPR_PKGCONF_CHECK="nspr" +PKGCONF_REQUIRES_PRIVATE="Requires.private: nspr" if test -n "$MOZ_SYSTEM_NSPR"; then - # piggy back on $MOZ_SYSTEM_NSPR to set a variable for the nspr check for js.pc - NSPR_PKGCONF_CHECK="nspr >= $NSPR_MINVER" - _SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $NSPR_CFLAGS" AC_TRY_COMPILE([#include "prlog.h"], @@ -193,8 +190,12 @@ if test -n "$MOZ_SYSTEM_NSPR"; then , AC_MSG_ERROR([system NSPR does not support PR_STATIC_ASSERT])) CFLAGS=$_SAVE_CFLAGS + # piggy back on $MOZ_SYSTEM_NSPR to set a variable for the nspr check for js.pc + PKGCONF_REQUIRES_PRIVATE="Requires.private: nspr >= $NSPR_MINVER" +elif test -n "$JS_POSIX_NSPR"; then + PKGCONF_REQUIRES_PRIVATE= fi -AC_SUBST(NSPR_PKGCONF_CHECK) +AC_SUBST([PKGCONF_REQUIRES_PRIVATE]) fi # _IS_OUTER_CONFIGURE diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure index bfcc5377e..e64cd76d9 100644 --- a/build/moz.configure/init.configure +++ b/build/moz.configure/init.configure @@ -89,15 +89,28 @@ option(env='OLD_CONFIGURE', nargs=1, help='Path to the old configure script') option(env='MOZ_CURRENT_PROJECT', nargs=1, help='Current build project') option(env='MOZCONFIG', nargs=1, help='Mozconfig location') +option('--with-external-source-dir', env='EXTERNAL_SOURCE_DIR', nargs=1, + help='External directory containing additional build files') + +@depends('--with-external-source-dir') +def external_source_dir(value): + if value: + return value[0] + +set_config('EXTERNAL_SOURCE_DIR', external_source_dir) +add_old_configure_assignment('EXTERNAL_SOURCE_DIR', external_source_dir) + # Read user mozconfig # ============================================================== # Note: the dependency on --help is only there to always read the mozconfig, # even when --help is passed. Without this dependency, the function wouldn't # be called when --help is passed, and the mozconfig wouldn't be read. @depends('MOZ_CURRENT_PROJECT', 'MOZCONFIG', 'OLD_CONFIGURE', - check_build_environment, '--help') + check_build_environment, '--with-external-source-dir', + '--help') @imports(_from='mozbuild.mozconfig', _import='MozconfigLoader') -def mozconfig(current_project, mozconfig, old_configure, build_env, help): +def mozconfig(current_project, mozconfig, old_configure, build_env, + external_source_dir, help): if not old_configure: die('The OLD_CONFIGURE environment variable must be set') @@ -120,7 +133,10 @@ def mozconfig(current_project, mozconfig, old_configure, build_env, help): if os.path.dirname(os.path.abspath(old_configure[0])).endswith('/js/src'): return {'path': None} - loader = MozconfigLoader(build_env.topsrcdir) + topsrcdir = build_env.topsrcdir + if external_source_dir: + topsrcdir = external_source_dir[0] + loader = MozconfigLoader(topsrcdir) current_project = current_project[0] if current_project else None mozconfig = mozconfig[0] if mozconfig else None mozconfig = loader.find_mozconfig(env={'MOZCONFIG': mozconfig}) @@ -610,9 +626,6 @@ def default_project(build_env, help): option('--enable-project', nargs=1, default=default_project, help='Project to build') -option('--with-external-source-dir', env='EXTERNAL_SOURCE_DIR', nargs=1, - help='External directory containing additional build files') - @depends('--enable-project', '--with-external-source-dir', check_build_environment, '--help') @imports(_from='os.path', _import='exists') @@ -640,14 +653,6 @@ def include_project_configure(project, external_source_dir, build_env, help): else: die('Cannot find project %s', build_app) -@depends('--with-external-source-dir') -def external_source_dir(value): - if value: - return value[0] - -set_config('EXTERNAL_SOURCE_DIR', external_source_dir) -add_old_configure_assignment('EXTERNAL_SOURCE_DIR', external_source_dir) - @depends(include_project_configure, check_build_environment, '--help') def build_project(include_project_configure, build_env, help): diff --git a/dom/base/crashtests/1385272-1.html b/dom/base/crashtests/1385272-1.html new file mode 100644 index 000000000..5bdd40799 --- /dev/null +++ b/dom/base/crashtests/1385272-1.html @@ -0,0 +1,29 @@ + + + + + diff --git a/dom/base/crashtests/crashtests.list b/dom/base/crashtests/crashtests.list index 46d20112d..f151dc875 100644 --- a/dom/base/crashtests/crashtests.list +++ b/dom/base/crashtests/crashtests.list @@ -208,6 +208,7 @@ load xhr_html_nullresponse.html load 1230422.html load 1251361.html load 1304437.html +pref(clipboard.autocopy,true) load 1385272-1.html pref(dom.IntersectionObserver.enabled,true) load 1324209.html pref(dom.IntersectionObserver.enabled,true) load 1326194-1.html pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html diff --git a/dom/base/nsDocumentEncoder.cpp b/dom/base/nsDocumentEncoder.cpp index 626a9e1b6..677af1b50 100644 --- a/dom/base/nsDocumentEncoder.cpp +++ b/dom/base/nsDocumentEncoder.cpp @@ -1002,6 +1002,14 @@ nsDocumentEncoder::EncodeToString(nsAString& aOutputString) return EncodeToStringWithMaxLength(0, aOutputString); } +static bool ParentIsTR(nsIContent* aContent) { + mozilla::dom::Element* parent = aContent->GetParentElement(); + if (!parent) { + return false; + } + return parent->IsHTMLElement(nsGkAtoms::tr); +} + NS_IMETHODIMP nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength, nsAString& aOutputString) @@ -1069,7 +1077,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength, NS_ENSURE_SUCCESS(rv, rv); } nsCOMPtr content = do_QueryInterface(node); - if (content && content->IsHTMLElement(nsGkAtoms::tr)) { + if (content && content->IsHTMLElement(nsGkAtoms::tr) && !ParentIsTR(content)) { nsINode* n = content; if (!prevNode) { // Went from a non- to a diff --git a/dom/file/MutableBlobStorage.cpp b/dom/file/MutableBlobStorage.cpp index 4ba8a5102..43f43b52d 100644 --- a/dom/file/MutableBlobStorage.cpp +++ b/dom/file/MutableBlobStorage.cpp @@ -405,6 +405,14 @@ MutableBlobStorage::GetBlobWhenReady(nsISupports* aParent, return mDataLen; } + // If we are waiting for the temporary file, it's better to wait... + if (previousState == eWaitingForTemporaryFile) { + mPendingParent = aParent; + mPendingContentType = aContentType; + mPendingCallback = aCallback; + return mDataLen; + } + RefPtr blobImpl; if (mData) { @@ -544,16 +552,25 @@ MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD) MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mStorageState == eWaitingForTemporaryFile || mStorageState == eClosed); + MOZ_ASSERT_IF(mPendingCallback, mStorageState == eClosed); - if (mStorageState == eClosed) { + // If the object has been already closed and we don't need to execute a + // callback, we need just to close the file descriptor in the correct thread. + if (mStorageState == eClosed && !mPendingCallback) { RefPtr runnable = new CloseFileRunnable(aFD); DispatchToIOThread(runnable.forget()); return; } - mStorageState = eInTemporaryFile; + // If we still receiving data, we can proceed in temporary-file mode. + if (mStorageState == eWaitingForTemporaryFile) { + mStorageState = eInTemporaryFile; + } + mFD = aFD; + // This runnable takes the ownership of mData and it will write this buffer + // into the temporary file. RefPtr runnable = WriteRunnable::AdoptBuffer(this, mFD, mData, mDataLen); MOZ_ASSERT(runnable); @@ -561,6 +578,23 @@ MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD) mData = nullptr; DispatchToIOThread(runnable.forget()); + + // If we are closed, it means that GetBlobWhenReady() has been called when we + // were already waiting for a temporary file-descriptor. Finally we are here, + // AdoptBuffer runnable is going to write the current buffer into this file. + // After that, there is nothing else to write, and we dispatch LastRunnable + // which ends up calling mPendingCallback via CreateBlobRunnable. + if (mStorageState == eClosed) { + MOZ_ASSERT(mPendingCallback); + + RefPtr runnable = + new LastRunnable(this, mPendingParent, mPendingContentType, + mPendingCallback); + DispatchToIOThread(runnable.forget()); + + mPendingParent = nullptr; + mPendingCallback = nullptr; + } } void diff --git a/dom/file/MutableBlobStorage.h b/dom/file/MutableBlobStorage.h index 5af8a682c..fad391b16 100644 --- a/dom/file/MutableBlobStorage.h +++ b/dom/file/MutableBlobStorage.h @@ -95,6 +95,10 @@ private: nsresult mErrorResult; RefPtr mTaskQueue; + + nsCOMPtr mPendingParent; + nsCString mPendingContentType; + RefPtr mPendingCallback; }; } // namespace dom diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 31fab8af1..4d94c54b9 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -5802,8 +5802,7 @@ bool HTMLMediaElement::CanActivateAutoplay() bool hasData = (mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) || - (mSrcStream && mSrcStream->Active()) || - mMediaSource; + (mSrcStream && mSrcStream->Active()); return hasData; } diff --git a/dom/html/crashtests/1386905.html b/dom/html/crashtests/1386905.html new file mode 100644 index 000000000..6ecc59e23 --- /dev/null +++ b/dom/html/crashtests/1386905.html @@ -0,0 +1,13 @@ + + + + + + diff --git a/dom/html/crashtests/crashtests.list b/dom/html/crashtests/crashtests.list index 757276d59..11d0ea840 100644 --- a/dom/html/crashtests/crashtests.list +++ b/dom/html/crashtests/crashtests.list @@ -78,4 +78,5 @@ load 1237633.html load 1281972-1.html load 1282894.html load 1290904.html +load 1386905.html asserts(0-3) load 1350972.html diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index af34fdfc6..b7467c77a 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -1751,6 +1751,8 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame) } mBoundFrame = nullptr; + // Clear mRootNode so that we don't unexpectedly notify below. + nsCOMPtr rootNode = mRootNode.forget(); // Now that we don't have a frame any more, store the value in the text buffer. // The only case where we don't do this is if a value transfer is in progress. @@ -1760,15 +1762,15 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame) NS_ENSURE_TRUE_VOID(success); } - if (mRootNode && mMutationObserver) { - mRootNode->RemoveMutationObserver(mMutationObserver); + if (rootNode && mMutationObserver) { + rootNode->RemoveMutationObserver(mMutationObserver); mMutationObserver = nullptr; } // Unbind the anonymous content from the tree. // We actually hold a reference to the content nodes so that // they're not actually destroyed. - nsContentUtils::DestroyAnonymousContent(&mRootNode); + nsContentUtils::DestroyAnonymousContent(&rootNode); nsContentUtils::DestroyAnonymousContent(&mPlaceholderDiv); } diff --git a/dom/media/gmp/GMPProcessParent.cpp b/dom/media/gmp/GMPProcessParent.cpp index 0bf0d925f..d0bcd2fae 100644 --- a/dom/media/gmp/GMPProcessParent.cpp +++ b/dom/media/gmp/GMPProcessParent.cpp @@ -25,6 +25,10 @@ using mozilla::ipc::GoannaChildProcessHost; using base::ProcessArchitecture; namespace mozilla { + +extern LogModule* GetGMPLog(); +#define GMP_LOG(msg, ...) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Debug, (msg, ##__VA_ARGS__)) + namespace gmp { GMPProcessParent::GMPProcessParent(const std::string& aGMPPath) @@ -51,10 +55,13 @@ GMPProcessParent::Launch(int32_t aTimeoutMs) // symbolic links or junction points. Sometimes the Users folder has been // moved to another drive using a junction point, so allow for this specific // case. See bug 1236680 for details. - if (!widget::WinUtils::ResolveMovedUsersFolder(wGMPPath)) { - NS_WARNING("ResolveMovedUsersFolder failed for GMP path."); + if (!widget::WinUtils::ResolveJunctionPointsAndSymLinks(wGMPPath)) { + GMP_LOG("ResolveJunctionPointsAndSymLinks failed for GMP path=%S", + wGMPPath.c_str()); + NS_WARNING("ResolveJunctionPointsAndSymLinks failed for GMP path."); return false; } + GMP_LOG("GMPProcessParent::Launch() resolved path to %S", wGMPPath.c_str()); // If the GMP path is a network path that is not mapped to a drive letter, // then we need to fix the path format for the sandbox rule. diff --git a/dom/media/mediasource/MediaSourceDecoder.cpp b/dom/media/mediasource/MediaSourceDecoder.cpp index 9bc740ac5..774bed868 100644 --- a/dom/media/mediasource/MediaSourceDecoder.cpp +++ b/dom/media/mediasource/MediaSourceDecoder.cpp @@ -316,12 +316,12 @@ MediaSourceDecoder::CanPlayThrough() } else if (duration <= currentPosition) { return true; } - // If we have data up to the mediasource's duration or 30s ahead, we can + // If we have data up to the mediasource's duration or 10s ahead, we can // assume that we can play without interruption. TimeIntervals buffered = GetBuffered(); buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2); TimeUnit timeAhead = - std::min(duration, currentPosition + TimeUnit::FromSeconds(30)); + std::min(duration, currentPosition + TimeUnit::FromSeconds(10)); TimeInterval interval(currentPosition, timeAhead); return buffered.ContainsStrict(ClampIntervalToEnd(interval)); } diff --git a/dom/media/mediasource/test/mochitest.ini b/dom/media/mediasource/test/mochitest.ini index 4ed672c65..e3b3aa8ea 100644 --- a/dom/media/mediasource/test/mochitest.ini +++ b/dom/media/mediasource/test/mochitest.ini @@ -91,6 +91,8 @@ skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not [test_OnEvents.html] [test_PlayEvents.html] skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3 +[test_PlayEventsAutoPlaying.html] +skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3 [test_ResumeAfterClearing_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3 [test_SeekableAfterEndOfStream.html] diff --git a/dom/media/mediasource/test/test_PlayEventsAutoPlaying.html b/dom/media/mediasource/test/test_PlayEventsAutoPlaying.html new file mode 100644 index 000000000..492677b5c --- /dev/null +++ b/dom/media/mediasource/test/test_PlayEventsAutoPlaying.html @@ -0,0 +1,74 @@ + + + + MSE: basic functionality + + + + + +
+
+
+ + diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index 44b586945..507c7291c 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -8,6 +8,7 @@ #ifdef XP_WIN #include "WMFDecoderModule.h" + #endif #ifdef MOZ_FFVPX #include "FFVPXRuntimeLinker.h" @@ -372,7 +373,16 @@ PDMFactory::CreatePDMs() } #endif #ifdef XP_WIN - if (MediaPrefs::PDMWMFEnabled()) { + if (MediaPrefs::PDMWMFEnabled() && IsVistaOrLater() && !IsWin7AndPre2000Compatible()) { + // *Only* use WMF on Vista and later, as if Firefox is run in Windows 95 + // compatibility mode on Windows 7 (it does happen!) we may crash trying + // to startup WMF. So we need to detect the OS version here, as in + // compatibility mode IsVistaOrLater() and friends behave as if we're on + // the emulated version of Windows. See bug 1279171. + // Additionally, we don't want to start the RemoteDecoderModule if we + // expect it's not going to work (i.e. on Windows older than Vista). + // IsWin7AndPre2000Compatible() uses GetVersionEx as the user specified OS version can + // be reflected when compatibility mode is in effect. m = new WMFDecoderModule(); RefPtr remote = new dom::RemoteDecoderModule(m); StartupPDM(remote); diff --git a/dom/media/platforms/wmf/WMFUtils.cpp b/dom/media/platforms/wmf/WMFUtils.cpp index ff6bb4da5..3d9de7d02 100644 --- a/dom/media/platforms/wmf/WMFUtils.cpp +++ b/dom/media/platforms/wmf/WMFUtils.cpp @@ -12,6 +12,7 @@ #include "nsThreadUtils.h" #include "nsWindowsHelpers.h" #include "mozilla/CheckedInt.h" +#include "mozilla/WindowsVersion.h" #include "VideoUtils.h" #include #include "nsTArray.h" @@ -204,6 +205,16 @@ LoadDLLs() HRESULT MFStartup() { + if (!IsVistaOrLater() || IsWin7AndPre2000Compatible()) { + // *Only* use WMF on Vista and later, as if Firefox is run in Windows 95 + // compatibility mode on Windows 7 (it does happen!) we may crash trying + // to startup WMF. So we need to detect the OS version here, as in + // compatibility mode IsVistaOrLater() and friends behave as if we're on + // the emulated version of Windows. See bug 1279171. + // Using GetVersionEx API which takes compatibility mode into account. + return E_FAIL; + } + HRESULT hr = LoadDLLs(); if (FAILED(hr)) { return hr; diff --git a/dom/plugins/ipc/PluginUtilsWin.cpp b/dom/plugins/ipc/PluginUtilsWin.cpp index 688f82443..b6fad4a0d 100644 --- a/dom/plugins/ipc/PluginUtilsWin.cpp +++ b/dom/plugins/ipc/PluginUtilsWin.cpp @@ -1,22 +1,22 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -/* PluginUtilsWin.cpp - top-level Windows plugin management code */ - -#include -#include "PluginUtilsWin.h" -#include "PluginModuleParent.h" -#include "mozilla/StaticMutex.h" - -namespace mozilla { -namespace plugins { -namespace PluginUtilsWin { - +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +/* PluginUtilsWin.cpp - top-level Windows plugin management code */ + +#include +#include "PluginUtilsWin.h" +#include "PluginModuleParent.h" +#include "mozilla/StaticMutex.h" + +namespace mozilla { +namespace plugins { +namespace PluginUtilsWin { + typedef nsTHashtable> PluginModuleSet; -StaticMutex sMutex; - +StaticMutex sMutex; + class AudioDeviceChangedRunnable : public Runnable { public: @@ -28,10 +28,10 @@ public: NS_IMETHOD Run() override { - StaticMutexAutoLock lock(sMutex); + StaticMutexAutoLock lock(sMutex); PLUGIN_LOG_DEBUG(("Notifying %d plugins of audio device change.", mAudioNotificationSet->Count())); - + for (auto iter = mAudioNotificationSet->ConstIter(); !iter.Done(); iter.Next()) { PluginModuleParent* pluginModule = iter.Get()->GetKey(); pluginModule->SendNPP_SetValue_NPNVaudioDeviceChangeDetails(mChangeDetails); @@ -43,195 +43,195 @@ protected: NPAudioDeviceChangeDetailsIPC mChangeDetails; const PluginModuleSet* mAudioNotificationSet; }; - -class AudioNotification : public IMMNotificationClient -{ -public: - AudioNotification() : - mRefCt(1) - , mIsRegistered(false) - { - HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), - NULL, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&mDeviceEnum)); - if (FAILED(hr)) { - mDeviceEnum = nullptr; - return; - } - - hr = mDeviceEnum->RegisterEndpointNotificationCallback(this); - if (FAILED(hr)) { - mDeviceEnum->Release(); - mDeviceEnum = nullptr; - return; - } - - mIsRegistered = true; - } - - ~AudioNotification() - { - MOZ_ASSERT(!mIsRegistered, - "Destroying AudioNotification without first calling Unregister"); - if (mDeviceEnum) { - mDeviceEnum->Release(); - } - } - - // IMMNotificationClient Implementation - HRESULT STDMETHODCALLTYPE - OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR device_id) override - { - NPAudioDeviceChangeDetailsIPC changeDetails; - changeDetails.flow = (int32_t)flow; - changeDetails.role = (int32_t)role; - changeDetails.defaultDevice = std::wstring(device_id); - + +class AudioNotification : public IMMNotificationClient +{ +public: + AudioNotification() : + mRefCt(1) + , mIsRegistered(false) + { + HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), + NULL, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&mDeviceEnum)); + if (FAILED(hr)) { + mDeviceEnum = nullptr; + return; + } + + hr = mDeviceEnum->RegisterEndpointNotificationCallback(this); + if (FAILED(hr)) { + mDeviceEnum->Release(); + mDeviceEnum = nullptr; + return; + } + + mIsRegistered = true; + } + + ~AudioNotification() + { + MOZ_ASSERT(!mIsRegistered, + "Destroying AudioNotification without first calling Unregister"); + if (mDeviceEnum) { + mDeviceEnum->Release(); + } + } + + // IMMNotificationClient Implementation + HRESULT STDMETHODCALLTYPE + OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR device_id) override + { + NPAudioDeviceChangeDetailsIPC changeDetails; + changeDetails.flow = (int32_t)flow; + changeDetails.role = (int32_t)role; + changeDetails.defaultDevice = device_id ? std::wstring(device_id) : L""; + // Make sure that plugin is notified on the main thread. RefPtr runnable = new AudioDeviceChangedRunnable(&mAudioNotificationSet, changeDetails); NS_DispatchToMainThread(runnable); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - OnDeviceAdded(LPCWSTR device_id) override - { - return S_OK; - }; - - HRESULT STDMETHODCALLTYPE - OnDeviceRemoved(LPCWSTR device_id) override - { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - OnDeviceStateChanged(LPCWSTR device_id, DWORD new_state) override - { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - OnPropertyValueChanged(LPCWSTR device_id, const PROPERTYKEY key) override - { - return S_OK; - } - - // IUnknown Implementation - ULONG STDMETHODCALLTYPE - AddRef() override - { - return InterlockedIncrement(&mRefCt); - } - - ULONG STDMETHODCALLTYPE - Release() override - { - ULONG ulRef = InterlockedDecrement(&mRefCt); - if (0 == ulRef) { - delete this; - } - return ulRef; - } - - HRESULT STDMETHODCALLTYPE - QueryInterface(REFIID riid, VOID **ppvInterface) override - { - if (__uuidof(IUnknown) == riid) { - AddRef(); - *ppvInterface = (IUnknown*)this; - } else if (__uuidof(IMMNotificationClient) == riid) { - AddRef(); - *ppvInterface = (IMMNotificationClient*)this; - } else { - *ppvInterface = NULL; - return E_NOINTERFACE; - } - return S_OK; - } - - /* - * A Valid instance must be Unregistered before Releasing it. - */ - void Unregister() - { - if (mDeviceEnum) { - mDeviceEnum->UnregisterEndpointNotificationCallback(this); - } - mIsRegistered = false; - } - - /* - * True whenever the notification server is set to report events to this object. - */ - bool IsRegistered() { - return mIsRegistered; - } - - void AddModule(PluginModuleParent* aModule) { - StaticMutexAutoLock lock(sMutex); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE + OnDeviceAdded(LPCWSTR device_id) override + { + return S_OK; + }; + + HRESULT STDMETHODCALLTYPE + OnDeviceRemoved(LPCWSTR device_id) override + { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE + OnDeviceStateChanged(LPCWSTR device_id, DWORD new_state) override + { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE + OnPropertyValueChanged(LPCWSTR device_id, const PROPERTYKEY key) override + { + return S_OK; + } + + // IUnknown Implementation + ULONG STDMETHODCALLTYPE + AddRef() override + { + return InterlockedIncrement(&mRefCt); + } + + ULONG STDMETHODCALLTYPE + Release() override + { + ULONG ulRef = InterlockedDecrement(&mRefCt); + if (0 == ulRef) { + delete this; + } + return ulRef; + } + + HRESULT STDMETHODCALLTYPE + QueryInterface(REFIID riid, VOID **ppvInterface) override + { + if (__uuidof(IUnknown) == riid) { + AddRef(); + *ppvInterface = (IUnknown*)this; + } else if (__uuidof(IMMNotificationClient) == riid) { + AddRef(); + *ppvInterface = (IMMNotificationClient*)this; + } else { + *ppvInterface = NULL; + return E_NOINTERFACE; + } + return S_OK; + } + + /* + * A Valid instance must be Unregistered before Releasing it. + */ + void Unregister() + { + if (mDeviceEnum) { + mDeviceEnum->UnregisterEndpointNotificationCallback(this); + } + mIsRegistered = false; + } + + /* + * True whenever the notification server is set to report events to this object. + */ + bool IsRegistered() { + return mIsRegistered; + } + + void AddModule(PluginModuleParent* aModule) { + StaticMutexAutoLock lock(sMutex); mAudioNotificationSet.PutEntry(aModule); - } - - void RemoveModule(PluginModuleParent* aModule) { - StaticMutexAutoLock lock(sMutex); + } + + void RemoveModule(PluginModuleParent* aModule) { + StaticMutexAutoLock lock(sMutex); mAudioNotificationSet.RemoveEntry(aModule); - } - - /* - * Are any modules registered for audio notifications? - */ - bool HasModules() { - return !mAudioNotificationSet.IsEmpty(); - } - -private: - bool mIsRegistered; // only used to make sure that Unregister is called before destroying a Valid instance. - LONG mRefCt; - IMMDeviceEnumerator* mDeviceEnum; + } + + /* + * Are any modules registered for audio notifications? + */ + bool HasModules() { + return !mAudioNotificationSet.IsEmpty(); + } + +private: + bool mIsRegistered; // only used to make sure that Unregister is called before destroying a Valid instance. + LONG mRefCt; + IMMDeviceEnumerator* mDeviceEnum; // Set of plugin modules that have registered to be notified when the audio device // changes. PluginModuleSet mAudioNotificationSet; -}; // class AudioNotification - -// callback that gets notified of audio device events, or NULL -AudioNotification* sAudioNotification = nullptr; - -nsresult -RegisterForAudioDeviceChanges(PluginModuleParent* aModuleParent, bool aShouldRegister) -{ - // Hold the AudioNotification singleton iff there are PluginModuleParents - // that are subscribed to it. - if (aShouldRegister) { - if (!sAudioNotification) { - // We are registering the first module. Create the singleton. - sAudioNotification = new AudioNotification(); - if (!sAudioNotification->IsRegistered()) { +}; // class AudioNotification + +// callback that gets notified of audio device events, or NULL +AudioNotification* sAudioNotification = nullptr; + +nsresult +RegisterForAudioDeviceChanges(PluginModuleParent* aModuleParent, bool aShouldRegister) +{ + // Hold the AudioNotification singleton iff there are PluginModuleParents + // that are subscribed to it. + if (aShouldRegister) { + if (!sAudioNotification) { + // We are registering the first module. Create the singleton. + sAudioNotification = new AudioNotification(); + if (!sAudioNotification->IsRegistered()) { PLUGIN_LOG_DEBUG(("Registered for plugin audio device notification failed.")); - sAudioNotification->Release(); - sAudioNotification = nullptr; - return NS_ERROR_FAILURE; - } + sAudioNotification->Release(); + sAudioNotification = nullptr; + return NS_ERROR_FAILURE; + } PLUGIN_LOG_DEBUG(("Registered for plugin audio device notification.")); - } - sAudioNotification->AddModule(aModuleParent); - } - else if (!aShouldRegister && sAudioNotification) { - sAudioNotification->RemoveModule(aModuleParent); - if (!sAudioNotification->HasModules()) { - // We have removed the last module from the notification mechanism - // so we can destroy the singleton. + } + sAudioNotification->AddModule(aModuleParent); + } + else if (!aShouldRegister && sAudioNotification) { + sAudioNotification->RemoveModule(aModuleParent); + if (!sAudioNotification->HasModules()) { + // We have removed the last module from the notification mechanism + // so we can destroy the singleton. PLUGIN_LOG_DEBUG(("Unregistering for plugin audio device notification.")); - sAudioNotification->Unregister(); - sAudioNotification->Release(); - sAudioNotification = nullptr; - } - } - return NS_OK; -} - -} // namespace PluginUtilsWin -} // namespace plugins -} // namespace mozilla + sAudioNotification->Unregister(); + sAudioNotification->Release(); + sAudioNotification = nullptr; + } + } + return NS_OK; +} + +} // namespace PluginUtilsWin +} // namespace plugins +} // namespace mozilla diff --git a/dom/security/test/csp/file_sandbox_13.html b/dom/security/test/csp/file_sandbox_13.html new file mode 100644 index 000000000..e4672ed05 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_13.html @@ -0,0 +1,25 @@ + + + + + + + I am sandboxed but with only inline "allow-scripts" + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_allow_scripts.html b/dom/security/test/csp/file_sandbox_allow_scripts.html new file mode 100644 index 000000000..faab9f0fc --- /dev/null +++ b/dom/security/test/csp/file_sandbox_allow_scripts.html @@ -0,0 +1,12 @@ + + + + + Bug 1396320: Fix CSP sandbox regression for allow-scripts + + + + + diff --git a/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^ b/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^ new file mode 100644 index 000000000..4705ce9de --- /dev/null +++ b/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: sandbox allow-scripts; diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini index 163a19a17..3b310ccfc 100644 --- a/dom/security/test/csp/mochitest.ini +++ b/dom/security/test/csp/mochitest.ini @@ -185,6 +185,7 @@ support-files = file_sandbox_10.html file_sandbox_11.html file_sandbox_12.html + file_sandbox_13.html file_require_sri_meta.sjs file_require_sri_meta.js file_sendbeacon.html @@ -329,3 +330,7 @@ support-files = file_frame_src_child_governs.html file_frame_src.js file_frame_src_inner.html +[test_sandbox_allow_scripts.html] +support-files = + file_sandbox_allow_scripts.html + file_sandbox_allow_scripts.html^headers^ diff --git a/dom/security/test/csp/test_sandbox.html b/dom/security/test/csp/test_sandbox.html index 3a60be304..97d5275d2 100644 --- a/dom/security/test/csp/test_sandbox.html +++ b/dom/security/test/csp/test_sandbox.html @@ -111,7 +111,7 @@ var testCases = [ // * using sandbox flag 'allow-scripts' in CSP and not as iframe attribute // * not using allow-same-origin in CSP (so a new NullPrincipal is created). csp: "default-src 'none'; script-src 'unsafe-inline'; sandbox allow-scripts", - file: "file_sandbox_5.html", + file: "file_sandbox_13.html", results: { img13_bad: -1, img13a_bad: -1, script13_bad: -1, script13a_bad: -1 }, nrOKmessages: 2 // sends 2 ok message }, diff --git a/dom/security/test/csp/test_sandbox_allow_scripts.html b/dom/security/test/csp/test_sandbox_allow_scripts.html new file mode 100644 index 000000000..10acaae43 --- /dev/null +++ b/dom/security/test/csp/test_sandbox_allow_scripts.html @@ -0,0 +1,31 @@ + + + + Bug 1396320: Fix CSP sandbox regression for allow-scripts + + + + + + + + diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 4c14d5741..4080a3d33 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -275,6 +275,10 @@ HTMLEditor::Init(nsIDOMDocument* aDoc, nsCOMPtr document = do_QueryInterface(aDoc); document->AddMutationObserverUnlessExists(this); + if (!mRootElement) { + UpdateRootElement(); + } + // disable Composer-only features if (IsMailEditor()) { SetAbsolutePositioningEnabled(false); @@ -346,45 +350,27 @@ HTMLEditor::PreDestroy(bool aDestroyingFrames) return TextEditor::PreDestroy(aDestroyingFrames); } -NS_IMETHODIMP -HTMLEditor::GetRootElement(nsIDOMElement** aRootElement) +void +HTMLEditor::UpdateRootElement() { - NS_ENSURE_ARG_POINTER(aRootElement); - - if (mRootElement) { - return EditorBase::GetRootElement(aRootElement); - } - - *aRootElement = nullptr; - // Use the HTML documents body element as the editor root if we didn't // get a root element during initialization. nsCOMPtr rootElement; nsCOMPtr bodyElement; - nsresult rv = GetBodyElement(getter_AddRefs(bodyElement)); - NS_ENSURE_SUCCESS(rv, rv); - + GetBodyElement(getter_AddRefs(bodyElement)); if (bodyElement) { rootElement = bodyElement; } else { // If there is no HTML body element, // we should use the document root element instead. nsCOMPtr doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); - - rv = doc->GetDocumentElement(getter_AddRefs(rootElement)); - NS_ENSURE_SUCCESS(rv, rv); - // Document can have no elements - if (!rootElement) { - return NS_ERROR_NOT_AVAILABLE; + if (doc) { + doc->GetDocumentElement(getter_AddRefs(rootElement)); } } mRootElement = do_QueryInterface(rootElement); - rootElement.forget(aRootElement); - - return NS_OK; } already_AddRefed @@ -3234,8 +3220,9 @@ HTMLEditor::DoContentInserted(nsIDocument* aDocument, nsCOMPtr kungFuDeathGrip(this); if (ShouldReplaceRootElement()) { + UpdateRootElement(); nsContentUtils::AddScriptRunner(NewRunnableMethod( - this, &HTMLEditor::ResetRootElementAndEventTarget)); + this, &HTMLEditor::NotifyRootChanged)); } // We don't need to handle our own modifications else if (!mAction && (aContainer ? aContainer->IsEditable() : aDocument->IsEditable())) { @@ -3282,8 +3269,9 @@ HTMLEditor::ContentRemoved(nsIDocument* aDocument, nsCOMPtr kungFuDeathGrip(this); if (SameCOMIdentity(aChild, mRootElement)) { + mRootElement = nullptr; nsContentUtils::AddScriptRunner(NewRunnableMethod( - this, &HTMLEditor::ResetRootElementAndEventTarget)); + this, &HTMLEditor::NotifyRootChanged)); } // We don't need to handle our own modifications else if (!mAction && (aContainer ? aContainer->IsEditable() : aDocument->IsEditable())) { @@ -5044,24 +5032,18 @@ HTMLEditor::ShouldReplaceRootElement() } void -HTMLEditor::ResetRootElementAndEventTarget() +HTMLEditor::NotifyRootChanged() { nsCOMPtr kungFuDeathGrip(this); - // Need to remove the event listeners first because BeginningOfDocument - // could set a new root (and event target is set by InstallEventListeners()) - // and we won't be able to remove them from the old event target then. RemoveEventListeners(); - mRootElement = nullptr; nsresult rv = InstallEventListeners(); if (NS_FAILED(rv)) { return; } - // We must have mRootElement now. - nsCOMPtr root; - rv = GetRootElement(getter_AddRefs(root)); - if (NS_FAILED(rv) || !mRootElement) { + UpdateRootElement(); + if (!mRootElement) { return; } diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index b8b69678a..850ca2146 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -363,8 +363,6 @@ public: NS_IMETHOD SelectAll() override; - NS_IMETHOD GetRootElement(nsIDOMElement** aRootElement) override; - // nsICSSLoaderObserver NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasAlternate, nsresult aStatus) override; @@ -477,7 +475,7 @@ protected: virtual void RemoveEventListeners() override; bool ShouldReplaceRootElement(); - void ResetRootElementAndEventTarget(); + void NotifyRootChanged(); nsresult GetBodyElement(nsIDOMHTMLElement** aBody); /** @@ -940,6 +938,8 @@ protected: nsIContent* aContainer, nsIContent* aChild); + void UpdateRootElement(); + // resizing bool mIsObjectResizingEnabled; bool mIsResizing; diff --git a/extensions/auth/nsAuthFactory.cpp b/extensions/auth/nsAuthFactory.cpp index d026a900b..3d2008225 100644 --- a/extensions/auth/nsAuthFactory.cpp +++ b/extensions/auth/nsAuthFactory.cpp @@ -210,7 +210,7 @@ static const mozilla::Module::ContractIDEntry kAuthContracts[] = { { NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-sspi", &kNS_NEGOTIATEAUTHSSPI_CID }, { NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi", &kNS_KERBAUTHSSPI_CID }, { NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm", &kNS_SYSNTLMAUTH_CID }, -#else +#elif !defined(XP_MACOSX) { NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm", &kNS_SAMBANTLMAUTH_CID }, #endif { NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "negotiate", &kNS_HTTPNEGOTIATEAUTH_CID }, diff --git a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp index cf56299a1..cfde89ffc 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp +++ b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp @@ -681,10 +681,15 @@ void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph) glyph->fTop = -SkToS16(SkFDot6Floor(bbox.yMax)); glyph->fLeft = SkToS16(SkFDot6Floor(bbox.xMin)); - if (isLCD(fRec) && - gSetLcdFilter && - (fLcdFilter == FT_LCD_FILTER_DEFAULT || - fLcdFilter == FT_LCD_FILTER_LIGHT)) { + if (isLCD(fRec)) { + // In FreeType < 2.8.1, LCD filtering, if explicitly used, may + // add padding to the glyph. When not used, there is no padding. + // As of 2.8.1, LCD filtering is now always supported and may + // add padding even if an LCD filter is not explicitly set. + // Regardless, if no LCD filtering is used, or if LCD filtering + // doesn't add padding, it is safe to modify the glyph's bounds + // here. generateGlyphImage will detect if the mask is smaller + // than the bounds and clip things appropriately. if (fRec.fFlags & kLCD_Vertical_Flag) { glyph->fTop -= 1; glyph->fHeight += 2; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index f0cf98ad2..c8d7c1564 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -221,7 +221,11 @@ MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData) // Blacklist these so that font fallback will not use them. if (mRequiresAAT && (FamilyName().EqualsLiteral("Songti SC") || FamilyName().EqualsLiteral("Songti TC") || - FamilyName().EqualsLiteral("STSong"))) { + FamilyName().EqualsLiteral("STSong") || + // Bug 1390980: on 10.11, the Kaiti fonts are also affected. + FamilyName().EqualsLiteral("Kaiti SC") || + FamilyName().EqualsLiteral("Kaiti TC") || + FamilyName().EqualsLiteral("STKaiti"))) { charmap->ClearRange(0x0f6b, 0x0f70); charmap->ClearRange(0x0f8c, 0x0f8f); charmap->clear(0x0f98); diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index b04fc314d..dea730a6e 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -687,6 +687,14 @@ gfxPlatform::Init() gpu->LaunchGPUProcess(); } + if (XRE_IsParentProcess()) { + if (gfxPlatform::ForceSoftwareVsync()) { + gPlatform->mVsyncSource = (gPlatform)->gfxPlatform::CreateHardwareVsyncSource(); + } else { + gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource(); + } + } + #ifdef USE_SKIA SkGraphics::Init(); # ifdef MOZ_ENABLE_FREETYPE @@ -774,14 +782,6 @@ gfxPlatform::Init() RegisterStrongMemoryReporter(new GfxMemoryImageReporter()); - if (XRE_IsParentProcess()) { - if (gfxPlatform::ForceSoftwareVsync()) { - gPlatform->mVsyncSource = (gPlatform)->gfxPlatform::CreateHardwareVsyncSource(); - } else { - gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource(); - } - } - #ifdef USE_SKIA uint32_t skiaCacheSize = GetSkiaGlyphCacheSize(); if (skiaCacheSize != kDefaultGlyphCacheSize) { diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 6a978f8c3..07e54040a 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -18,6 +18,7 @@ #include "mozilla/Services.h" #include "mozilla/Sprintf.h" #include "mozilla/WindowsVersion.h" +#include "nsIGfxInfo.h" #include "nsServiceManagerUtils.h" #include "nsTArray.h" #include "mozilla/Telemetry.h" @@ -1441,6 +1442,21 @@ gfxWindowsPlatform::InitializeD3D11Config() d3d11.EnableByDefault(); + if (!IsWin8OrLater() && + !DeviceManagerDx::Get()->CheckRemotePresentSupport()) { + nsCOMPtr gfxInfo; + gfxInfo = services::GetGfxInfo(); + nsAutoString adaptorId; + gfxInfo->GetAdapterDeviceID(adaptorId); + // Blacklist Intel HD Graphics 510/520/530 on Windows 7 without platform + // update due to the crashes in Bug 1351349. + if (adaptorId.EqualsLiteral("0x1912") || adaptorId.EqualsLiteral("0x1916") || + adaptorId.EqualsLiteral("0x1902")) { + d3d11.Disable(FeatureStatus::Blacklisted, "Blacklisted, see bug 1351349", + NS_LITERAL_CSTRING("FEATURE_FAILURE_BUG_1351349")); + } + } + // If the user prefers D3D9, act as though they disabled D3D11. if (gfxPrefs::LayersPreferD3D9()) { d3d11.UserDisable("Disabled due to user preference for Direct3D 9", diff --git a/js/public/CallArgs.h b/js/public/CallArgs.h index d527b5603..a7774309a 100644 --- a/js/public/CallArgs.h +++ b/js/public/CallArgs.h @@ -300,7 +300,7 @@ class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase(lineOrPcOffset); diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index 9d4002c50..0e30bc3f2 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -211,7 +211,8 @@ namespace js }; } -class MOZ_NON_MEMMOVABLE JSStructuredCloneData : public mozilla::BufferList +class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) : + public mozilla::BufferList { typedef js::SystemAllocPolicy AllocPolicy; typedef mozilla::BufferList BufferList; diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index c8742f33f..7332f198f 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -193,7 +193,7 @@ using Vector = mozilla::Vector; // heap snapshots store their strings as const char16_t*. In order to provide // zero-cost accessors to these strings in a single interface that works with // both cases, we use this variant type. -class AtomOrTwoByteChars : public Variant { +class JS_PUBLIC_API(AtomOrTwoByteChars) : public Variant { using Base = Variant; public: @@ -466,8 +466,10 @@ class ConcreteStackFrame : public BaseStackFrame { bool isSelfHosted(JSContext* cx) const override { MOZ_CRASH("null JS::ubi::StackFrame"); } }; -MOZ_MUST_USE bool ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame, - MutableHandleObject outSavedFrameStack); +MOZ_MUST_USE JS_PUBLIC_API(bool) +ConstructSavedFrameStackSlow(JSContext* cx, + JS::ubi::StackFrame& frame, + MutableHandleObject outSavedFrameStack); /*** ubi::Node ************************************************************************************/ @@ -518,7 +520,7 @@ Uint32ToCoarseType(uint32_t n) // The base class implemented by each ubi::Node referent type. Subclasses must // not add data members to this class. -class Base { +class JS_PUBLIC_API(Base) { friend class Node; // For performance's sake, we'd prefer to avoid a virtual destructor; and @@ -969,7 +971,7 @@ class PreComputedEdgeRange : public EdgeRange { // // ... // } -class MOZ_STACK_CLASS RootList { +class MOZ_STACK_CLASS JS_PUBLIC_API(RootList) { Maybe& noGC; public: @@ -1001,7 +1003,7 @@ class MOZ_STACK_CLASS RootList { /*** Concrete classes for ubi::Node referent types ************************************************/ template<> -class Concrete : public Base { +class JS_PUBLIC_API(Concrete) : public Base { protected: explicit Concrete(RootList* ptr) : Base(ptr) { } RootList& get() const { return *static_cast(ptr); } @@ -1018,7 +1020,7 @@ class Concrete : public Base { // A reusable ubi::Concrete specialization base class for types supported by // JS::TraceChildren. template -class TracerConcrete : public Base { +class JS_PUBLIC_API(TracerConcrete) : public Base { js::UniquePtr edges(JSContext* cx, bool wantNames) const override; JS::Zone* zone() const override; @@ -1029,7 +1031,7 @@ class TracerConcrete : public Base { // For JS::TraceChildren-based types that have a 'compartment' method. template -class TracerConcreteWithCompartment : public TracerConcrete { +class JS_PUBLIC_API(TracerConcreteWithCompartment) : public TracerConcrete { typedef TracerConcrete TracerBase; JSCompartment* compartment() const override; @@ -1040,7 +1042,7 @@ class TracerConcreteWithCompartment : public TracerConcrete { // Define specializations for some commonly-used public JSAPI types. // These can use the generic templates above. template<> -class Concrete : TracerConcrete { +class JS_PUBLIC_API(Concrete) : TracerConcrete { protected: explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) { } @@ -1056,7 +1058,7 @@ class Concrete : TracerConcrete { }; template<> -class Concrete : TracerConcreteWithCompartment { +class JS_PUBLIC_API(Concrete) : TracerConcreteWithCompartment { protected: explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment(ptr) { } @@ -1073,7 +1075,7 @@ class Concrete : TracerConcreteWithCompartment { // The JSObject specialization. template<> -class Concrete : public TracerConcreteWithCompartment { +class JS_PUBLIC_API(Concrete) : public TracerConcreteWithCompartment { protected: explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { } @@ -1098,7 +1100,7 @@ class Concrete : public TracerConcreteWithCompartment { // For JSString, we extend the generic template with a 'size' implementation. template<> -class Concrete : TracerConcrete { +class JS_PUBLIC_API(Concrete) : TracerConcrete { protected: explicit Concrete(JSString *ptr) : TracerConcrete(ptr) { } @@ -1115,7 +1117,7 @@ class Concrete : TracerConcrete { // The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts. template<> -class Concrete : public Base { +class JS_PUBLIC_API(Concrete) : public Base { const char16_t* typeName() const override; Size size(mozilla::MallocSizeOf mallocSizeOf) const override; js::UniquePtr edges(JSContext* cx, bool wantNames) const override; diff --git a/js/public/UbiNodeCensus.h b/js/public/UbiNodeCensus.h index c0859ec56..8c7990886 100644 --- a/js/public/UbiNodeCensus.h +++ b/js/public/UbiNodeCensus.h @@ -83,7 +83,7 @@ struct Census; class CountBase; struct CountDeleter { - void operator()(CountBase*); + JS_PUBLIC_API(void) operator()(CountBase*); }; using CountBasePtr = js::UniquePtr; @@ -203,7 +203,7 @@ struct Census { explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } - MOZ_MUST_USE bool init(); + MOZ_MUST_USE JS_PUBLIC_API(bool) init(); }; // A BreadthFirst handler type that conducts a census, using a CountBase to @@ -227,22 +227,23 @@ class CensusHandler { // This class needs to retain no per-node data. class NodeData { }; - MOZ_MUST_USE bool operator() (BreadthFirst& traversal, - Node origin, const Edge& edge, - NodeData* referentData, bool first); + MOZ_MUST_USE JS_PUBLIC_API(bool) operator() (BreadthFirst& traversal, + Node origin, const Edge& edge, + NodeData* referentData, bool first); }; using CensusTraversal = BreadthFirst; // Examine the census options supplied by the API consumer, and (among other // things) use that to build a CountType tree. -MOZ_MUST_USE bool ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, - CountTypePtr& outResult); +MOZ_MUST_USE JS_PUBLIC_API(bool) ParseCensusOptions(JSContext* cx, + Census& census, HandleObject options, + CountTypePtr& outResult); // Parse the breakdown language (as described in // js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer // is returned on error and is reported to the cx. -CountTypePtr ParseBreakdown(JSContext* cx, HandleValue breakdownValue); +JS_PUBLIC_API(CountTypePtr) ParseBreakdown(JSContext* cx, HandleValue breakdownValue); } // namespace ubi diff --git a/js/public/Utility.h b/js/public/Utility.h index 249260610..8f7dc1254 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -178,7 +178,7 @@ static inline bool ShouldFailWithOOM() { return false; } namespace js { /* Disable OOM testing in sections which are not OOM safe. */ -struct MOZ_RAII AutoEnterOOMUnsafeRegion +struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion) { MOZ_NORETURN MOZ_COLD void crash(const char* reason); MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason); diff --git a/js/src/Makefile.in b/js/src/Makefile.in index fde813867..9df0ac3ba 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -166,13 +166,13 @@ endif # GNU_CC endif endif -SCRIPTS = $(JS_CONFIG_NAME) - $(LIBRARY_NAME).pc: js.pc cp $^ $@ +# Install versioned file, for parallel installability in Linux distributions install:: $(LIBRARY_NAME).pc - $(SYSINSTALL) $^ $(DESTDIR)$(libdir)/pkgconfig + cp $^ $(JS_LIBRARY_NAME).pc + $(SYSINSTALL) $(JS_LIBRARY_NAME).pc $(DESTDIR)$(libdir)/pkgconfig install:: js-config.h $(SYSINSTALL) $^ $(DESTDIR)$(includedir) @@ -208,9 +208,13 @@ install:: # END SpiderMonkey header installation ############################################# -install:: $(SCRIPTS) - $(SYSINSTALL) $^ $(DESTDIR)$(bindir) +# Install versioned script, for parallel installability in Linux distributions +install:: js-config + cp $^ js$(MOZJS_MAJOR_VERSION)-config + $(SYSINSTALL) js$(MOZJS_MAJOR_VERSION)-config $(DESTDIR)$(bindir) +# Use install_name_tool to set the install_name properly for standalone +# installed libraries on macOS install:: $(REAL_LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY) ifneq (,$(REAL_LIBRARY)) $(SYSINSTALL) $(REAL_LIBRARY) $(DESTDIR)$(libdir) @@ -218,9 +222,14 @@ ifneq (,$(REAL_LIBRARY)) endif ifneq (,$(SHARED_LIBRARY)) $(SYSINSTALL) $(SHARED_LIBRARY) $(DESTDIR)$(libdir) +ifeq ($(OS_ARCH),Darwin) + install_name_tool -id $(abspath $(libdir)/$(SHARED_LIBRARY)) $(DESTDIR)$(libdir)/$(SHARED_LIBRARY) +endif endif ifneq (,$(IMPORT_LIBRARY)) +ifneq ($(IMPORT_LIBRARY),$(SHARED_LIBRARY)) $(SYSINSTALL) $(IMPORT_LIBRARY) $(DESTDIR)$(libdir) +endif endif $(MAKE) -C shell install @@ -246,6 +255,7 @@ source-package: DIST=$(DIST) \ MKDIR=$(MKDIR) \ TAR=$(TAR) \ + AUTOCONF=$(AUTOCONF) \ MOZJS_MAJOR_VERSION=$(MOZJS_MAJOR_VERSION) \ MOZJS_MINOR_VERSION=$(MOZJS_MINOR_VERSION) \ MOZJS_PATCH_VERSION=$(MOZJS_PATCH_VERSION) \ diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp index fd8455eb8..fefebc8fe 100644 --- a/js/src/gc/Barrier.cpp +++ b/js/src/gc/Barrier.cpp @@ -180,12 +180,21 @@ MovableCellHasher::match(const Key& k, const Lookup& l) return zone->getUniqueIdInfallible(k) == zone->getUniqueIdInfallible(l); } -template struct MovableCellHasher; -template struct MovableCellHasher; -template struct MovableCellHasher; -template struct MovableCellHasher; -template struct MovableCellHasher; -template struct MovableCellHasher; +#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING + +template struct JS_PUBLIC_API(MovableCellHasher); +template struct JS_PUBLIC_API(MovableCellHasher); +template struct JS_PUBLIC_API(MovableCellHasher); +template struct JS_PUBLIC_API(MovableCellHasher); +template struct JS_PUBLIC_API(MovableCellHasher); +template struct JS_PUBLIC_API(MovableCellHasher); + +#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING +#pragma GCC diagnostic pop +#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING } // namespace js diff --git a/js/src/gc/MemoryProfiler.cpp b/js/src/gc/MemoryProfiler.cpp index 8825bb650..a061f9303 100644 --- a/js/src/gc/MemoryProfiler.cpp +++ b/js/src/gc/MemoryProfiler.cpp @@ -27,13 +27,13 @@ MemProfiler::GetGCHeapProfiler(JSRuntime* runtime) return runtime->gc.mMemProfiler.mGCHeapProfiler; } -MemProfiler* +JS_FRIEND_API(MemProfiler*) MemProfiler::GetMemProfiler(JSContext* context) { return &context->gc.mMemProfiler; } -void +JS_FRIEND_API(void) MemProfiler::start(GCHeapProfiler* aGCHeapProfiler) { ReleaseAllJITCode(mRuntime->defaultFreeOp()); @@ -41,7 +41,7 @@ MemProfiler::start(GCHeapProfiler* aGCHeapProfiler) sActiveProfilerCount++; } -void +JS_FRIEND_API(void) MemProfiler::stop() { sActiveProfilerCount--; diff --git a/js/src/jit/JitcodeMap.cpp b/js/src/jit/JitcodeMap.cpp index 3650da896..b20c615a8 100644 --- a/js/src/jit/JitcodeMap.cpp +++ b/js/src/jit/JitcodeMap.cpp @@ -1637,7 +1637,7 @@ JS::ForEachProfiledFrameOp::FrameHandle::FrameHandle(JSRuntime* rt, js::jit::Jit } } -JS::ProfilingFrameIterator::FrameKind +JS_PUBLIC_API(JS::ProfilingFrameIterator::FrameKind) JS::ForEachProfiledFrameOp::FrameHandle::frameKind() const { if (entry_.isBaseline()) diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index 013e39dda..910619a76 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -1294,7 +1294,7 @@ FrameHandle::updateHasTrackedOptimizations() canonicalAddr_ = (void*)(((uint8_t*) entry_.nativeStartAddr()) + entryOffset); } -void +JS_PUBLIC_API(void) FrameHandle::forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op, JSScript** scriptOut, jsbytecode** pcOut) const { @@ -1303,7 +1303,7 @@ FrameHandle::forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op, entry_.youngestFrameLocationAtAddr(rt_, addr_, scriptOut, pcOut); } -void +JS_PUBLIC_API(void) FrameHandle::forEachOptimizationTypeInfo(ForEachTrackedOptimizationTypeInfoOp& op) const { MOZ_ASSERT(optsIndex_.isSome()); diff --git a/js/src/js.pc.in b/js/src/js.pc.in index 1efea3342..2eae393a6 100644 --- a/js/src/js.pc.in +++ b/js/src/js.pc.in @@ -6,6 +6,6 @@ includedir=@includedir@ Name: SpiderMonkey @MOZILLA_VERSION@ Description: The Mozilla library for JavaScript Version: @MOZILLA_VERSION@ -Requires.private: @NSPR_PKGCONF_CHECK@ +@PKGCONF_REQUIRES_PRIVATE@ Libs: -L${libdir} -l@JS_LIBRARY_NAME@ Cflags: -include ${includedir}/@JS_LIBRARY_NAME@/js/RequiredDefines.h -I${includedir}/@JS_LIBRARY_NAME@ diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index fda46f9f1..e2be19a3c 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -121,7 +121,7 @@ using JS::ToUint32; #define JS_ADDRESSOF_VA_LIST(ap) (&(ap)) #endif -bool +JS_PUBLIC_API(bool) JS::CallArgs::requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const { if (length() < required) { @@ -3118,7 +3118,7 @@ JS_DefineConstIntegers(JSContext* cx, HandleObject obj, const JSConstIntegerSpec return DefineConstScalar(cx, obj, cis); } -bool +JS_PUBLIC_API(bool) JSPropertySpec::getValue(JSContext* cx, MutableHandleValue vp) const { MOZ_ASSERT(!isAccessor()); diff --git a/js/src/jsapi.h b/js/src/jsapi.h index e0d910148..154a80d05 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1962,7 +1962,7 @@ struct JSPropertySpec { bool isAccessor() const { return !(flags & JSPROP_INTERNAL_USE_BIT); } - bool getValue(JSContext* cx, JS::MutableHandleValue value) const; + JS_PUBLIC_API(bool) getValue(JSContext* cx, JS::MutableHandleValue value) const; bool isSelfHosted() const { MOZ_ASSERT(isAccessor()); @@ -6271,7 +6271,7 @@ struct MaxFrames * consider self-hosted frames with the given principals as satisfying the stack * capture. */ -struct FirstSubsumedFrame +struct JS_PUBLIC_API(FirstSubsumedFrame) { JSContext* cx; JSPrincipals* principals; @@ -6492,7 +6492,7 @@ class AutoStopwatch; * provide a concrete implementation of this class, as well as the * relevant callbacks (see below). */ -struct PerformanceGroup { +struct JS_PUBLIC_API(PerformanceGroup) { PerformanceGroup(); // The current iteration of the event loop. diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index a39ead3de..b29894162 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1284,7 +1284,7 @@ GetErrorMessage(void* userRef, const unsigned errorNumber); * JSString methods and often the code can be rewritten so that only indexes * instead of char pointers are used in parts of the code that can GC. */ -class MOZ_STACK_CLASS AutoStableStringChars +class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars) { /* * When copying string char, use this many bytes of inline storage. This is @@ -2910,7 +2910,7 @@ class GCHeapProfiler class MemProfiler { static mozilla::Atomic sActiveProfilerCount; - static NativeProfiler* sNativeProfiler; + static JS_FRIEND_DATA(NativeProfiler*) sNativeProfiler; static GCHeapProfiler* GetGCHeapProfiler(void* addr); static GCHeapProfiler* GetGCHeapProfiler(JSRuntime* runtime); @@ -2925,8 +2925,8 @@ class MemProfiler public: explicit MemProfiler(JSRuntime* aRuntime) : mGCHeapProfiler(nullptr), mRuntime(aRuntime) {} - void start(GCHeapProfiler* aGCHeapProfiler); - void stop(); + JS_FRIEND_API(void) start(GCHeapProfiler* aGCHeapProfiler); + JS_FRIEND_API(void) stop(); GCHeapProfiler* getGCHeapProfiler() const { return mGCHeapProfiler; @@ -2936,7 +2936,7 @@ class MemProfiler return sActiveProfilerCount > 0; } - static MemProfiler* GetMemProfiler(JSContext* context); + static JS_FRIEND_API(MemProfiler*) GetMemProfiler(JSContext* context); static void SetNativeProfiler(NativeProfiler* aProfiler) { sNativeProfiler = aProfiler; diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 2a96dc3ed..0ae8a4bde 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -93,6 +93,14 @@ #define JS_NO_FASTCALL #endif +// gcc is buggy and warns on our attempts to JS_PUBLIC_API our +// forward-declarations or explicit template instantiations. See +// . Add a way to detect +// that so we can locally disable that warning. +#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 6 || (__GNUC__ == 6 && __GNUC_MINOR__ <= 4)) +#define JS_BROKEN_GCC_ATTRIBUTE_WARNING +#endif + /*********************************************************************** ** MACROS: JS_BEGIN_MACRO ** JS_END_MACRO diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 218b6ed90..d6a977589 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -364,7 +364,7 @@ ReportAccessDenied(JSContext* cx); JS_FRIEND_API(bool) IsCrossCompartmentWrapper(JSObject* obj); -void +JS_FRIEND_API(void) NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper); void diff --git a/js/src/make-source-package.sh b/js/src/make-source-package.sh index 192144c62..f4131b98f 100644 --- a/js/src/make-source-package.sh +++ b/js/src/make-source-package.sh @@ -7,6 +7,7 @@ set -e : ${MKDIR:=mkdir} : ${TAR:=tar} +: ${AUTOCONF:=autoconf-2.13} : ${SRCDIR:=$(cd $(dirname $0); pwd 2>/dev/null)} : ${MOZJS_NAME:=mozjs} # The place to gather files to be added to the tarball. @@ -34,6 +35,7 @@ echo "Environment:" echo " MAKE = $MAKE" echo " MKDIR = $MKDIR" echo " TAR = $TAR" +echo " AUTOCONF = $AUTOCONF" echo " STAGING = $STAGING" echo " DIST = $DIST" echo " SRCDIR = $SRCDIR" @@ -97,6 +99,12 @@ case $cmd in ${MKDIR} -p ${tgtpath}/.cargo cp -pPR ${TOPSRCDIR}/.cargo/config.in ${tgtpath}/.cargo + # generate configure files to avoid build dependency on autoconf-2.13 + cp -PR ${TOPSRCDIR}/js/src/configure.in ${tgtpath}/js/src/configure + chmod a+x ${tgtpath}/js/src/configure + ${AUTOCONF} --localdir=${TOPSRCDIR}/js/src \ + ${TOPSRCDIR}/js/src/old-configure.in >${tgtpath}/js/src/old-configure + # put in js itself cp -pPR ${TOPSRCDIR}/mfbt ${tgtpath} cp -p ${SRCDIR}/../moz.configure ${tgtpath}/js diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 5ccd61eb6..b16c35a46 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -482,7 +482,7 @@ NukeRemovedCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper) MOZ_ASSERT(IsDeadProxyObject(wrapper)); } -void +JS_FRIEND_API(void) js::NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper) { JSCompartment* comp = wrapper->compartment(); diff --git a/js/src/shell/Makefile.in b/js/src/shell/Makefile.in index ebe7992c3..ebc58cfc7 100644 --- a/js/src/shell/Makefile.in +++ b/js/src/shell/Makefile.in @@ -10,5 +10,7 @@ endif include $(topsrcdir)/config/rules.mk +# Install versioned binary for parallel installability in Linux distributions install:: $(PROGRAM) - $(SYSINSTALL) $^ $(DESTDIR)$(bindir) + cp $^ $^$(MOZJS_MAJOR_VERSION) + $(SYSINSTALL) $^$(MOZJS_MAJOR_VERSION) $(DESTDIR)$(bindir) diff --git a/js/src/vm/SPSProfiler.cpp b/js/src/vm/SPSProfiler.cpp index 80c2aff03..8ba04fea9 100644 --- a/js/src/vm/SPSProfiler.cpp +++ b/js/src/vm/SPSProfiler.cpp @@ -483,7 +483,7 @@ SPSBaselineOSRMarker::~SPSBaselineOSRMarker() entry.unsetOSR(); } -JSScript* +JS_PUBLIC_API(JSScript*) ProfileEntry::script() const volatile { MOZ_ASSERT(isJs()); diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 1f0c541b2..1b78cb1be 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -1702,8 +1702,9 @@ struct MOZ_STACK_CLASS AtomizingMatcher } }; -bool ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame, - MutableHandleObject outSavedFrameStack) +JS_PUBLIC_API(bool) +ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame, + MutableHandleObject outSavedFrameStack) { SavedFrame::AutoLookupVector stackChain(cx); Rooted ubiFrame(cx, frame); diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index f2cf4646c..af75834ed 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -30,7 +30,16 @@ struct JSCompartment; namespace JS { namespace dbg { -class AutoEntryMonitor; +#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING + +class JS_PUBLIC_API(AutoEntryMonitor); + +#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING +#pragma GCC diagnostic pop +#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING } // namespace dbg } // namespace JS diff --git a/js/src/vm/UbiNodeCensus.cpp b/js/src/vm/UbiNodeCensus.cpp index 4836bfecf..e2c56c666 100644 --- a/js/src/vm/UbiNodeCensus.cpp +++ b/js/src/vm/UbiNodeCensus.cpp @@ -17,7 +17,7 @@ using namespace js; namespace JS { namespace ubi { -void +JS_PUBLIC_API(void) CountDeleter::operator()(CountBase* ptr) { if (!ptr) @@ -29,7 +29,7 @@ CountDeleter::operator()(CountBase* ptr) js_free(ptr); } -bool +JS_PUBLIC_API(bool) Census::init() { AutoLockForExclusiveAccess lock(cx); atomsZone = cx->runtime()->atomsCompartment(lock)->zone(); @@ -915,7 +915,7 @@ ByFilename::report(JSContext* cx, CountBase& countBase, MutableHandleValue repor /*** Census Handler *******************************************************************************/ -bool +JS_PUBLIC_API(bool) CensusHandler::operator() (BreadthFirst& traversal, Node origin, const Edge& edge, NodeData* referentData, bool first) @@ -958,7 +958,7 @@ ParseChildBreakdown(JSContext* cx, HandleObject breakdown, PropertyName* prop) return ParseBreakdown(cx, v); } -CountTypePtr +JS_PUBLIC_API(CountTypePtr) ParseBreakdown(JSContext* cx, HandleValue breakdownValue) { if (breakdownValue.isUndefined()) { @@ -1150,7 +1150,7 @@ GetDefaultBreakdown(JSContext* cx) other)); } -bool +JS_PUBLIC_API(bool) ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, CountTypePtr& outResult) { RootedValue breakdown(cx, UndefinedValue()); diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 08e73f5f4..17b5e0f8d 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -2067,10 +2067,10 @@ RecreateLostWaivers(JSContext* cx, const PropertyDescriptor* orig, orig->value.isObject() && WrapperFactory::HasWaiveXrayFlag(&orig->value.toObject()); bool getterWasWaived = - (orig->attrs & JSPROP_GETTER) && + (orig->attrs & JSPROP_GETTER) && orig->getter && WrapperFactory::HasWaiveXrayFlag(JS_FUNC_TO_DATA_PTR(JSObject*, orig->getter)); bool setterWasWaived = - (orig->attrs & JSPROP_SETTER) && + (orig->attrs & JSPROP_SETTER) && orig->setter && WrapperFactory::HasWaiveXrayFlag(JS_FUNC_TO_DATA_PTR(JSObject*, orig->setter)); // Recreate waivers. Note that for value, we need an extra UncheckedUnwrap diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.c index 0cef82166..80f1eb52d 100644 --- a/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.c +++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.c @@ -239,6 +239,15 @@ base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char * return BASE64_SUCCESS; } +unsigned char base64_decode_get_raw(unsigned char index) +{ + /* only have 128 values, MSB must not be set! */ + if (index >= 128) { + return INVALID_CHAR; + } + return base64_to_raw_table[index]; +} + /* * base64_decode * @@ -280,8 +289,8 @@ base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char * for (i=0; i=src_bytes) || - (base64_to_raw_table[src[i+1]] != PADDING)) { + (base64_decode_get_raw(src[i+1]) != PADDING)) { return BASE64_BUFFER_OVERRUN; } } @@ -363,7 +372,7 @@ base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char * */ if ((val & 0x03) || (i+1>=src_bytes) || - (base64_to_raw_table[src[i+1]] != PADDING)) { + (base64_decode_get_raw(src[i+1]) != PADDING)) { return BASE64_BUFFER_OVERRUN; } } diff --git a/mfbt/BufferList.h b/mfbt/BufferList.h index 42aea12db..26b335957 100644 --- a/mfbt/BufferList.h +++ b/mfbt/BufferList.h @@ -16,6 +16,9 @@ #include "mozilla/Vector.h" #include +// Undo potential #include damage to be able to use std::min. +#undef min + // BufferList represents a sequence of buffers of data. A BufferList can choose // to own its buffers or not. The class handles writing to the buffers, // iterating over them, and reading data out. Unlike SegmentedVector, the diff --git a/mfbt/WindowsVersion.h b/mfbt/WindowsVersion.h index 5fa30c5c1..4a73fb3ff 100644 --- a/mfbt/WindowsVersion.h +++ b/mfbt/WindowsVersion.h @@ -84,6 +84,44 @@ IsWindowsBuildOrLater(uint32_t aBuild) return false; } +inline bool +IsWindows10BuildOrLater(uint32_t aBuild) +{ + static uint32_t minBuild = 0; + static uint32_t maxBuild = UINT32_MAX; + + if (minBuild >= aBuild) { + return true; + } + + if (aBuild >= maxBuild) { + return false; + } + + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + info.dwMajorVersion = 10; + info.dwBuildNumber = aBuild; + + DWORDLONG conditionMask = 0; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + + if (VerifyVersionInfo(&info, VER_MAJORVERSION | VER_MINORVERSION | + VER_BUILDNUMBER | VER_SERVICEPACKMAJOR | + VER_SERVICEPACKMINOR, conditionMask)) { + minBuild = aBuild; + return true; + } + + maxBuild = aBuild; + return false; +} + #if 0//defined(_M_X64) || defined(_M_AMD64) // We support only Win7 or later on Win64. MOZ_ALWAYS_INLINE bool @@ -183,6 +221,12 @@ IsWin10OrLater() return IsWindowsVersionOrLater(0x0a000000ul); } +MOZ_ALWAYS_INLINE bool +IsWin10CreatorsUpdateOrLater() +{ + return IsWindows10BuildOrLater(15063); +} + MOZ_ALWAYS_INLINE bool IsNotWin7PreRTM() { @@ -190,6 +234,41 @@ IsNotWin7PreRTM() IsWindowsBuildOrLater(7600); } +MOZ_ALWAYS_INLINE bool +IsWin7AndPre2000Compatible() { + /* + * See Bug 1279171. + * We'd like to avoid using WMF on specific OS version when compatibility + * mode is in effect. The purpose of this function is to check if FF runs on + * Win7 OS with application compatibility mode being set to 95/98/ME. + * Those compatibility mode options (95/98/ME) can only display and + * be selected for 32-bit application. + * If the compatibility mode is in effect, the GetVersionEx function will + * report the OS as it identifies itself, which may not be the OS that is + * installed. + * Note : 1) We only target for Win7 build number greater than 7600. + * 2) GetVersionEx may be altered or unavailable for release after + * Win8.1. Set pragma to avoid build warning as error. + */ + bool isWin7 = IsNotWin7PreRTM() && !IsWin8OrLater(); + if (!isWin7) { + return false; + } + + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); +#pragma warning(push) +#pragma warning(disable:4996) + bool success = GetVersionEx((LPOSVERSIONINFO) &info); +#pragma warning(pop) + if (!success) { + return false; + } + return info.dwMajorVersion < 5; +} + } // namespace mozilla #endif /* mozilla_WindowsVersion_h */ diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index b6524a0d9..2bed0e59d 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -336,10 +336,10 @@ nsJAR::GetInputStreamWithSpec(const nsACString& aJarDirSpec, // Watch out for the jar:foo.zip!/ (aDir is empty) top-level special case! nsZipItem *item = nullptr; - const char *entry = PromiseFlatCString(aEntryName).get(); - if (*entry) { + const nsCString& entry = PromiseFlatCString(aEntryName); + if (*entry.get()) { // First check if item exists in jar - item = mZip->GetItem(entry); + item = mZip->GetItem(entry.get()); if (!item) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST; } nsJARInputStream* jis = new nsJARInputStream(); @@ -348,7 +348,7 @@ nsJAR::GetInputStreamWithSpec(const nsACString& aJarDirSpec, nsresult rv = NS_OK; if (!item || item->IsDirectory()) { - rv = jis->InitDirectory(this, aJarDirSpec, entry); + rv = jis->InitDirectory(this, aJarDirSpec, entry.get()); } else { rv = jis->InitFile(this, item); } diff --git a/security/sandbox/mac/Sandbox.mm b/security/sandbox/mac/Sandbox.mm index b90c5a553..59b8e1dbc 100644 --- a/security/sandbox/mac/Sandbox.mm +++ b/security/sandbox/mac/Sandbox.mm @@ -275,6 +275,14 @@ static const char contentSandboxRules[] = " (if (= macosMinorVersion 9)\n" " (allow mach-lookup (global-name \"com.apple.xpcd\")))\n" "\n" + " (if (>= macosMinorVersion 13)\n" + " (allow mach-lookup\n" + " ; bug 1376163\n" + " (global-name \"com.apple.audio.AudioComponentRegistrar\")\n" + " ; bug 1392988\n" + " (xpc-service-name \"com.apple.coremedia.videodecoder\")\n" + " (xpc-service-name \"com.apple.coremedia.videoencoder\")))\n" + "\n" " (allow iokit-open\n" " (iokit-user-client-class \"IOHIDParamUserClient\")\n" " (iokit-user-client-class \"IOAudioControlUserClient\")\n" diff --git a/toolkit/components/extensions/test/mochitest/test_ext_unload_frame.html b/toolkit/components/extensions/test/mochitest/test_ext_unload_frame.html index bc94b25d8..5572de281 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_unload_frame.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_unload_frame.html @@ -60,8 +60,19 @@ function connect_background() { }); } function connect_contentScript(testType) { + let isUnloading = false; + addEventListener("pagehide", () => { isUnloading = true; }, {once: true}); + let port = browser.runtime.connect({name: "port from frame"}); port.onMessage.addListener(msg => { + // The background page sends a reply as soon as we call runtime.connect(). + // It is possible that the reply reaches this frame before the + // window.close() request has been processed. + if (!isUnloading) { + browser.test.log(`Ignorting unexpected reply ("${msg}") because the page is not being unloaded.`); + return; + } + // The frame has been removed, so we should not get a reply. browser.test.fail(`Unexpected reply: ${msg}`); }); diff --git a/toolkit/locales/l10n.mk b/toolkit/locales/l10n.mk index 48d086fcd..ecc5de3bd 100644 --- a/toolkit/locales/l10n.mk +++ b/toolkit/locales/l10n.mk @@ -190,7 +190,7 @@ ifndef WGET endif $(NSINSTALL) -D $(ABS_DIST)/$(PKG_PATH) (cd $(ABS_DIST)/$(PKG_PATH) && \ - $(WGET) --no-cache -nv --no-iri -N -O $(PACKAGE) '$(EN_US_BINARY_URL)/$(EN_US_PACKAGE_NAME)') + $(WGET) --no-cache -nv --no-iri -N -O '$(notdir $(PACKAGE))' '$(EN_US_BINARY_URL)/$(EN_US_PACKAGE_NAME)') @echo 'Downloaded $(EN_US_BINARY_URL)/$(EN_US_PACKAGE_NAME) to $(ABS_DIST)/$(PKG_PATH)/$(PACKAGE)' ifdef RETRIEVE_WINDOWS_INSTALLER ifeq ($(OS_ARCH), WINNT) diff --git a/widget/cocoa/nsColorPicker.mm b/widget/cocoa/nsColorPicker.mm index 1fdaa03a2..263ea349b 100644 --- a/widget/cocoa/nsColorPicker.mm +++ b/widget/cocoa/nsColorPicker.mm @@ -54,11 +54,11 @@ HexStrToInt(NSString* str) - (void)open:(NSColor*)aInitialColor title:(NSString*)aTitle { - [mColorPanel setTitle:aTitle]; - [mColorPanel setColor:aInitialColor]; [mColorPanel setTarget:self]; [mColorPanel setAction:@selector(colorChanged:)]; [mColorPanel setDelegate:self]; + [mColorPanel setTitle:aTitle]; + [mColorPanel setColor:aInitialColor]; [mColorPanel makeKeyAndOrderFront:nil]; } @@ -80,11 +80,9 @@ HexStrToInt(NSString* str) - (void)dealloc { - if ([mColorPanel delegate] == self) { - [mColorPanel setTarget:nil]; - [mColorPanel setAction:nil]; - [mColorPanel setDelegate:nil]; - } + [mColorPanel setTarget:nil]; + [mColorPanel setAction:nil]; + [mColorPanel setDelegate:nil]; mColorPanel = nil; mColorPicker = nullptr; diff --git a/widget/gtk/nsClipboard.cpp b/widget/gtk/nsClipboard.cpp index 053ae970e..eecae3e88 100644 --- a/widget/gtk/nsClipboard.cpp +++ b/widget/gtk/nsClipboard.cpp @@ -214,7 +214,8 @@ nsClipboard::SetData(nsITransferable *aTransferable, GtkTargetEntry *gtkTargets = gtk_target_table_new_from_list(list, &numTargets); // Set getcallback and request to store data after an application exit - if (gtk_clipboard_set_with_data(gtkClipboard, gtkTargets, numTargets, + if (gtkTargets && + gtk_clipboard_set_with_data(gtkClipboard, gtkTargets, numTargets, clipboard_get_cb, clipboard_clear_cb, this)) { // We managed to set-up the clipboard so update internal state diff --git a/widget/windows/KeyboardLayout.cpp b/widget/windows/KeyboardLayout.cpp index 2f06d55d9..58e7bfe60 100644 --- a/widget/windows/KeyboardLayout.cpp +++ b/widget/windows/KeyboardLayout.cpp @@ -2517,7 +2517,8 @@ NativeKey::HandleCharMessage(const MSG& aCharMsg, *aEventDispatched = false; } - if (IsCharOrSysCharMessage(mMsg) && IsAnotherInstanceRemovingCharMessage()) { + if ((IsCharOrSysCharMessage(mMsg) || IsEnterKeyPressCharMessage(mMsg)) && + IsAnotherInstanceRemovingCharMessage()) { MOZ_LOG(sNativeKeyLogger, LogLevel::Warning, ("%p NativeKey::HandleCharMessage(), WARNING, does nothing because " "the message should be handled in another instance removing this " @@ -2546,7 +2547,9 @@ NativeKey::HandleCharMessage(const MSG& aCharMsg, // When a control key is inputted by a key, it should be handled without // WM_*CHAR messages at receiving WM_*KEYDOWN message. So, when we receive // WM_*CHAR message directly, we see a control character here. - if (IsControlCharMessage(aCharMsg)) { + // Note that when the char is '\r', it means that the char message should + // cause "Enter" keypress event for inserting a line break. + if (IsControlCharMessage(aCharMsg) && !IsEnterKeyPressCharMessage(aCharMsg)) { // In this case, we don't need to dispatch eKeyPress event because: // 1. We're the only browser which dispatches "keypress" event for // non-printable characters (Although, both Chrome and Edge dispatch @@ -2573,7 +2576,11 @@ NativeKey::HandleCharMessage(const MSG& aCharMsg, // First, handle normal text input or non-printable key case here. WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget); - keypressEvent.mCharCode = static_cast(aCharMsg.wParam); + if (IsEnterKeyPressCharMessage(aCharMsg)) { + keypressEvent.mKeyCode = NS_VK_RETURN; + } else { + keypressEvent.mCharCode = static_cast(aCharMsg.wParam); + } nsresult rv = mDispatcher->BeginNativeInputTransaction(); if (NS_WARN_IF(NS_FAILED(rv))) { MOZ_LOG(sNativeKeyLogger, LogLevel::Error, diff --git a/widget/windows/KeyboardLayout.h b/widget/windows/KeyboardLayout.h index 70aacc80e..ba0d2d2d0 100644 --- a/widget/windows/KeyboardLayout.h +++ b/widget/windows/KeyboardLayout.h @@ -531,6 +531,10 @@ private: return aMSG.message == WM_CHAR && !IsControlChar(static_cast(aMSG.wParam)); } + bool IsEnterKeyPressCharMessage(const MSG& aMSG) const + { + return aMSG.message == WM_CHAR && aMSG.wParam == '\r'; + } bool IsPrintableCharOrSysCharMessage(const MSG& aMSG) const { return IsCharOrSysCharMessage(aMSG) && diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index 2731e1eaf..3049aa32f 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -2122,6 +2122,18 @@ TSFTextStore::GetSelection(ULONG ulIndex, Selection& selectionForTSF = SelectionForTSFRef(); if (selectionForTSF.IsDirty()) { + if (DoNotReturnErrorFromGetSelection()) { + AutoSetTemporarySelection temprarySetter(selectionForTSF); + *pSelection = selectionForTSF.ACP(); + *pcFetched = 1; + MOZ_LOG(sTextStoreLog, LogLevel::Info, + ("0x%p TSFTextStore::GetSelection() returns fake selection range " + "for avoiding a crash in TSF, " + "acpStart=%d, acpEnd=%d (length=%d), reverted=%s", + this, selectionForTSF.StartOffset(), selectionForTSF.EndOffset(), + selectionForTSF.Length(), GetBoolName(selectionForTSF.IsReversed()))); + return S_OK; + } MOZ_LOG(sTextStoreLog, LogLevel::Error, ("0x%p TSFTextStore::GetSelection() FAILED due to " "SelectionForTSFRef() failure", this)); @@ -2130,10 +2142,26 @@ TSFTextStore::GetSelection(ULONG ulIndex, *pSelection = selectionForTSF.ACP(); *pcFetched = 1; MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("0x%p TSFTextStore::GetSelection() succeeded", this)); + ("0x%p TSFTextStore::GetSelection() succeeded, " + "acpStart=%d, acpEnd=%d (length=%d), reverted=%s", + this, selectionForTSF.StartOffset(), selectionForTSF.EndOffset(), + selectionForTSF.Length(), GetBoolName(selectionForTSF.IsReversed()))); return S_OK; } +// static +bool +TSFTextStore::DoNotReturnErrorFromGetSelection() +{ + // There is a crash bug of TSF if we return error from GetSelection(). + // That was introduced in Anniversary Update (build 14393, see bug 1312302) + // TODO: We should avoid to run this hack on fixed builds. When we get + // exact build number, we should get back here. + static bool sTSFMayCrashIfGetSelectionReturnsError = + IsWindows10BuildOrLater(14393); + return sTSFMayCrashIfGetSelectionReturnsError; +} + bool TSFTextStore::IsComposingInContent() const { @@ -4861,14 +4889,7 @@ TSFTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget, HRESULT hr; RefPtr threadMgr = sThreadMgr; - { - // Windows 10's softwware keyboard requires that SetSelection must be - // always successful into SetFocus. If returning error, it might crash - // into TextInputFramework.dll. - AutoSetTemporarySelection setSelection(textStore->SelectionForTSFRef()); - - hr = threadMgr->SetFocus(newDocMgr); - } + hr = threadMgr->SetFocus(newDocMgr); if (NS_WARN_IF(FAILED(hr))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, diff --git a/widget/windows/TSFTextStore.h b/widget/windows/TSFTextStore.h index 08896ef36..d41dff0e4 100644 --- a/widget/windows/TSFTextStore.h +++ b/widget/windows/TSFTextStore.h @@ -253,6 +253,11 @@ public: */ static bool IsMSJapaneseIMEActive(); + /** + * Returns true if TSF may crash if GetSelection() returns E_FAIL. + */ + static bool DoNotReturnErrorFromGetSelection(); + #ifdef DEBUG // Returns true when keyboard layout has IME (TIP). static bool CurrentKeyboardLayoutHasIME(); diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index f30a83248..d3592e810 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -1883,111 +1883,65 @@ WinUtils::GetMaxTouchPoints() return 0; } -#pragma pack(push, 1) -typedef struct REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - }; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; -#pragma pack(pop) +typedef DWORD (WINAPI * GetFinalPathNameByHandlePtr)(HANDLE hFile, + LPTSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); /* static */ bool -WinUtils::ResolveMovedUsersFolder(std::wstring& aPath) +WinUtils::ResolveJunctionPointsAndSymLinks(std::wstring& aPath) { - wchar_t* usersPath; - if (FAILED(WinUtils::SHGetKnownFolderPath(FOLDERID_UserProfiles, 0, nullptr, - &usersPath))) { - return false; - } - - // Ensure usersPath gets freed properly. - UniquePtr autoFreePath(usersPath); - - // Is aPath in Users folder? - size_t usersLen = wcslen(usersPath); - if (_wcsnicmp(aPath.c_str(), usersPath, usersLen) != 0 || - aPath[usersLen] != L'\\') { + // Users folder was introduced with Vista. + if (!IsVistaOrLater()) { return true; } - DWORD attributes = ::GetFileAttributesW(usersPath); - if (attributes == INVALID_FILE_ATTRIBUTES) { + wchar_t path[MAX_PATH] = { 0 }; + + nsAutoHandle handle( + ::CreateFileW(aPath.c_str(), + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + nullptr)); + + if (handle == INVALID_HANDLE_VALUE) { return false; } - // Junction points are implemented as reparse points, is the Users folder one? - if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT)) { - return true; + // GetFinalPathNameByHandleW is a Vista and later API. Since ESR builds with + // XP support still, we need to load the function manually. + GetFinalPathNameByHandlePtr getFinalPathNameFnPtr = nullptr; + HMODULE kernel32Dll = ::GetModuleHandleW(L"Kernel32"); + if (kernel32Dll) { + getFinalPathNameFnPtr = (GetFinalPathNameByHandlePtr) + ::GetProcAddress(kernel32Dll, "GetFinalPathNameByHandleW"); } // Get the reparse point data. - nsAutoHandle usersHandle( - ::CreateFileW(usersPath, 0, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - nullptr)); - - char maxReparseBuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE] = {0}; - REPARSE_DATA_BUFFER* reparseBuf = (REPARSE_DATA_BUFFER*)maxReparseBuf; - DWORD bytesReturned = 0; - if (!::DeviceIoControl(usersHandle, FSCTL_GET_REPARSE_POINT, nullptr, 0, - reparseBuf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, - &bytesReturned, nullptr)) { + if (!getFinalPathNameFnPtr) { return false; } - // Check to see if the reparse point is a junction point. - if (reparseBuf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) { - return true; - } - - // The offset and length are in bytes. Length doesn't include null. - wchar_t* substituteName = reparseBuf->MountPointReparseBuffer.PathBuffer + - reparseBuf->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); - std::wstring::size_type substituteLen = - reparseBuf->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t); - - // If the substitute path starts with the NT namespace then remove it. - if (wcsncmp(substituteName, kNTPrefix, kNTPrefixLen) == 0) { - substituteName += kNTPrefixLen; - substituteLen -= kNTPrefixLen; - } - - // Check that what remains looks like a drive letter path. - if (substituteName[1] != L':' || substituteName[2] != L'\\') { + DWORD pathLen = getFinalPathNameFnPtr( + handle, path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + if (pathLen == 0 || pathLen >= MAX_PATH) { return false; } + aPath = path; - // The documentation for SHGetKnownFolderPath says that it doesn't return a - // trailing backslash. The REPARSE_DATA_BUFFER path doesn't seem to have one - // either, but the documentation doesn't mention it, so let's make sure. - if (substituteName[substituteLen - 1] == L'\\') { - --substituteLen; + // GetFinalPathNameByHandle sticks a '\\?\' in front of the path, + // but that confuses some APIs so strip it off. It will also put + // '\\?\UNC\' in front of network paths, we convert that to '\\'. + if (aPath.compare(0, 7, L"\\\\?\\UNC") == 0) { + aPath.erase(2, 6); + } else if (aPath.compare(0, 4, L"\\\\?\\") == 0) { + aPath.erase(0, 4); } - aPath.replace(0, usersLen, substituteName, substituteLen); return true; } diff --git a/widget/windows/WinUtils.h b/widget/windows/WinUtils.h index b35c0c1c8..5dc298661 100644 --- a/widget/windows/WinUtils.h +++ b/widget/windows/WinUtils.h @@ -467,16 +467,16 @@ public: static uint32_t GetMaxTouchPoints(); /** - * Detect if path is within the Users folder and Users is actually a junction - * point to another folder. - * If this is detected it will change the path to the actual path. + * Fully resolves a path to its final path name. So if path contains + * junction points or symlinks to other folders, we'll resolve the path + * fully to the actual path that the links target. * * @param aPath path to be resolved. * @return true if successful, including if nothing needs to be changed. * false if something failed or aPath does not exist, aPath will * remain unchanged. */ - static bool ResolveMovedUsersFolder(std::wstring& aPath); + static bool ResolveJunctionPointsAndSymLinks(std::wstring& aPath); /** * dwmapi.dll function typedefs and declarations