From aaa97f23a2659b3c7e7398476b0f8d6f38a9c67b Mon Sep 17 00:00:00 2001 From: cku Date: Tue, 21 Feb 2017 17:44:22 +0800 Subject: [PATCH 01/42] Bug 1340992 - Demote MOZ_ASSERT to NS_ASSERTION before root cause addressed. r=me MozReview-Commit-ID: I8goOZdPs9d --- layout/svg/nsSVGIntegrationUtils.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index cef7e000f8d6b..f5f07b6f6642e 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -129,10 +129,10 @@ class PreEffectsVisualOverflowCollector : public nsLayoutUtils::BoxCallback bool mightHaveNoneSVGMask = nsSVGEffects::GetEffectProperties(firstFrame).MightHaveNoneSVGMask(); - MOZ_ASSERT(mightHaveNoneSVGMask || - aFrame->GetParent()->StyleContext()->GetPseudo() == - nsCSSAnonBoxes::mozAnonymousBlock, - "How did we getting here, then?"); + NS_ASSERTION(mightHaveNoneSVGMask || + aFrame->GetParent()->StyleContext()->GetPseudo() == + nsCSSAnonBoxes::mozAnonymousBlock, + "How did we getting here, then?"); } bool hasEffect = nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame); From b476f817ece87446a14f383e7e9b26629d6f701d Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 20 Feb 2017 20:18:23 +0100 Subject: [PATCH 02/42] Bug 1341080: Provide an empty filename if the wasm caller doesn't have one in DescribeScriptedCaller; r=luke MozReview-Commit-ID: 8h0NbN7jOBq --HG-- extra : rebase_source : b669683e4fb4a582f29198290f7d59c4eb1c3eb8 extra : amend_source : 2dbf1ea54750f972f556ccd04c99c68837b92c53 --- .../tests/wasm/regress/null-metadata-filename.js | 12 ++++++++++++ js/src/jsapi.cpp | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/js/src/jit-test/tests/wasm/regress/null-metadata-filename.js b/js/src/jit-test/tests/wasm/regress/null-metadata-filename.js index 831dc3adb282a..c164188b62526 100644 --- a/js/src/jit-test/tests/wasm/regress/null-metadata-filename.js +++ b/js/src/jit-test/tests/wasm/regress/null-metadata-filename.js @@ -7,3 +7,15 @@ var code = evaluate("(function() { 'use asm'; function g() { return 43 } return }); assertEq(code()(), 43); + +evaluate(` +let f = evalReturningScope.bind(null, ''); + +(function(glob, stdlib) { + "use asm"; + var f = stdlib.f; + function _() { f(); } + return _; +})(this, { f })(); +`, { fileName: null }); + diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 2cb201e95f469..f60b5feb7ca3a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6761,7 +6761,7 @@ DescribeScriptedCaller(JSContext* cx, AutoFilename* filename, unsigned* lineno, if (filename) { if (i.isWasm()) { // For Wasm, copy out the filename, there is no script source. - UniqueChars copy = DuplicateString(i.filename()); + UniqueChars copy = DuplicateString(i.filename() ? i.filename() : ""); if (!copy) filename->setUnowned("out of memory"); else From a4987976971622bb7cfc498237c45f874d86f36a Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Tue, 21 Feb 2017 11:27:19 +0100 Subject: [PATCH 03/42] Bug 1289723 - Fixing crashedTabs test for e10s-multi. r=mrbkap --- .../components/sessionstore/test/browser_crashedTabs.js | 7 +++---- toolkit/content/widgets/remote-browser.xml | 8 ++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/browser/components/sessionstore/test/browser_crashedTabs.js b/browser/components/sessionstore/test/browser_crashedTabs.js index b97bc91e761a2..193f9b16d535d 100644 --- a/browser/components/sessionstore/test/browser_crashedTabs.js +++ b/browser/components/sessionstore/test/browser_crashedTabs.js @@ -13,7 +13,6 @@ const PAGE_2 = "data:text/html,Another%20regular,%20everyday,%20norm add_task(function* test_initialize() { yield SpecialPowers.pushPrefEnv({ set: [ - [ "dom.ipc.processCount", 1 ], [ "browser.tabs.animate", false] ] }); }); @@ -241,7 +240,7 @@ add_task(function* test_revive_tab_from_session_store() { browser.loadURI(PAGE_1); yield promiseBrowserLoaded(browser); - let newTab2 = gBrowser.addTab(); + let newTab2 = gBrowser.addTab("about:blank", { sameProcessAsFrameLoader: browser.frameLoader }); let browser2 = newTab2.linkedBrowser; ok(browser2.isRemoteBrowser, "Should be a remote browser"); yield promiseBrowserLoaded(browser2); @@ -298,7 +297,7 @@ add_task(function* test_revive_all_tabs_from_session_store() { // a second window, since only selected tabs will show // about:tabcrashed. let win2 = yield BrowserTestUtils.openNewBrowserWindow(); - let newTab2 = win2.gBrowser.addTab(PAGE_1); + let newTab2 = win2.gBrowser.addTab(PAGE_1, { sameProcessAsFrameLoader: browser.frameLoader }); win2.gBrowser.selectedTab = newTab2; let browser2 = newTab2.linkedBrowser; ok(browser2.isRemoteBrowser, "Should be a remote browser"); @@ -405,7 +404,7 @@ add_task(function* test_hide_restore_all_button() { // Load up a second window so we can get another tab to show // about:tabcrashed let win2 = yield BrowserTestUtils.openNewBrowserWindow(); - let newTab3 = win2.gBrowser.addTab(PAGE_2); + let newTab3 = win2.gBrowser.addTab(PAGE_2, { sameProcessAsFrameLoader: browser.frameLoader }); win2.gBrowser.selectedTab = newTab3; let otherWinBrowser = newTab3.linkedBrowser; yield promiseBrowserLoaded(otherWinBrowser); diff --git a/toolkit/content/widgets/remote-browser.xml b/toolkit/content/widgets/remote-browser.xml index 0dde870a52782..141dba9454763 100644 --- a/toolkit/content/widgets/remote-browser.xml +++ b/toolkit/content/widgets/remote-browser.xml @@ -190,7 +190,9 @@ let changed = val.toFixed(2) != this._fullZoom.toFixed(2); this._fullZoom = val; - this.messageManager.sendAsyncMessage("FullZoom", {value: val}); + try { + this.messageManager.sendAsyncMessage("FullZoom", {value: val}); + } catch(ex) {} if (changed) { let event = new Event("FullZoomChange", {bubbles: true}); @@ -208,7 +210,9 @@ let changed = val.toFixed(2) != this._textZoom.toFixed(2); this._textZoom = val; - this.messageManager.sendAsyncMessage("TextZoom", {value: val}); + try { + this.messageManager.sendAsyncMessage("TextZoom", {value: val}); + } catch(ex) {} if (changed) { let event = new Event("TextZoomChange", {bubbles: true}); From 770c47f73cb007347674d8245b70a77a2f3afe9f Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Tue, 21 Feb 2017 11:27:23 +0100 Subject: [PATCH 04/42] Bug 1337730 - part1: releaseCachedProcesses API for testing. r=mrbkap --- dom/base/nsFrameMessageManager.cpp | 8 +++++++- dom/base/nsIMessageManager.idl | 6 ++++++ dom/ipc/ContentParent.cpp | 26 ++++++++++++++++++++++++++ dom/ipc/ContentParent.h | 2 ++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 489b4d4d69923..5b66c4c69b185 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -35,7 +35,7 @@ #include "mozilla/Telemetry.h" #include "mozilla/dom/File.h" #include "mozilla/dom/MessagePort.h" -#include "mozilla/dom/nsIContentParent.h" +#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/ProcessGlobal.h" #include "mozilla/dom/SameProcessMessageQueue.h" @@ -778,6 +778,12 @@ nsFrameMessageManager::GetChildAt(uint32_t aIndex, return NS_OK; } +NS_IMETHODIMP +nsFrameMessageManager::ReleaseCachedProcesses() +{ + ContentParent::ReleaseCachedProcesses(); + return NS_OK; +} // nsIContentFrameMessageManager diff --git a/dom/base/nsIMessageManager.idl b/dom/base/nsIMessageManager.idl index 375f92abd4485..605f26d5738ca 100644 --- a/dom/base/nsIMessageManager.idl +++ b/dom/base/nsIMessageManager.idl @@ -327,6 +327,12 @@ interface nsIMessageBroadcaster : nsIMessageListenerManager * Return a single subordinate message manager. */ nsIMessageListenerManager getChildAt(in unsigned long aIndex); + + /** + * Some processes are kept alive after their last tab/window are closed for testing + * (see dom.ipc.keepProcessesAlive). This function releases those. + */ + void releaseCachedProcesses(); }; [scriptable, builtinclass, uuid(0e602c9e-1977-422a-a8e4-fe0d4a4f78d0)] diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index d218912eab640..5e4fd19a12ed8 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -650,6 +650,32 @@ ContentParent::IsMaxProcessCountReached(const nsAString& aContentProcessType) return GetPoolSize(aContentProcessType) >= GetMaxProcessCount(aContentProcessType); } +/*static*/ void +ContentParent::ReleaseCachedProcesses() +{ + // We might want to extend this for other process types as well in the future... + nsTArray& contentParents = GetOrCreatePool(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE)); + ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); + nsTArray toRelease; + + // Shuting down these processes will change the array so let's use another array for the removal. + for (auto* cp : contentParents) { + nsTArray tabIds = cpm->GetTabParentsByProcessId(cp->mChildID); + if (!tabIds.Length()) { + toRelease.AppendElement(cp); + } + } + + for (auto* cp : toRelease) { + // Start a soft shutdown. + cp->ShutDownProcess(SEND_SHUTDOWN_MESSAGE); + // Make sure we don't select this process for new tabs. + cp->MarkAsDead(); + // Make sure that this process is no longer accessible from JS by its message manager. + cp->ShutDownMessageManager(); + } +} + /*static*/ already_AddRefed ContentParent::RandomSelect(const nsTArray& aContentParents, ContentParent* aOpener, int32_t aMaxContentParents) diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 81f4a2c4ba698..4a2de11ccc516 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -153,6 +153,8 @@ class ContentParent final : public PContentParent static bool IsMaxProcessCountReached(const nsAString& aContentProcessType); + static void ReleaseCachedProcesses(); + /** * Picks a random content parent from |aContentParents| with a given |aOpener| * respecting the index limit set by |aMaxContentParents|. From ab52060726d36b54039bc6cfcfcd824be327b339 Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Tue, 21 Feb 2017 11:27:27 +0100 Subject: [PATCH 05/42] Bug 1337730 - Fixing loadprocesscript test for e10s-multi. r=mrbkap --- dom/base/test/browser.ini | 1 - ...rowser_messagemanager_loadprocessscript.js | 31 ++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/dom/base/test/browser.ini b/dom/base/test/browser.ini index 32db9ce1b7b23..e65fc2b41f4ac 100644 --- a/dom/base/test/browser.ini +++ b/dom/base/test/browser.ini @@ -24,7 +24,6 @@ tags = mcb [browser_bug1011748.js] [browser_bug1058164.js] [browser_messagemanager_loadprocessscript.js] -skip-if = e10s # Bug 1315042 [browser_messagemanager_targetframeloader.js] [browser_messagemanager_unload.js] [browser_pagehide_on_tab_close.js] diff --git a/dom/base/test/browser_messagemanager_loadprocessscript.js b/dom/base/test/browser_messagemanager_loadprocessscript.js index feabfb43c6532..d86c7a0483d38 100644 --- a/dom/base/test/browser_messagemanager_loadprocessscript.js +++ b/dom/base/test/browser_messagemanager_loadprocessscript.js @@ -49,6 +49,29 @@ function promiseMessage(messageManager, message) { }) } +add_task(function*(){ + // This test is only relevant in e10s. + if (!gMultiProcessBrowser) + return; + + ppmm.releaseCachedProcesses(); + + yield SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", 5]]}) + yield SpecialPowers.pushPrefEnv({"set": [["dom.ipc.keepProcessesAlive.web", 5]]}) + + let tabs = []; + for (let i = 0; i < 3; i++) { + tabs[i] = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); + } + + for (let i = 0; i < 3; i++) { + yield BrowserTestUtils.removeTab(tabs[i]); + } + + ppmm.releaseCachedProcesses(); + is(ppmm.childCount, 3, "Should get back to 3 processes at this point."); +}) + // Test that loading a process script loads in all existing processes add_task(function*() { let checks = []; @@ -65,7 +88,7 @@ add_task(function*() { if (!gMultiProcessBrowser) return; - is(ppmm.childCount, 2, "Should be two processes at this point"); + is(ppmm.childCount, 3, "Should be three processes at this point"); // Load something in the main process gBrowser.selectedBrowser.loadURI("about:robots"); @@ -80,7 +103,7 @@ add_task(function*() { // However, stuff like remote thumbnails can cause a content // process to exist nonetheless. This should be rare, though, // so the test is useful most of the time. - if (ppmm.childCount == 1) { + if (ppmm.childCount == 2) { let mainMM = ppmm.getChildAt(0); let check = checkProcess(ppmm); @@ -95,7 +118,7 @@ add_task(function*() { gBrowser.selectedBrowser.loadURI("about:blank"); yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); - is(ppmm.childCount, 2, "Should be back to two processes at this point"); + is(ppmm.childCount, 3, "Should be back to three processes at this point"); // The new process should have responded yield check; @@ -103,7 +126,7 @@ add_task(function*() { ppmm.removeDelayedProcessScript(processScriptURL); let childMM; - childMM = ppmm.getChildAt(0) == mainMM ? ppmm.getChildAt(1) : ppmm.getChildAt(0); + childMM = ppmm.getChildAt(2); childMM.loadProcessScript(initTestScriptURL, false); let msg = yield promiseMessage(childMM, "ProcessTest:InitGood"); From 5d759be63fd67368694ee636fe01e71baa2990c6 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 14 Dec 2016 14:58:26 -0500 Subject: [PATCH 06/42] bug 1318370 - stop using -Z7 for MSVC compilation with sccache. r=glandium We've been using -Z7 to make MSVC emit CodeView debug info directly in the object files instead of in PDB files because sccache can't cache PDB files if the same one is written to by multiple compiles, which was previously happening in our build system, and was hard to override in the NSS build. Now that those are fixed this should work fine. This adds a bit to the compile rule to remove the PDB file before compilation, since sccache won't cache a compilation if the PDB file it is supposed to generate already exists (for the aforementioned reason). MozReview-Commit-ID: rFlX0XfTGw --HG-- extra : rebase_source : 8f991ce72115537466f5720c20dc53083f3b2b35 --- build/mozconfig.cache | 5 ----- config/rules.mk | 12 ++++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/build/mozconfig.cache b/build/mozconfig.cache index d683f0c58fdda..6bbe4c160094c 100644 --- a/build/mozconfig.cache +++ b/build/mozconfig.cache @@ -131,11 +131,6 @@ else # Windows builds have a default wrapper that needs to be overridden mk_add_options "export CC_WRAPPER=" mk_add_options "export CXX_WRAPPER=" - # For now, sccache doesn't support separate PDBs so force debug info to be - # in object files. - mk_add_options "export COMPILE_PDB_FLAG=" - mk_add_options "export HOST_PDB_FLAG=" - mk_add_options "export MOZ_DEBUG_FLAGS=-Z7" ;; esac fi diff --git a/config/rules.mk b/config/rules.mk index 1f974406b2204..5afd1bd98c035 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -156,6 +156,10 @@ ifndef GNU_CC COMPILE_PDB_FLAG ?= -Fd$(basename $(@F)).pdb COMPILE_CFLAGS += $(COMPILE_PDB_FLAG) COMPILE_CXXFLAGS += $(COMPILE_PDB_FLAG) +ifdef MOZ_USING_SCCACHE +# We remove the PDB file before compilation so that sccache knows it's safe to cache. +RM_PDB_FILE = -$(RM) $(basename $(@F)).pdb +endif LINK_PDBFILE ?= $(basename $(@F)).pdb ifdef MOZ_DEBUG @@ -850,23 +854,28 @@ $(OBJS) $(HOST_OBJS) $(PROGOBJS) $(HOST_PROGOBJS): $(GLOBAL_DEPS) # Rules for building native targets must come first because of the host_ prefix $(HOST_COBJS): $(REPORT_BUILD_VERBOSE) + $(RM_PDB_FILE) $(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CPPFLAGS) $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(HOST_CPPOBJS): $(REPORT_BUILD_VERBOSE) $(call BUILDSTATUS,OBJECT_FILE $@) + $(RM_PDB_FILE) $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CPPFLAGS) $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(HOST_CMOBJS): $(REPORT_BUILD_VERBOSE) + $(RM_PDB_FILE) $(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CPPFLAGS) $(HOST_CFLAGS) $(HOST_CMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(HOST_CMMOBJS): $(REPORT_BUILD_VERBOSE) + $(RM_PDB_FILE) $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CPPFLAGS) $(HOST_CXXFLAGS) $(HOST_CMMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(COBJS): $(REPORT_BUILD_VERBOSE) + $(RM_PDB_FILE) $(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $($(notdir $<)_FLAGS) $(_VPATH_SRCS) # DEFINES and ACDEFINES are needed here to enable conditional compilation of Q_OBJECTs: @@ -998,14 +1007,17 @@ $(SOBJS): $(CPPOBJS): $(REPORT_BUILD_VERBOSE) $(call BUILDSTATUS,OBJECT_FILE $@) + $(RM_PDB_FILE) $(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(_VPATH_SRCS) $(CMMOBJS): $(REPORT_BUILD_VERBOSE) + $(RM_PDB_FILE) $(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $($(notdir $<)_FLAGS) $(_VPATH_SRCS) $(CMOBJS): $(REPORT_BUILD_VERBOSE) + $(RM_PDB_FILE) $(ELOG) $(CC) -o $@ -c $(COMPILE_CFLAGS) $(COMPILE_CMFLAGS) $($(notdir $<)_FLAGS) $(_VPATH_SRCS) $(filter %.s,$(CPPSRCS:%.cpp=%.s)): %.s: %.cpp $(call mkdir_deps,$(MDDEPDIR)) From 0ba51f368364b00167a27ed09d3473bff8b6f007 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Tue, 10 Jan 2017 16:52:27 -0500 Subject: [PATCH 07/42] bug 1318370 - move _DEPEND_CFLAGS+CL_INCLUDES_PREFIX to toolchain.configure, ignore {CC,CXX}_WRAPPER when using sccache r=glandium Currently mozconfig.cache overrides a few build options for sccache. This patch moves them into toolchain.configure so that the build system will set them properly when sccache is in use. Additionally, {CC,CXX}_WRAPPER are set in config.mk, so just avoid setting them when sccache is in use. MozReview-Commit-ID: FYlVKRI8OiN --HG-- extra : rebase_source : cc7e4346869b98a52840c101824044abc236637f --- build/moz.configure/toolchain.configure | 31 +++++++++++++++++++ build/mozconfig.cache | 10 ------ config/config.mk | 6 ++-- js/src/old-configure.in | 41 ------------------------- old-configure.in | 41 ------------------------- 5 files changed, 33 insertions(+), 96 deletions(-) diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure index 7496a26fa10ac..ba2db8dcb21c6 100644 --- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -831,6 +831,7 @@ host_cxx_compiler = compiler('C++', host, c_compiler=host_c_compiler, other_c_compiler=c_compiler) # Generic compiler-based conditions. +building_with_msvc = depends(c_compiler)(lambda info: info.type == 'msvc') non_msvc_compiler = depends(c_compiler)(lambda info: info.type != 'msvc') building_with_gcc = depends(c_compiler)(lambda info: info.type == 'gcc') @@ -967,6 +968,36 @@ set_define('HAVE_VISIBILITY_ATTRIBUTE', set_config('WRAP_SYSTEM_INCLUDES', wrap_system_includes) set_config('VISIBILITY_FLAGS', visibility_flags) +@depends(c_compiler, using_sccache) +def depend_cflags(c_compiler, using_sccache): + if c_compiler.type != 'msvc': + return '-MD -MP -MF $(MDDEPDIR)/$(@F).pp' + elif using_sccache: + # sccache supports a special flag to create depfiles + # by parsing MSVC's -showIncludes output. + return '-deps$(MDDEPDIR)/$(@F).pp' + +set_config('_DEPEND_CFLAGS', depend_cflags) + +@depends(c_compiler, when=building_with_msvc) +@imports(_from='re', _import='compile', _as='re_compile') +def msvc_showincludes_prefix(c_compiler): + pattern = re_compile(r'^([^:]*:.*[ :] )(.*\\stdio.h)$') + output = try_invoke_compiler([c_compiler.compiler], 'C', '#include \n', + ['-nologo', '-c', '-Fonul', '-showIncludes']) + for line in output.splitlines(): + if line.endswith('\\stdio.h'): + m = pattern.match(line) + if m: + if not m.group(2): + die("Unable to parse cl -showIncludes prefix. " + + "This compiler's locale has an unsupported formatting.") + return m.group(1) + # We should have found the prefix and returned earlier + die('Cannot find cl -showIncludes prefix.') + +set_config('CL_INCLUDES_PREFIX', msvc_showincludes_prefix) + @depends(target) def is_windows(target): return target.kernel == 'WINNT' diff --git a/build/mozconfig.cache b/build/mozconfig.cache index 6bbe4c160094c..98cf83a8f4b6f 100644 --- a/build/mozconfig.cache +++ b/build/mozconfig.cache @@ -123,16 +123,6 @@ else mk_add_options MOZ_PREFLIGHT_ALL+=build/sccache.mk mk_add_options MOZ_POSTFLIGHT_ALL+=build/sccache.mk mk_add_options "UPLOAD_EXTRA_FILES+=sccache.log.gz" - case "$platform" in - win*) - # sccache supports a special flag to create depfiles. - #TODO: bug 1318370 - move this all into toolchain.configure - export _DEPEND_CFLAGS='-deps$(MDDEPDIR)/$(@F).pp' - # Windows builds have a default wrapper that needs to be overridden - mk_add_options "export CC_WRAPPER=" - mk_add_options "export CXX_WRAPPER=" - ;; - esac fi fi diff --git a/config/config.mk b/config/config.mk index df1a388be6542..6e1cd54cd191d 100644 --- a/config/config.mk +++ b/config/config.mk @@ -120,8 +120,10 @@ CONFIG_TOOLS = $(MOZ_BUILD_ROOT)/config AUTOCONF_TOOLS = $(MOZILLA_DIR)/build/autoconf ifdef _MSC_VER +ifndef MOZ_USING_SCCACHE CC_WRAPPER ?= $(call py_action,cl) CXX_WRAPPER ?= $(call py_action,cl) +endif endif # _MSC_VER CC := $(CC_WRAPPER) $(CC) @@ -623,7 +625,3 @@ endif PLY_INCLUDE = -I$(MOZILLA_DIR)/other-licenses/ply export CL_INCLUDES_PREFIX -# Make sure that the build system can handle non-ASCII characters -# in environment variables to prevent it from breking silently on -# non-English systems. -export NONASCII diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 24f6d00e74c74..49c428dd62338 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -1881,46 +1881,6 @@ AC_LANG_C MOZ_EXPAND_LIBS -dnl ======================================================== -dnl = -dnl = Build depencency options -dnl = -dnl ======================================================== -MOZ_ARG_HEADER(Build dependencies) - -if test "$GNU_CC" -a "$GNU_CXX"; then - _DEPEND_CFLAGS='-MD -MP -MF $(MDDEPDIR)/$(@F).pp' -else - dnl Don't override this for MSVC - if test -z "$_WIN32_MSVC"; then - _USE_CPP_INCLUDE_FLAG= - _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' - _DEFINES_CXXFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' - else - echo '#include ' > dummy-hello.c - changequote(,) - dnl This output is localized, split at the first double space or colon and space. - _CL_PREFIX_REGEX="^\([^:]*:.*[ :] \)\(.*\\\stdio.h\)$" - CL_INCLUDES_PREFIX=`${CC} -showIncludes -c -Fonul dummy-hello.c 2>&1 | sed -ne 's/'"$_CL_PREFIX_REGEX"'/\1/p'` - _CL_STDIO_PATH=`${CC} -showIncludes -c -Fonul dummy-hello.c 2>&1 | sed -ne 's/'"$_CL_PREFIX_REGEX"'/\2/p'` - changequote([,]) - if ! test -e "$_CL_STDIO_PATH"; then - AC_MSG_ERROR([Unable to parse cl -showIncludes prefix. This compiler's locale has an unsupported formatting.]) - fi - if test -z "$CL_INCLUDES_PREFIX"; then - AC_MSG_ERROR([Cannot find cl -showIncludes prefix.]) - fi - AC_SUBST(CL_INCLUDES_PREFIX) - rm -f dummy-hello.c - - dnl Make sure that the build system can handle non-ASCII characters - dnl in environment variables to prevent it from breaking silently on - dnl non-English systems. - NONASCII=$'\241\241' - AC_SUBST(NONASCII) - fi -fi - dnl ======================================================== dnl = Link js shell to system readline dnl ======================================================== @@ -2058,7 +2018,6 @@ HOST_CFLAGS=`echo \ HOST_CXXFLAGS=`echo \ $HOST_CXXFLAGS` -AC_SUBST(_DEPEND_CFLAGS) AC_SUBST(MOZ_SYSTEM_NSPR) OS_CFLAGS="$CFLAGS" diff --git a/old-configure.in b/old-configure.in index 961b2e61f3b19..9b7965645badc 100644 --- a/old-configure.in +++ b/old-configure.in @@ -4692,46 +4692,6 @@ if test "$COMPILE_ENVIRONMENT"; then MOZ_EXPAND_LIBS fi # COMPILE_ENVIRONMENT -dnl ======================================================== -dnl = -dnl = Build depencency options -dnl = -dnl ======================================================== -MOZ_ARG_HEADER(Build dependencies) - -if test "$GNU_CC" -a "$GNU_CXX"; then - _DEPEND_CFLAGS='-MD -MP -MF $(MDDEPDIR)/$(@F).pp' -else - dnl Don't override this for MSVC - if test -z "$_WIN32_MSVC"; then - _USE_CPP_INCLUDE_FLAG= - _DEFINES_CFLAGS='$(ACDEFINES) -D_MOZILLA_CONFIG_H_ -DMOZILLA_CLIENT' - _DEFINES_CXXFLAGS='$(ACDEFINES) -D_MOZILLA_CONFIG_H_ -DMOZILLA_CLIENT' - else - echo '#include ' > dummy-hello.c - changequote(,) - dnl This output is localized, split at the first double space or colon and space. - _CL_PREFIX_REGEX="^\([^:]*:.*[ :] \)\(.*\\\stdio.h\)$" - CL_INCLUDES_PREFIX=`${CC} -showIncludes -c -Fonul dummy-hello.c 2>&1 | sed -ne 's/'"$_CL_PREFIX_REGEX"'/\1/p'` - _CL_STDIO_PATH=`${CC} -showIncludes -c -Fonul dummy-hello.c 2>&1 | sed -ne 's/'"$_CL_PREFIX_REGEX"'/\2/p'` - changequote([,]) - if ! test -e "$_CL_STDIO_PATH"; then - AC_MSG_ERROR([Unable to parse cl -showIncludes prefix. This compiler's locale has an unsupported formatting.]) - fi - if test -z "$CL_INCLUDES_PREFIX"; then - AC_MSG_ERROR([Cannot find cl -showIncludes prefix.]) - fi - AC_SUBST(CL_INCLUDES_PREFIX) - rm -f dummy-hello.c - - dnl Make sure that the build system can handle non-ASCII characters - dnl in environment variables to prevent it from breaking silently on - dnl non-English systems. - NONASCII=$'\241\241' - AC_SUBST(NONASCII) - fi -fi - dnl ======================================================== dnl = dnl = Static Build Options @@ -5350,7 +5310,6 @@ HOST_CFLAGS=`echo \ HOST_CXXFLAGS=`echo \ $HOST_CXXFLAGS` -AC_SUBST(_DEPEND_CFLAGS) AC_SUBST(MOZ_SYSTEM_JPEG) AC_SUBST(MOZ_SYSTEM_PNG) AC_SUBST(MOZ_SYSTEM_BZ2) From c841558f8ec02ce32d799d2e1f9016fe51b5abc2 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Fri, 17 Feb 2017 14:31:20 -0500 Subject: [PATCH 08/42] bug 1318370 - remove SCCACHE_NAMESERVER from mozconfig.cache, unused since we switched to sccache2. r=glandium MozReview-Commit-ID: 1ktLJiIY9jh --HG-- extra : rebase_source : 7516f1c845656093818d6350a0927c47e56a429d --- build/mozconfig.cache | 5 ----- 1 file changed, 5 deletions(-) diff --git a/build/mozconfig.cache b/build/mozconfig.cache index 98cf83a8f4b6f..4dfcbc2ac691d 100644 --- a/build/mozconfig.cache +++ b/build/mozconfig.cache @@ -113,11 +113,6 @@ else exit 1 fi mk_add_options "export SCCACHE_BUCKET=$bucket" - case "$master" in - *us[ew][12].mozilla.com*|*euc1.mozilla.com*) - mk_add_options "export SCCACHE_NAMESERVER=169.254.169.253" - ;; - esac ac_add_options "--with-ccache=$topsrcdir/sccache2/sccache${suffix}" export SCCACHE_VERBOSE_STATS=1 mk_add_options MOZ_PREFLIGHT_ALL+=build/sccache.mk From 70d5eceb33fb77bdd7cf92e08772c8e361ff799d Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Tue, 21 Feb 2017 12:11:04 +0100 Subject: [PATCH 09/42] Backed out changeset 59d4978e8726 (bug 1289723) for eslint failure --- .../components/sessionstore/test/browser_crashedTabs.js | 7 ++++--- toolkit/content/widgets/remote-browser.xml | 8 ++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/browser/components/sessionstore/test/browser_crashedTabs.js b/browser/components/sessionstore/test/browser_crashedTabs.js index 193f9b16d535d..b97bc91e761a2 100644 --- a/browser/components/sessionstore/test/browser_crashedTabs.js +++ b/browser/components/sessionstore/test/browser_crashedTabs.js @@ -13,6 +13,7 @@ const PAGE_2 = "data:text/html,Another%20regular,%20everyday,%20norm add_task(function* test_initialize() { yield SpecialPowers.pushPrefEnv({ set: [ + [ "dom.ipc.processCount", 1 ], [ "browser.tabs.animate", false] ] }); }); @@ -240,7 +241,7 @@ add_task(function* test_revive_tab_from_session_store() { browser.loadURI(PAGE_1); yield promiseBrowserLoaded(browser); - let newTab2 = gBrowser.addTab("about:blank", { sameProcessAsFrameLoader: browser.frameLoader }); + let newTab2 = gBrowser.addTab(); let browser2 = newTab2.linkedBrowser; ok(browser2.isRemoteBrowser, "Should be a remote browser"); yield promiseBrowserLoaded(browser2); @@ -297,7 +298,7 @@ add_task(function* test_revive_all_tabs_from_session_store() { // a second window, since only selected tabs will show // about:tabcrashed. let win2 = yield BrowserTestUtils.openNewBrowserWindow(); - let newTab2 = win2.gBrowser.addTab(PAGE_1, { sameProcessAsFrameLoader: browser.frameLoader }); + let newTab2 = win2.gBrowser.addTab(PAGE_1); win2.gBrowser.selectedTab = newTab2; let browser2 = newTab2.linkedBrowser; ok(browser2.isRemoteBrowser, "Should be a remote browser"); @@ -404,7 +405,7 @@ add_task(function* test_hide_restore_all_button() { // Load up a second window so we can get another tab to show // about:tabcrashed let win2 = yield BrowserTestUtils.openNewBrowserWindow(); - let newTab3 = win2.gBrowser.addTab(PAGE_2, { sameProcessAsFrameLoader: browser.frameLoader }); + let newTab3 = win2.gBrowser.addTab(PAGE_2); win2.gBrowser.selectedTab = newTab3; let otherWinBrowser = newTab3.linkedBrowser; yield promiseBrowserLoaded(otherWinBrowser); diff --git a/toolkit/content/widgets/remote-browser.xml b/toolkit/content/widgets/remote-browser.xml index 141dba9454763..0dde870a52782 100644 --- a/toolkit/content/widgets/remote-browser.xml +++ b/toolkit/content/widgets/remote-browser.xml @@ -190,9 +190,7 @@ let changed = val.toFixed(2) != this._fullZoom.toFixed(2); this._fullZoom = val; - try { - this.messageManager.sendAsyncMessage("FullZoom", {value: val}); - } catch(ex) {} + this.messageManager.sendAsyncMessage("FullZoom", {value: val}); if (changed) { let event = new Event("FullZoomChange", {bubbles: true}); @@ -210,9 +208,7 @@ let changed = val.toFixed(2) != this._textZoom.toFixed(2); this._textZoom = val; - try { - this.messageManager.sendAsyncMessage("TextZoom", {value: val}); - } catch(ex) {} + this.messageManager.sendAsyncMessage("TextZoom", {value: val}); if (changed) { let event = new Event("TextZoomChange", {bubbles: true}); From 056368b30f5ce018d4c90dee8d1d06b1481638a6 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Tue, 21 Feb 2017 06:20:12 -0500 Subject: [PATCH 10/42] bug 1318370 - fix clang-cl builds. r=bustage MozReview-Commit-ID: 8imNZDxMkVF --HG-- extra : rebase_source : 58a6a51428b5c7229dc968e3cc74ea9b751f051e --- build/moz.configure/toolchain.configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure index ba2db8dcb21c6..fa044aa4cfa98 100644 --- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -970,9 +970,9 @@ set_config('VISIBILITY_FLAGS', visibility_flags) @depends(c_compiler, using_sccache) def depend_cflags(c_compiler, using_sccache): - if c_compiler.type != 'msvc': + if c_compiler.type in ('gcc', 'clang'): return '-MD -MP -MF $(MDDEPDIR)/$(@F).pp' - elif using_sccache: + elif c_compiler.type == 'msvc' and using_sccache: # sccache supports a special flag to create depfiles # by parsing MSVC's -showIncludes output. return '-deps$(MDDEPDIR)/$(@F).pp' From a9cf5da32eb22a98c6961fefa408e535fcfbb395 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Tue, 21 Feb 2017 04:38:48 -0700 Subject: [PATCH 11/42] Bug 1339944 - Prohibit context switches while handling OOM during type inference operations, r=jandem. --- js/src/vm/TypeInference.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 3439a056b7931..b3abba73c7d07 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -4599,6 +4599,7 @@ AutoClearTypeInferenceStateOnOOM::~AutoClearTypeInferenceStateOnOOM() if (oom) { JSRuntime* rt = zone->runtimeFromActiveCooperatingThread(); js::CancelOffThreadIonCompile(rt); + JSRuntime::AutoProhibitActiveContextChange apacc(rt); zone->setPreservingCode(false); zone->discardJitCode(rt->defaultFreeOp(), /* discardBaselineCode = */ false); zone->types.clearAllNewScriptsOnOOM(); From f9bc8c7133e570fce771c8c4f3a191cd2c0b6330 Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Tue, 21 Feb 2017 13:30:17 +0100 Subject: [PATCH 12/42] Bug 1289723 - Fixing crashedTabs test for e10s-multi. r=mrbkap r=felipc --- .../components/sessionstore/test/browser_crashedTabs.js | 7 +++---- toolkit/content/widgets/remote-browser.xml | 8 ++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/browser/components/sessionstore/test/browser_crashedTabs.js b/browser/components/sessionstore/test/browser_crashedTabs.js index b97bc91e761a2..193f9b16d535d 100644 --- a/browser/components/sessionstore/test/browser_crashedTabs.js +++ b/browser/components/sessionstore/test/browser_crashedTabs.js @@ -13,7 +13,6 @@ const PAGE_2 = "data:text/html,Another%20regular,%20everyday,%20norm add_task(function* test_initialize() { yield SpecialPowers.pushPrefEnv({ set: [ - [ "dom.ipc.processCount", 1 ], [ "browser.tabs.animate", false] ] }); }); @@ -241,7 +240,7 @@ add_task(function* test_revive_tab_from_session_store() { browser.loadURI(PAGE_1); yield promiseBrowserLoaded(browser); - let newTab2 = gBrowser.addTab(); + let newTab2 = gBrowser.addTab("about:blank", { sameProcessAsFrameLoader: browser.frameLoader }); let browser2 = newTab2.linkedBrowser; ok(browser2.isRemoteBrowser, "Should be a remote browser"); yield promiseBrowserLoaded(browser2); @@ -298,7 +297,7 @@ add_task(function* test_revive_all_tabs_from_session_store() { // a second window, since only selected tabs will show // about:tabcrashed. let win2 = yield BrowserTestUtils.openNewBrowserWindow(); - let newTab2 = win2.gBrowser.addTab(PAGE_1); + let newTab2 = win2.gBrowser.addTab(PAGE_1, { sameProcessAsFrameLoader: browser.frameLoader }); win2.gBrowser.selectedTab = newTab2; let browser2 = newTab2.linkedBrowser; ok(browser2.isRemoteBrowser, "Should be a remote browser"); @@ -405,7 +404,7 @@ add_task(function* test_hide_restore_all_button() { // Load up a second window so we can get another tab to show // about:tabcrashed let win2 = yield BrowserTestUtils.openNewBrowserWindow(); - let newTab3 = win2.gBrowser.addTab(PAGE_2); + let newTab3 = win2.gBrowser.addTab(PAGE_2, { sameProcessAsFrameLoader: browser.frameLoader }); win2.gBrowser.selectedTab = newTab3; let otherWinBrowser = newTab3.linkedBrowser; yield promiseBrowserLoaded(otherWinBrowser); diff --git a/toolkit/content/widgets/remote-browser.xml b/toolkit/content/widgets/remote-browser.xml index 0dde870a52782..43124992ca676 100644 --- a/toolkit/content/widgets/remote-browser.xml +++ b/toolkit/content/widgets/remote-browser.xml @@ -190,7 +190,9 @@ let changed = val.toFixed(2) != this._fullZoom.toFixed(2); this._fullZoom = val; - this.messageManager.sendAsyncMessage("FullZoom", {value: val}); + try { + this.messageManager.sendAsyncMessage("FullZoom", {value: val}); + } catch (ex) {} if (changed) { let event = new Event("FullZoomChange", {bubbles: true}); @@ -208,7 +210,9 @@ let changed = val.toFixed(2) != this._textZoom.toFixed(2); this._textZoom = val; - this.messageManager.sendAsyncMessage("TextZoom", {value: val}); + try { + this.messageManager.sendAsyncMessage("TextZoom", {value: val}); + } catch (ex) {} if (changed) { let event = new Event("TextZoomChange", {bubbles: true}); From 71aecda25d4074d58e52560bb183b4d2110581bd Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 21 Feb 2017 13:48:44 +0100 Subject: [PATCH 13/42] Bug 1338828 part 1 - Add CacheIR SetProp/SetElem stubs for proxies. r=h4writer --- js/src/jit/BaselineCacheIRCompiler.cpp | 73 ++++++++++++++++++++++++++ js/src/jit/CacheIR.cpp | 69 +++++++++++++++++++++++- js/src/jit/CacheIR.h | 19 +++++++ js/src/jit/IonCacheIRCompiler.cpp | 12 +++++ js/src/jit/IonCaches.cpp | 9 ---- js/src/proxy/Proxy.cpp | 25 +++++++++ js/src/proxy/Proxy.h | 9 +++- 7 files changed, 205 insertions(+), 11 deletions(-) diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp index 5c774bb357ae6..8c0bafdd69020 100644 --- a/js/src/jit/BaselineCacheIRCompiler.cpp +++ b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -1505,6 +1505,79 @@ BaselineCacheIRCompiler::emitCallSetArrayLength() return true; } +typedef bool (*ProxySetPropertyFn)(JSContext*, HandleObject, HandleId, HandleValue, bool); +static const VMFunction ProxySetPropertyInfo = + FunctionInfo(ProxySetProperty, "ProxySetProperty"); + +bool +BaselineCacheIRCompiler::emitCallProxySet() +{ + Register obj = allocator.useRegister(masm, reader.objOperandId()); + ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId()); + Address idAddr(stubAddress(reader.stubOffset())); + bool strict = reader.readBool(); + + AutoScratchRegister scratch(allocator, masm); + + allocator.discardStack(masm); + + AutoStubFrame stubFrame(*this); + stubFrame.enter(masm, scratch); + + // Load the jsid in the scratch register. + masm.loadPtr(idAddr, scratch); + + masm.Push(Imm32(strict)); + masm.Push(val); + masm.Push(scratch); + masm.Push(obj); + + if (!callVM(masm, ProxySetPropertyInfo)) + return false; + + stubFrame.leave(masm); + return true; +} + +typedef bool (*ProxySetPropertyByValueFn)(JSContext*, HandleObject, HandleValue, HandleValue, bool); +static const VMFunction ProxySetPropertyByValueInfo = + FunctionInfo(ProxySetPropertyByValue, "ProxySetPropertyByValue"); + +bool +BaselineCacheIRCompiler::emitCallProxySetByValue() +{ + Register obj = allocator.useRegister(masm, reader.objOperandId()); + ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId()); + ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId()); + bool strict = reader.readBool(); + + allocator.discardStack(masm); + + // We need a scratch register but we don't have any registers available on + // x86, so temporarily store |obj| in the frame's scratch slot. + int scratchOffset = BaselineFrame::reverseOffsetOfScratchValue(); + masm.storePtr(obj, Address(BaselineFrameReg, scratchOffset)); + + AutoStubFrame stubFrame(*this); + stubFrame.enter(masm, obj); + + // Restore |obj|. Because we entered a stub frame we first have to load + // the original frame pointer. + masm.loadPtr(Address(BaselineFrameReg, 0), obj); + masm.loadPtr(Address(obj, scratchOffset), obj); + + masm.Push(Imm32(strict)); + masm.Push(val); + masm.Push(idVal); + masm.Push(obj); + + if (!callVM(masm, ProxySetPropertyByValueInfo)) + return false; + + stubFrame.leave(masm); + return true; +} + bool BaselineCacheIRCompiler::emitTypeMonitorResult() { diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 00b9eb097698c..a8afbb3e873e9 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -1447,7 +1447,6 @@ SetPropIRGenerator::maybeEmitIdGuard(jsid id) emitIdGuard(setElemKeyValueId(), id); } - GetNameIRGenerator::GetNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, HandleObject env, HandlePropertyName name) : IRGenerator(cx, script, pc, CacheKind::GetName), @@ -1904,9 +1903,14 @@ SetPropIRGenerator::tryAttachStub() return true; if (tryAttachSetArrayLength(obj, objId, id, rhsValId)) return true; + if (tryAttachProxy(obj, objId, id, rhsValId)) + return true; return false; } + if (tryAttachProxyElement(obj, objId, rhsValId)) + return true; + uint32_t index; Int32OperandId indexId; if (maybeGuardInt32Index(idVal_, setElemKeyValueId(), &index, &indexId)) { @@ -2506,6 +2510,69 @@ SetPropIRGenerator::tryAttachSetUnboxedArrayElementHole(HandleObject obj, ObjOpe return true; } +bool +SetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id, + ValOperandId rhsId) +{ + MOZ_ASSERT(obj->is()); + + writer.guardIsProxy(objId); + + // Ensure that the incoming object is not a DOM proxy, so that we can get to + // the specialized stubs + writer.guardNotDOMProxy(objId); + + if (cacheKind_ == CacheKind::SetProp) { + writer.callProxySet(objId, id, rhsId, IsStrictSetPC(pc_)); + } else { + // We could call maybeEmitIdGuard here and then emit CallProxySet, but + // for SetElem we prefer to attach a stub that can handle any Value + // so we don't attach a new stub for every id. + MOZ_ASSERT(cacheKind_ == CacheKind::SetElem); + writer.callProxySetByValue(objId, setElemKeyValueId(), rhsId, IsStrictSetPC(pc_)); + } + + writer.returnFromIC(); + + trackAttached("GenericProxy"); + return true; +} + +bool +SetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id, + ValOperandId rhsId) +{ + switch (GetProxyStubType(cx_, obj, id)) { + case ProxyStubType::None: + return false; + case ProxyStubType::DOMExpando: + case ProxyStubType::DOMShadowed: + case ProxyStubType::DOMUnshadowed: + case ProxyStubType::Generic: + return tryAttachGenericProxy(obj, objId, id, rhsId); + } + + MOZ_CRASH("Unexpected ProxyStubType"); +} + +bool +SetPropIRGenerator::tryAttachProxyElement(HandleObject obj, ObjOperandId objId, ValOperandId rhsId) +{ + if (!obj->is()) + return false; + + writer.guardIsProxy(objId); + + // Like GetPropIRGenerator::tryAttachProxyElement, don't check for DOM + // proxies here as we don't have specialized DOM stubs for this. + MOZ_ASSERT(cacheKind_ == CacheKind::SetElem); + writer.callProxySetByValue(objId, setElemKeyValueId(), rhsId, IsStrictSetPC(pc_)); + writer.returnFromIC(); + + trackAttached("ProxyElement"); + return true; +} + bool SetPropIRGenerator::tryAttachAddSlotStub(HandleObjectGroup oldGroup, HandleShape oldShape) { diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index abc707b696923..ea901b700facc 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -195,6 +195,8 @@ extern const char* CacheKindNames[]; _(CallNativeSetter) \ _(CallScriptedSetter) \ _(CallSetArrayLength) \ + _(CallProxySet) \ + _(CallProxySetByValue) \ \ /* The *Result ops load a value into the cache's result register. */ \ _(LoadFixedSlotResult) \ @@ -707,6 +709,18 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter buffer_.writeByte(uint32_t(strict)); writeOperandId(rhs); } + void callProxySet(ObjOperandId obj, jsid id, ValOperandId rhs, bool strict) { + writeOpWithOperandId(CacheOp::CallProxySet, obj); + writeOperandId(rhs); + addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id); + buffer_.writeByte(uint32_t(strict)); + } + void callProxySetByValue(ObjOperandId obj, ValOperandId id, ValOperandId rhs, bool strict) { + writeOpWithOperandId(CacheOp::CallProxySetByValue, obj); + writeOperandId(id); + writeOperandId(rhs); + buffer_.writeByte(uint32_t(strict)); + } void loadBooleanResult(bool val) { writeOp(CacheOp::LoadBooleanResult); @@ -1077,6 +1091,11 @@ class MOZ_RAII SetPropIRGenerator : public IRGenerator bool tryAttachSetUnboxedArrayElementHole(HandleObject obj, ObjOperandId objId, uint32_t index, Int32OperandId indexId, ValOperandId rhsId); + bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id, + ValOperandId rhsId); + bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId); + bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId, ValOperandId rhsId); + void trackAttached(const char* name); public: diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp index 5370574c1bc4e..cdb700a2ef222 100644 --- a/js/src/jit/IonCacheIRCompiler.cpp +++ b/js/src/jit/IonCacheIRCompiler.cpp @@ -933,6 +933,18 @@ IonCacheIRCompiler::emitCallSetArrayLength() MOZ_CRASH("Baseline-specific op"); } +bool +IonCacheIRCompiler::emitCallProxySet() +{ + MOZ_CRASH("Baseline-specific op"); +} + +bool +IonCacheIRCompiler::emitCallProxySetByValue() +{ + MOZ_CRASH("Baseline-specific op"); +} + bool IonCacheIRCompiler::emitLoadTypedObjectResult() { diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 5b7a7d3886a2f..20139e529a6ca 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -1440,15 +1440,6 @@ EmitObjectOpResultCheck(MacroAssembler& masm, Label* failure, bool strict, masm.bind(&noStrictError); } -static bool -ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, bool strict) -{ - RootedValue receiver(cx, ObjectValue(*proxy)); - ObjectOpResult result; - return Proxy::set(cx, proxy, id, v, receiver, result) - && result.checkStrictErrorOrWarning(cx, proxy, id, strict); -} - static bool EmitCallProxySet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher, HandleId propId, LiveRegisterSet liveRegs, Register object, diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 16b504bd71bfa..e035e3c0161bc 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -354,6 +354,31 @@ Proxy::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, Handle return handler->set(cx, proxy, id, v, receiver, result); } +bool +js::ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue val, bool strict) +{ + ObjectOpResult result; + RootedValue receiver(cx, ObjectValue(*proxy)); + if (!Proxy::set(cx, proxy, id, val, receiver, result)) + return false; + return result.checkStrictErrorOrWarning(cx, proxy, id, strict); +} + +bool +js::ProxySetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal, HandleValue val, + bool strict) +{ + RootedId id(cx); + if (!ValueToId(cx, idVal, &id)) + return false; + + ObjectOpResult result; + RootedValue receiver(cx, ObjectValue(*proxy)); + if (!Proxy::set(cx, proxy, id, val, receiver, result)) + return false; + return result.checkStrictErrorOrWarning(cx, proxy, id, strict); +} + bool Proxy::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) { diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index 4e10ee0e0e2ca..eef9d0c6f12c2 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -79,7 +79,7 @@ proxy_Call(JSContext* cx, unsigned argc, Value* vp); bool proxy_Construct(JSContext* cx, unsigned argc, Value* vp); -// These two functions are used by JIT code +// These functions are used by JIT code bool ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp); @@ -88,6 +88,13 @@ bool ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal, MutableHandleValue vp); +bool +ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue val, bool strict); + +bool +ProxySetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal, HandleValue val, + bool strict); + } /* namespace js */ #endif /* proxy_Proxy_h */ From 26b0ba2897ea54da9a9e316f3edd012466591153 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 21 Feb 2017 13:49:05 +0100 Subject: [PATCH 14/42] Bug 1338828 part 2 - Add CacheIR SetProp/SetElem stubs for shadowing DOM proxies. r=h4writer --- js/src/jit/CacheIR.cpp | 20 ++++++++++++++++++++ js/src/jit/CacheIR.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index a8afbb3e873e9..55d5be2be2085 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -2538,6 +2538,25 @@ SetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, return true; } +bool +SetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id, + ValOperandId rhsId) +{ + MOZ_ASSERT(IsCacheableDOMProxy(obj)); + + maybeEmitIdGuard(id); + writer.guardShape(objId, obj->maybeShape()); + + // No need for more guards: we know this is a DOM proxy, since the shape + // guard enforces a given JSClass, so just go ahead and emit the call to + // ProxySet. + writer.callProxySet(objId, id, rhsId, IsStrictSetPC(pc_)); + writer.returnFromIC(); + + trackAttached("DOMProxyShadowed"); + return true; +} + bool SetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId) @@ -2547,6 +2566,7 @@ SetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleI return false; case ProxyStubType::DOMExpando: case ProxyStubType::DOMShadowed: + return tryAttachDOMProxyShadowed(obj, objId, id, rhsId); case ProxyStubType::DOMUnshadowed: case ProxyStubType::Generic: return tryAttachGenericProxy(obj, objId, id, rhsId); diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index ea901b700facc..01ed08b14b52d 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -1093,6 +1093,8 @@ class MOZ_RAII SetPropIRGenerator : public IRGenerator bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId); + bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id, + ValOperandId rhsId); bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId); bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId, ValOperandId rhsId); From cb50efb0c889eff1037bc807622a02d2a8aea43b Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 21 Feb 2017 13:49:29 +0100 Subject: [PATCH 15/42] Bug 1338828 part 3 - Add CacheIR SetProp/SetElem stubs for unshadowed setter calls on DOM proxies. r=h4writer --- js/src/jit/CacheIR.cpp | 109 +++++++++++++++++++++++++++++++---------- js/src/jit/CacheIR.h | 4 +- 2 files changed, 85 insertions(+), 28 deletions(-) diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 55d5be2be2085..23040728001f8 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -2165,9 +2165,36 @@ SetPropIRGenerator::trackNotAttached() #endif } +static bool +CanAttachSetter(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleId id, + MutableHandleObject holder, MutableHandleShape propShape, + bool* isTemporarilyUnoptimizable) +{ + // Don't attach a setter stub for ops like JSOP_INITELEM. + if (IsPropertyInitOp(JSOp(*pc))) + return false; + MOZ_ASSERT(IsPropertySetOp(JSOp(*pc))); + + PropertyResult prop; + if (!LookupPropertyPure(cx, obj, id, holder.address(), &prop)) + return false; + + if (prop.isNonNativeProperty()) + return false; + + propShape.set(prop.maybeShape()); + if (!IsCacheableSetPropCallScripted(obj, holder, propShape, isTemporarilyUnoptimizable) && + !IsCacheableSetPropCallNative(obj, holder, propShape)) + { + return false; + } + + return true; +} + static void -EmitCallSetterResultNoGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder, - Shape* shape, ObjOperandId objId, ValOperandId rhsId) +EmitCallSetterNoGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder, + Shape* shape, ObjOperandId objId, ValOperandId rhsId) { if (IsCacheableSetPropCallNative(obj, holder, shape)) { JSFunction* target = &shape->setterValue().toObject().as(); @@ -2189,30 +2216,15 @@ bool SetPropIRGenerator::tryAttachSetter(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId) { - // Don't attach a setter stub for ops like JSOP_INITELEM. - if (IsPropertyInitOp(JSOp(*pc_))) - return false; - MOZ_ASSERT(IsPropertySetOp(JSOp(*pc_))); - - PropertyResult prop; - JSObject* holder; - if (!LookupPropertyPure(cx_, obj, id, &holder, &prop)) - return false; - - if (prop.isNonNativeProperty()) + RootedObject holder(cx_); + RootedShape propShape(cx_); + if (!CanAttachSetter(cx_, pc_, obj, id, &holder, &propShape, isTemporarilyUnoptimizable_)) return false; - Shape* shape = prop.maybeShape(); - if (!IsCacheableSetPropCallScripted(obj, holder, shape, isTemporarilyUnoptimizable_) && - !IsCacheableSetPropCallNative(obj, holder, shape)) - { - return false; - } - maybeEmitIdGuard(id); Maybe expandoId; - TestMatchingReceiver(writer, obj, shape, objId, &expandoId); + TestMatchingReceiver(writer, obj, propShape, objId, &expandoId); if (obj != holder) { GeneratePrototypeGuards(writer, obj, holder, objId); @@ -2222,7 +2234,7 @@ SetPropIRGenerator::tryAttachSetter(HandleObject obj, ObjOperandId objId, Handle writer.guardShape(holderId, holder->as().lastProperty()); } - EmitCallSetterResultNoGuards(writer, obj, holder, shape, objId, rhsId); + EmitCallSetterNoGuards(writer, obj, holder, propShape, objId, rhsId); trackAttached("Setter"); return true; @@ -2512,15 +2524,19 @@ SetPropIRGenerator::tryAttachSetUnboxedArrayElementHole(HandleObject obj, ObjOpe bool SetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id, - ValOperandId rhsId) + ValOperandId rhsId, bool handleDOMProxies) { MOZ_ASSERT(obj->is()); writer.guardIsProxy(objId); - // Ensure that the incoming object is not a DOM proxy, so that we can get to - // the specialized stubs - writer.guardNotDOMProxy(objId); + if (!handleDOMProxies) { + // Ensure that the incoming object is not a DOM proxy, so that we can + // get to the specialized stubs. If handleDOMProxies is true, we were + // unable to attach a specialized DOM stub, so we just handle all + // proxies here. + writer.guardNotDOMProxy(objId); + } if (cacheKind_ == CacheKind::SetProp) { writer.callProxySet(objId, id, rhsId, IsStrictSetPC(pc_)); @@ -2557,6 +2573,42 @@ SetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId obj return true; } +bool +SetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id, + ValOperandId rhsId) +{ + MOZ_ASSERT(IsCacheableDOMProxy(obj)); + + RootedObject proto(cx_, obj->staticPrototype()); + if (!proto) + return false; + + RootedObject holder(cx_); + RootedShape propShape(cx_); + if (!CanAttachSetter(cx_, pc_, proto, id, &holder, &propShape, isTemporarilyUnoptimizable_)) + return false; + + maybeEmitIdGuard(id); + writer.guardShape(objId, obj->maybeShape()); + + // Guard that our expando object hasn't started shadowing this property. + CheckDOMProxyExpandoDoesNotShadow(writer, obj, id, objId); + + GeneratePrototypeGuards(writer, obj, holder, objId); + + // Guard on the holder of the property. + ObjOperandId holderId = writer.loadObject(holder); + writer.guardShape(holderId, holder->as().lastProperty()); + + // EmitCallSetterNoGuards expects |obj| to be the object the property is + // on to do some checks. Since we actually looked at proto, and no extra + // guards will be generated, we can just pass that instead. + EmitCallSetterNoGuards(writer, proto, holder, propShape, objId, rhsId); + + trackAttached("DOMProxyUnshadowed"); + return true; +} + bool SetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId) @@ -2568,8 +2620,11 @@ SetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleI case ProxyStubType::DOMShadowed: return tryAttachDOMProxyShadowed(obj, objId, id, rhsId); case ProxyStubType::DOMUnshadowed: + if (tryAttachDOMProxyUnshadowed(obj, objId, id, rhsId)) + return true; + return tryAttachGenericProxy(obj, objId, id, rhsId, /* handleDOMProxies = */ true); case ProxyStubType::Generic: - return tryAttachGenericProxy(obj, objId, id, rhsId); + return tryAttachGenericProxy(obj, objId, id, rhsId, /* handleDOMProxies = */ false); } MOZ_CRASH("Unexpected ProxyStubType"); diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 01ed08b14b52d..e05cfbef1b9d6 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -1092,9 +1092,11 @@ class MOZ_RAII SetPropIRGenerator : public IRGenerator Int32OperandId indexId, ValOperandId rhsId); bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id, - ValOperandId rhsId); + ValOperandId rhsId, bool handleDOMProxies); bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId); + bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id, + ValOperandId rhsId); bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId); bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId, ValOperandId rhsId); From 9fcb9743eef206f3f2db6818e1bb37d6c5146281 Mon Sep 17 00:00:00 2001 From: Franziskus Kiefer Date: Tue, 21 Feb 2017 13:55:41 +0100 Subject: [PATCH 16/42] Bug 1334127 - land NSS 93b99b0936d3, r=me --HG-- extra : rebase_source : 5793f0f4595bb1bbff9338dca3e4f5068db5a47f --- security/nss/TAG-INFO | 2 +- security/nss/automation/ossfuzz/build.sh | 44 +++++-- .../taskcluster/docker-aarch64/Dockerfile | 5 +- .../taskcluster/docker-aarch64/setup.sh | 11 +- .../taskcluster/graph/src/extend.js | 94 +++++++++----- .../taskcluster/graph/src/try_syntax.js | 13 +- security/nss/cmd/bltest/blapitest.c | 1 - security/nss/cmd/ecperf/ecperf.c | 1 - security/nss/cmd/fbectest/fbectest.c | 1 - security/nss/cmd/fipstest/fipstest.c | 2 +- security/nss/cmd/lib/secutil.c | 23 ++-- security/nss/cmd/tstclnt/tstclnt.c | 2 +- security/nss/coreconf/coreconf.dep | 1 + .../nss/coreconf/precommit.clang-format.sh | 63 ++++++++++ security/nss/fuzz/clone_libfuzzer.sh | 6 +- security/nss/fuzz/fuzz.gyp | 23 ++++ security/nss/fuzz/mpi-expmod.options | 2 +- security/nss/fuzz/mpi-invmod.options | 2 + security/nss/fuzz/mpi_add_target.cc | 2 +- security/nss/fuzz/mpi_addmod_target.cc | 2 +- security/nss/fuzz/mpi_div_target.cc | 2 +- security/nss/fuzz/mpi_expmod_target.cc | 2 +- security/nss/fuzz/mpi_helper.h | 28 ++++- security/nss/fuzz/mpi_invmod_target.cc | 70 +++++++++++ security/nss/fuzz/mpi_mod_target.cc | 2 +- security/nss/fuzz/mpi_mulmod_target.cc | 2 +- security/nss/fuzz/mpi_sqr_target.cc | 25 +--- security/nss/fuzz/mpi_sqrmod_target.cc | 21 +--- security/nss/fuzz/mpi_sub_target.cc | 2 +- security/nss/fuzz/mpi_submod_target.cc | 2 +- .../fuzz/tls-client-no_fuzzer_mode.options | 3 + security/nss/fuzz/tls_client_config.cc | 35 ++++++ security/nss/fuzz/tls_client_config.h | 24 ++++ security/nss/fuzz/tls_client_target.cc | 41 ++++-- security/nss/gtests/nss_bogo_shim/config.json | 20 +-- .../nss/gtests/nss_bogo_shim/nss_bogo_shim.cc | 87 +++++++++++-- security/nss/gtests/pk11_gtest/manifest.mn | 1 + .../pk11_gtest/pk11_curve25519_unittest.cc | 117 ++++++++++++++++++ security/nss/gtests/pk11_gtest/pk11_gtest.gyp | 1 + .../nss/gtests/ssl_gtest/libssl_internals.c | 4 + .../nss/gtests/ssl_gtest/libssl_internals.h | 1 + .../gtests/ssl_gtest/ssl_cert_ext_unittest.cc | 31 +++++ .../ssl_gtest/ssl_ciphersuite_unittest.cc | 9 +- .../ssl_gtest/ssl_resumption_unittest.cc | 57 +++++++++ security/nss/gtests/ssl_gtest/tls_connect.cc | 1 + security/nss/lib/base/error.c | 3 + security/nss/lib/cryptohi/keyi.h | 7 -- security/nss/lib/cryptohi/keythi.h | 6 +- security/nss/lib/cryptohi/seckey.c | 69 ++++------- security/nss/lib/freebl/blapi.h | 7 +- security/nss/lib/freebl/blapit.h | 1 - security/nss/lib/freebl/drbg.c | 4 +- security/nss/lib/freebl/ec.c | 19 ++- security/nss/lib/freebl/ecdecode.c | 18 ++- security/nss/lib/freebl/ecl/ecp_25519.c | 3 +- security/nss/lib/freebl/ecl/uint128.c | 5 +- security/nss/lib/freebl/freebl_base.gypi | 5 + security/nss/lib/freebl/ldvector.c | 6 +- security/nss/lib/freebl/loader.c | 8 ++ security/nss/lib/freebl/loader.h | 6 +- security/nss/lib/freebl/mpi/README | 3 - security/nss/lib/freebl/mpi/mpi-config.h | 4 - security/nss/lib/freebl/mpi/mpi.c | 2 - security/nss/lib/freebl/mpi/mpi.h | 2 - security/nss/lib/freebl/mpi/mpprime.h | 4 + security/nss/lib/pk11wrap/pk11akey.c | 4 +- security/nss/lib/pk11wrap/pk11skey.c | 39 +++++- security/nss/lib/softoken/pkcs11.c | 2 +- security/nss/lib/softoken/pkcs11c.c | 9 +- security/nss/lib/ssl/ssl3con.c | 12 +- security/nss/lib/ssl/ssl3ecc.c | 8 +- security/nss/lib/ssl/ssl3exthandle.c | 10 +- security/nss/lib/ssl/sslimpl.h | 11 +- security/nss/lib/ssl/sslnonce.c | 3 +- security/nss/lib/ssl/tls13con.c | 73 +++-------- security/nss/lib/util/eccutil.h | 5 +- security/nss/lib/util/secport.h | 4 +- security/nss/tests/bogo/bogo.sh | 2 +- 78 files changed, 915 insertions(+), 337 deletions(-) create mode 100755 security/nss/coreconf/precommit.clang-format.sh create mode 100644 security/nss/fuzz/mpi-invmod.options create mode 100644 security/nss/fuzz/mpi_invmod_target.cc create mode 100644 security/nss/fuzz/tls-client-no_fuzzer_mode.options create mode 100644 security/nss/fuzz/tls_client_config.cc create mode 100644 security/nss/fuzz/tls_client_config.h create mode 100644 security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc diff --git a/security/nss/TAG-INFO b/security/nss/TAG-INFO index b218ebde2fc5b..4b2985be1f318 100644 --- a/security/nss/TAG-INFO +++ b/security/nss/TAG-INFO @@ -1 +1 @@ -tip +93b99b0936d3 diff --git a/security/nss/automation/ossfuzz/build.sh b/security/nss/automation/ossfuzz/build.sh index 08ffaa4c79d89..04dca18cf4483 100755 --- a/security/nss/automation/ossfuzz/build.sh +++ b/security/nss/automation/ossfuzz/build.sh @@ -9,17 +9,14 @@ # List of targets disabled for oss-fuzz. declare -A disabled=([pkcs8]=1) -# Build the library. -CXX="$CXX -stdlib=libc++" LDFLAGS="$CFLAGS" \ - ./build.sh -c -v --fuzz=oss --fuzz=tls --disable-tests +# List of targets we want to fuzz in TLS and non-TLS mode. +declare -A tls_targets=([tls-client]=1) -# Copy libFuzzer options -cp fuzz/*.options $OUT/ - -# Find fuzzing targets. -for fuzzer in $(find ../dist/Debug/bin -name "nssfuzz-*" -printf "%f\n"); do - name=${fuzzer:8} - [ -n "${disabled[$name]:-}" ] && continue; +# Helper function that copies a fuzzer binary and its seed corpus. +copy_fuzzer() +{ + local fuzzer=$1 + local name=$2 # Copy the binary. cp ../dist/Debug/bin/$fuzzer $OUT/$name @@ -30,4 +27,31 @@ for fuzzer in $(find ../dist/Debug/bin -name "nssfuzz-*" -printf "%f\n"); do else zip $OUT/${name}_seed_corpus.zip $SRC/nss-corpus/*/* fi +} + +# Copy libFuzzer options +cp fuzz/*.options $OUT/ + +# Build the library (non-TLS fuzzing mode). +CXX="$CXX -stdlib=libc++" LDFLAGS="$CFLAGS" \ + ./build.sh -c -v --fuzz=oss --fuzz --disable-tests + +# Copy fuzzing targets. +for fuzzer in $(find ../dist/Debug/bin -name "nssfuzz-*" -printf "%f\n"); do + name=${fuzzer:8} + if [ -z "${disabled[$name]:-}" ]; then + [ -n "${tls_targets[$name]:-}" ] && name="${name}-no_fuzzer_mode" + copy_fuzzer $fuzzer $name + fi +done + +# Build the library again (TLS fuzzing mode). +CXX="$CXX -stdlib=libc++" LDFLAGS="$CFLAGS" \ + ./build.sh -c -v --fuzz=oss --fuzz=tls --disable-tests + +# Copy dual mode targets in TLS mode. +for name in "${!tls_targets[@]}"; do + if [ -z "${disabled[$name]:-}" ]; then + copy_fuzzer nssfuzz-$name $name + fi done diff --git a/security/nss/automation/taskcluster/docker-aarch64/Dockerfile b/security/nss/automation/taskcluster/docker-aarch64/Dockerfile index 5fef5eafd1acb..cd58278f59720 100644 --- a/security/nss/automation/taskcluster/docker-aarch64/Dockerfile +++ b/security/nss/automation/taskcluster/docker-aarch64/Dockerfile @@ -1,4 +1,4 @@ -FROM aarch64/ubuntu:xenial-20161213 +FROM franziskus/xenial:aarch64 MAINTAINER Franziskus Kiefer RUN useradd -d /home/worker -s /bin/bash -m worker @@ -12,6 +12,9 @@ RUN chmod +x /home/worker/bin/* ADD setup.sh /tmp/setup.sh RUN bash /tmp/setup.sh +# Change user. +USER worker + # Env variables. ENV HOME /home/worker ENV SHELL /bin/bash diff --git a/security/nss/automation/taskcluster/docker-aarch64/setup.sh b/security/nss/automation/taskcluster/docker-aarch64/setup.sh index 4d1a93dd78670..b137a504650c2 100755 --- a/security/nss/automation/taskcluster/docker-aarch64/setup.sh +++ b/security/nss/automation/taskcluster/docker-aarch64/setup.sh @@ -4,6 +4,15 @@ set -v -e -x export DEBIAN_FRONTEND=noninteractive +apt-get -y update +apt-get -y install software-properties-common + +# Add more repos +add-apt-repository "deb http://ports.ubuntu.com/ xenial main restricted universe multiverse" +add-apt-repository "deb http://ports.ubuntu.com/ xenial-security main restricted universe multiverse" +add-apt-repository "deb http://ports.ubuntu.com/ xenial-updates main restricted universe multiverse" +add-apt-repository "deb http://ports.ubuntu.com/ xenial-backports main restricted universe multiverse" + # Update. apt-get -y update apt-get -y dist-upgrade @@ -13,8 +22,8 @@ apt_packages+=('build-essential') apt_packages+=('ca-certificates') apt_packages+=('curl') apt_packages+=('zlib1g-dev') -apt_packages+=('gyp') apt_packages+=('ninja-build') +apt_packages+=('gyp') apt_packages+=('mercurial') # Install packages. diff --git a/security/nss/automation/taskcluster/graph/src/extend.js b/security/nss/automation/taskcluster/graph/src/extend.js index be77e50e4b5c0..57858b229cac6 100644 --- a/security/nss/automation/taskcluster/graph/src/extend.js +++ b/security/nss/automation/taskcluster/graph/src/extend.js @@ -18,7 +18,7 @@ const WINDOWS_CHECKOUT_CMD = queue.filter(task => { if (task.group == "Builds") { // Remove extra builds on {A,UB}San and ARM. - if (task.collection == "asan" || task.collection == "arm-debug") { + if (task.collection == "asan" || task.platform == "aarch64") { return false; } @@ -27,6 +27,11 @@ queue.filter(task => { (task.platform != "linux64" || task.collection != "debug")) { return false; } + + // Make modular builds only on Linux x64. + if (task.symbol == "modular" && task.platform != "linux64") { + return false; + } } if (task.tests == "bogo" || task.tests == "interop") { @@ -35,20 +40,15 @@ queue.filter(task => { return false; } - // No ARM - if (task.collection == "arm-debug") { + // No ARM; TODO: enable + if (task.platform == "aarch64") { return false; } } - // Temporarily disable SSL tests on ARM. - if (task.tests == "ssl" && task.collection == "arm-debug") { - return false; - } - // GYP builds with -Ddisable_libpkix=1 by default. - if ((task.collection == "gyp" || task.collection == "asan") && - task.tests == "chains") { + if ((task.collection == "gyp" || task.collection == "asan" + || task.platform == "aarch64") && task.tests == "chains") { return false; } @@ -63,13 +63,6 @@ queue.map(task => { } } - if (task.collection == "arm-debug") { - // These tests take quite some time on our poor ARM devices. - if (task.tests == "chains" || (task.tests == "ssl" && task.cycle == "standard")) { - task.maxRunTime = 14400; - } - } - // Windows is slow. if (task.platform == "windows2012-64" && task.tests == "chains") { task.maxRunTime = 7200; @@ -149,15 +142,35 @@ export default async function main() { await scheduleTools(); - await scheduleLinux("Linux 32 (ARM, debug)", { - image: "franziskus/nss-arm-ci", + let aarch64_base = { + image: "franziskus/nss-aarch64-ci", provisioner: "localprovisioner", - collection: "arm-debug", - workerType: "nss-rpi", - platform: "linux32", - maxRunTime: 7200, - tier: 3 - }); + workerType: "nss-aarch64", + platform: "aarch64", + maxRunTime: 7200 + }; + + await scheduleLinux("Linux AArch64 (debug)", + merge({ + command: [ + "/bin/bash", + "-c", + "bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh" + ], + collection: "debug", + }, aarch64_base) + ); + + await scheduleLinux("Linux AArch64 (opt)", + merge({ + command: [ + "/bin/bash", + "-c", + "bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh --opt" + ], + collection: "opt", + }, aarch64_base) + ); } /*****************************************************************************/ @@ -251,7 +264,7 @@ async function scheduleLinux(name, base) { /*****************************************************************************/ -function scheduleFuzzingRun(base, name, target, max_len, symbol = null) { +function scheduleFuzzingRun(base, name, target, max_len, symbol = null, corpus = null) { const MAX_FUZZ_TIME = 300; queue.scheduleTask(merge(base, { @@ -260,7 +273,7 @@ function scheduleFuzzingRun(base, name, target, max_len, symbol = null) { "/bin/bash", "-c", "bin/checkout.sh && nss/automation/taskcluster/scripts/fuzz.sh " + - `${target} nss/fuzz/corpus/${target} ` + + `${target} nss/fuzz/corpus/${corpus || target} ` + `-max_total_time=${MAX_FUZZ_TIME} ` + `-max_len=${max_len}` ], @@ -290,7 +303,7 @@ async function scheduleFuzzing() { "/bin/bash", "-c", "bin/checkout.sh && " + - "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz=tls" + "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz" ], artifacts: { public: { @@ -308,9 +321,22 @@ async function scheduleFuzzing() { name: "Linux x64 (debug, fuzz)" })); + // The task that builds NSPR+NSS (TLS fuzzing mode). + let task_build_tls = queue.scheduleTask(merge(build_base, { + name: "Linux x64 (debug, TLS fuzz)", + symbol: "B", + group: "TLS", + command: [ + "/bin/bash", + "-c", + "bin/checkout.sh && " + + "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz=tls" + ], + })); + // Schedule tests. queue.scheduleTask(merge(base, { - parent: task_build, + parent: task_build_tls, name: "Gtests", command: [ "/bin/bash", @@ -337,10 +363,16 @@ async function scheduleFuzzing() { for (let name of mpi_names) { scheduleFuzzingRun(mpi_base, `MPI (${name})`, `mpi-${name}`, 4096, name); } + scheduleFuzzingRun(mpi_base, `MPI (invmod)`, `mpi-invmod`, 256, "invmod"); - // Schedule TLS fuzzing runs. + // Schedule TLS fuzzing runs (non-fuzzing mode). let tls_base = merge(run_base, {group: "TLS"}); - scheduleFuzzingRun(tls_base, "TLS Client", "tls-client", 20000, "client"); + scheduleFuzzingRun(tls_base, "TLS Client", "tls-client", 20000, "client-nfm", + "tls-client-no_fuzzer_mode"); + + // Schedule TLS fuzzing runs (fuzzing mode). + let tls_fm_base = merge(tls_base, {parent: task_build_tls}); + scheduleFuzzingRun(tls_fm_base, "TLS Client", "tls-client", 20000, "client"); return queue.submit(); } diff --git a/security/nss/automation/taskcluster/graph/src/try_syntax.js b/security/nss/automation/taskcluster/graph/src/try_syntax.js index 80da83e3e98db..e5203e714d234 100644 --- a/security/nss/automation/taskcluster/graph/src/try_syntax.js +++ b/security/nss/automation/taskcluster/graph/src/try_syntax.js @@ -22,8 +22,8 @@ function parseOptions(opts) { } // Parse platforms. - let allPlatforms = ["linux", "linux64", "linux64-asan", "win64", "arm", - "linux64-gyp", "linux64-fuzz"]; + let allPlatforms = ["linux", "linux64", "linux64-asan", "win64", + "linux64-gyp", "linux64-fuzz", "aarch64"]; let platforms = intersect(opts.platform.split(/\s*,\s*/), allPlatforms); // If the given value is nonsense or "none" default to all platforms. @@ -108,8 +108,7 @@ function filter(opts) { "linux64-asan": "linux64", "linux64-fuzz": "linux64", "linux64-gyp": "linux64", - "win64": "windows2012-64", - "arm": "linux32" + "win64": "windows2012-64" }; // Check the platform name. @@ -118,8 +117,6 @@ function filter(opts) { // Additional checks. if (platform == "linux64-asan") { keep &= coll("asan"); - } else if (platform == "arm") { - keep &= coll("arm-opt") || coll("arm-debug"); } else if (platform == "linux64-gyp") { keep &= coll("gyp"); } else if (platform == "linux64-fuzz") { @@ -136,8 +133,8 @@ function filter(opts) { } // Finally, filter by build type. - let isDebug = coll("debug") || coll("asan") || coll("arm-debug") || - coll("gyp") || coll("fuzz"); + let isDebug = coll("debug") || coll("asan") || coll("gyp") || + coll("fuzz"); return (isDebug && opts.builds.includes("d")) || (!isDebug && opts.builds.includes("o")); } diff --git a/security/nss/cmd/bltest/blapitest.c b/security/nss/cmd/bltest/blapitest.c index 6a178ada8cbce..a3a162da12e8b 100644 --- a/security/nss/cmd/bltest/blapitest.c +++ b/security/nss/cmd/bltest/blapitest.c @@ -1870,7 +1870,6 @@ bltest_ecdsa_init(bltestCipherInfo *cipherInfo, PRBool encrypt) pubkey->ecParams.DEREncoding.len = key->ecParams.DEREncoding.len; pubkey->ecParams.DEREncoding.data = key->ecParams.DEREncoding.data; pubkey->ecParams.name = key->ecParams.name; - pubkey->ecParams.pointSize = key->ecParams.pointSize; pubkey->publicValue.len = key->publicValue.len; pubkey->publicValue.data = key->publicValue.data; asymk->pubKey = pubkey; diff --git a/security/nss/cmd/ecperf/ecperf.c b/security/nss/cmd/ecperf/ecperf.c index 41ecbdc609df3..40ba3c8a582a7 100644 --- a/security/nss/cmd/ecperf/ecperf.c +++ b/security/nss/cmd/ecperf/ecperf.c @@ -564,7 +564,6 @@ ectest_curve_freebl(ECCurveName curve, int iterations, int numThreads, ecParams.curve.seed.len = 0; ecParams.DEREncoding.data = NULL; ecParams.DEREncoding.len = 0; - ecParams.pointSize = ecCurve_map[curve]->pointSize; ecParams.fieldID.size = ecCurve_map[curve]->size; ecParams.fieldID.type = fieldType; diff --git a/security/nss/cmd/fbectest/fbectest.c b/security/nss/cmd/fbectest/fbectest.c index 18f0b737007ca..2b6541199217a 100644 --- a/security/nss/cmd/fbectest/fbectest.c +++ b/security/nss/cmd/fbectest/fbectest.c @@ -71,7 +71,6 @@ init_params(ECParams *ecParams, ECCurveName curve, PLArenaPool **arena, ecParams->fieldID.size = ecCurve_map[curve]->size; ecParams->fieldID.type = type; ecParams->cofactor = ecCurve_map[curve]->cofactor; - ecParams->pointSize = ecCurve_map[curve]->pointSize; return SECSuccess; } diff --git a/security/nss/cmd/fipstest/fipstest.c b/security/nss/cmd/fipstest/fipstest.c index c4c700cbb148d..ab73e42a5034b 100644 --- a/security/nss/cmd/fipstest/fipstest.c +++ b/security/nss/cmd/fipstest/fipstest.c @@ -2523,7 +2523,7 @@ ecdsa_pkv_test(char *reqfn) PORT_Free(pubkey.data); pubkey.data = NULL; } - SECITEM_AllocItem(NULL, &pubkey, ecparams->pointSize); + SECITEM_AllocItem(NULL, &pubkey, EC_GetPointSize(ecparams)); if (pubkey.data == NULL) { goto loser; } diff --git a/security/nss/cmd/lib/secutil.c b/security/nss/cmd/lib/secutil.c index 1d910a40b4568..cb4752df9ca7e 100644 --- a/security/nss/cmd/lib/secutil.c +++ b/security/nss/cmd/lib/secutil.c @@ -3230,6 +3230,8 @@ SEC_PrintCertificateAndTrust(CERTCertificate *cert, SECItem data; CERTCertTrust certTrust; PK11SlotList *slotList; + PRBool falseAttributeFound = PR_FALSE; + PRBool trueAttributeFound = PR_FALSE; const char *moz_policy_ca_info = NULL; data.data = cert->derCert.data; @@ -3250,23 +3252,24 @@ SEC_PrintCertificateAndTrust(CERTCertificate *cert, PORT_SetError(0); if (PK11_HasAttributeSet(se->slot, handle, CKA_NSS_MOZILLA_CA_POLICY, PR_FALSE)) { - moz_policy_ca_info = "true (attribute present)"; - } else { - if (PORT_GetError() != 0) { - moz_policy_ca_info = "false (attribute missing)"; - } else { - moz_policy_ca_info = "false (attribute present)"; - } + trueAttributeFound = PR_TRUE; + } else if (!PORT_GetError()) { + falseAttributeFound = PR_TRUE; } } } PK11_FreeSlotList(slotList); } - if (moz_policy_ca_info) { - SECU_Indent(stdout, 1); - printf("Mozilla-CA-Policy: %s\n", moz_policy_ca_info); + if (trueAttributeFound) { + moz_policy_ca_info = "true (attribute present)"; + } else if (falseAttributeFound) { + moz_policy_ca_info = "false (attribute present)"; + } else { + moz_policy_ca_info = "false (attribute missing)"; } + SECU_Indent(stdout, 1); + printf("Mozilla-CA-Policy: %s\n", moz_policy_ca_info); if (trust) { SECU_PrintTrustFlags(stdout, trust, diff --git a/security/nss/cmd/tstclnt/tstclnt.c b/security/nss/cmd/tstclnt/tstclnt.c index c2b916e90b58e..37d0667732773 100644 --- a/security/nss/cmd/tstclnt/tstclnt.c +++ b/security/nss/cmd/tstclnt/tstclnt.c @@ -1509,7 +1509,7 @@ main(int argc, char **argv) /* XXX: 'B' was used in the past but removed in 3.28, * please leave some time before resuing it. */ optstate = PL_CreateOptState(argc, argv, - "46A:CDFGHI:KL:M:OR:STUV:WYZa:bc:d:fgh:m:n:op:qr:st:uvw:z"); + "46A:CDFGHI:KL:M:OR:STUV:W:YZa:bc:d:fgh:m:n:op:qr:st:uvw:z"); while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch (optstate->option) { case '?': diff --git a/security/nss/coreconf/coreconf.dep b/security/nss/coreconf/coreconf.dep index 5182f75552c81..590d1bfaeee3f 100644 --- a/security/nss/coreconf/coreconf.dep +++ b/security/nss/coreconf/coreconf.dep @@ -10,3 +10,4 @@ */ #error "Do not include this header file." + diff --git a/security/nss/coreconf/precommit.clang-format.sh b/security/nss/coreconf/precommit.clang-format.sh new file mode 100755 index 0000000000000..11382c39bfddb --- /dev/null +++ b/security/nss/coreconf/precommit.clang-format.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# This is a pre-commit hook for use with either mercurial or git. +# +# Install this by running the script with an argument of "install". +# +# All that does is add the following lines to .hg/hgrc: +# +# [hook] +# pretxncommit.clang-format = [ ! -x ./coreconf/precommit.clang-format.sh ] || ./coreconf/precommit.clang-format.sh +# +# Or installs a symlink to .git/hooks/precommit: +# $ ln -s ../../coreconf/precommit.clang-format.sh .git/hooks/pre-commit + +hash clang-format || exit 1 +[ "$(hg root 2>/dev/null)" = "$PWD" ] && hg=1 || hg=0 +[ "$(git rev-parse --show-toplevel 2>/dev/null)" = "$PWD" ] && git=1 || git=0 + +if [ "$1" = "install" ]; then + if [ "$hg" -eq 1 ]; then + hgrc="$(hg root)"/.hg/hgrc + if ! grep -q '^pretxncommit.clang-format' "$hgrc"; then + echo '[hook]' >> "$hgrc" + echo 'pretxncommit.clang-format = [ ! -x ./coreconf/precommit.clang-format.sh ] || ./coreconf/precommit.clang-format.sh' >> "$hgrc" + echo "Installed mercurial pretxncommit hook" + exit + fi + fi + if [ "$git" -eq 1 ]; then + hook="$(git rev-parse --show-toplevel)"/.git/hooks/pre-commit + if [ ! -e "$hook" ]; then + ln -s ../../coreconf/precommit.clang-format.sh "$hook" + echo "Installed git pre-commit hook" + exit + fi + fi + echo "Hook already installed, or not in NSS repo" + exit 2 +fi + +err=0 +files=() +if [ "$hg" -eq 1 ]; then + files=($(hg status -m -a --rev tip^:tip | cut -f 2 -d ' ' -)) +fi +if [ "$git" -eq 1 ]; then + files=($(git status --porcelain | sed '/^[MACU]/{s/..//;p;};/^R/{s/^.* -> //;p;};d')) +fi +tmp=$(mktemp) +trap 'rm -f "$tmp"' ERR EXIT +for f in "${files[@]}"; do + ext="${f##*.}" + if [ "$ext" = "c" -o "$ext" = "h" -o "$ext" = "cc" ]; then + [ "$hg" -eq 1 ] && hg cat -r tip "$f" > "$tmp" + [ "$git" -eq 1 ] && git show :"$f" > "$tmp" + if ! cat "$tmp" | clang-format -assume-filename="$f" | \ + diff -q "$tmp" - >/dev/null; then + [ "$err" -eq 0 ] && echo "Formatting errors found in:" 1>&2 + echo " $f" 1>&2 + err=1 + fi + fi +done +exit "$err" diff --git a/security/nss/fuzz/clone_libfuzzer.sh b/security/nss/fuzz/clone_libfuzzer.sh index d57e6d8074ca9..9b9e096a9ae6a 100755 --- a/security/nss/fuzz/clone_libfuzzer.sh +++ b/security/nss/fuzz/clone_libfuzzer.sh @@ -1,7 +1,7 @@ #!/bin/sh d=$(dirname $0) -$d/git-copy.sh https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer 0b27dad707a1d67ec854423e25b1a521c9d5ab7a $d/libFuzzer +$d/git-copy.sh https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer b96a41ac6bbc3824fc7c7977662bebacac8f0983 $d/libFuzzer # [https://llvm.org/bugs/show_bug.cgi?id=31318] # This prevents a known buffer overrun that won't be fixed as the affected code @@ -30,8 +30,8 @@ cat < get_modulus(const uint8_t *data, size_t size, // Initialise MPI and BN variables // XXX: Also silence unused variable warnings for R. -#define INIT_NUMBERS \ +#define INIT_FOUR_NUMBERS \ mp_int a, b, c, r; \ mp_int *m1 = nullptr; \ BN_CTX *ctx = BN_CTX_new(); \ @@ -45,6 +45,24 @@ std::tuple get_modulus(const uint8_t *data, size_t size, (void)(R); \ } while (0); +// Initialise MPI and BN variables +// XXX: Also silence unused variable warnings for B. +#define INIT_THREE_NUMBERS \ + mp_int a, b, c; \ + BN_CTX *ctx = BN_CTX_new(); \ + BN_CTX_start(ctx); \ + BIGNUM *A = BN_CTX_get(ctx); \ + BIGNUM *B = BN_CTX_get(ctx); \ + BIGNUM *C = BN_CTX_get(ctx); \ + assert(mp_init(&a) == MP_OKAY); \ + assert(mp_init(&b) == MP_OKAY); \ + assert(mp_init(&c) == MP_OKAY); \ + size_t max_size = 4 * size + 1; \ + parse_input(data, size, A, &a); \ + do { \ + (void)(B); \ + } while (0); + #define CLEANUP_AND_RETURN \ mp_clear(&a); \ mp_clear(&b); \ @@ -57,4 +75,12 @@ std::tuple get_modulus(const uint8_t *data, size_t size, BN_CTX_free(ctx); \ return 0; +#define CLEANUP_AND_RETURN_THREE \ + mp_clear(&a); \ + mp_clear(&b); \ + mp_clear(&c); \ + BN_CTX_end(ctx); \ + BN_CTX_free(ctx); \ + return 0; + #endif // mpi_helper_h__ diff --git a/security/nss/fuzz/mpi_invmod_target.cc b/security/nss/fuzz/mpi_invmod_target.cc new file mode 100644 index 0000000000000..9820af947f4cf --- /dev/null +++ b/security/nss/fuzz/mpi_invmod_target.cc @@ -0,0 +1,70 @@ +/* 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/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" +#include "mpprime.h" + +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 4 to get everything we need from data. + if (size < 4) { + return 0; + } + + INIT_THREE_NUMBERS + + // Make a prime of length size. + int count = 0; + mp_err res = MP_NO; + // mpp_make_prime is so slow :( use something smaller than size. + int primeLen = std::max(static_cast(size / 4), 3); + uint8_t bp[primeLen]; + memcpy(bp, data, primeLen); + do { + bp[0] |= 0x80; /* set high-order bit */ + bp[primeLen - 1] |= 0x01; /* set low-order bit */ + ++count; + assert(mp_read_unsigned_octets(&b, bp, primeLen) == MP_OKAY); + } while ((res = mpp_make_prime(&b, primeLen * 8, PR_FALSE, nullptr)) != + MP_YES && + count < 10); + if (res != MP_YES) { + return 0; + } + + // Use the same prime in OpenSSL B + char tmp[max_size]; + mp_toradix(&b, tmp, 16); + int tmpLen; + assert((tmpLen = BN_hex2bn(&B, tmp)) != 0); + + // Compare with OpenSSL invmod + res = mp_invmod(&a, &b, &c); + BIGNUM *X = BN_mod_inverse(C, A, B, ctx); + if (res != MP_OKAY) { + // In case we couldn't compute the inverse, OpenSSL shouldn't be able to + // either. + assert(X == nullptr); + } else { + check_equal(C, &c, max_size); + + // Check a * c mod b == 1 + assert(mp_mulmod(&a, &c, &b, &c) == MP_OKAY); + bool eq = mp_cmp_d(&c, 1) == 0; + if (!eq) { + char cC[max_size]; + mp_tohex(&c, cC); + std::cout << "c = " << std::hex << cC << std::endl; + } + assert(eq); + } + + CLEANUP_AND_RETURN_THREE +} diff --git a/security/nss/fuzz/mpi_mod_target.cc b/security/nss/fuzz/mpi_mod_target.cc index 2be1bf0812306..85c883faffba6 100644 --- a/security/nss/fuzz/mpi_mod_target.cc +++ b/security/nss/fuzz/mpi_mod_target.cc @@ -14,7 +14,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < 3) { return 0; } - INIT_NUMBERS + INIT_FOUR_NUMBERS // We can't divide by 0. if (mp_cmp_z(&b) == 0) { diff --git a/security/nss/fuzz/mpi_mulmod_target.cc b/security/nss/fuzz/mpi_mulmod_target.cc index 7bd4261fa181f..75585e2d76dcc 100644 --- a/security/nss/fuzz/mpi_mulmod_target.cc +++ b/security/nss/fuzz/mpi_mulmod_target.cc @@ -14,7 +14,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < 3) { return 0; } - INIT_NUMBERS + INIT_FOUR_NUMBERS auto modulus = get_modulus(data, size, ctx); // Compare with OpenSSL mul mod diff --git a/security/nss/fuzz/mpi_sqr_target.cc b/security/nss/fuzz/mpi_sqr_target.cc index 1b85040853cbc..b404d624c9239 100644 --- a/security/nss/fuzz/mpi_sqr_target.cc +++ b/security/nss/fuzz/mpi_sqr_target.cc @@ -14,16 +14,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < 2) { return 0; } - mp_int a, c, r; - BN_CTX *ctx = BN_CTX_new(); - BN_CTX_start(ctx); - BIGNUM *A = BN_CTX_get(ctx); - BIGNUM *C = BN_CTX_get(ctx); - assert(mp_init(&a) == MP_OKAY); - assert(mp_init(&c) == MP_OKAY); - assert(mp_init(&r) == MP_OKAY); - size_t max_size = 4 * size + 1; - parse_input(data, size, A, &a); + + INIT_THREE_NUMBERS // Compare with OpenSSL sqr assert(mp_sqr(&a, &c) == MP_OKAY); @@ -31,11 +23,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { check_equal(C, &c, max_size); // Check a * a == a**2 - assert(mp_mul(&a, &a, &r) == MP_OKAY); - bool eq = mp_cmp(&r, &c) == 0; + assert(mp_mul(&a, &a, &b) == MP_OKAY); + bool eq = mp_cmp(&b, &c) == 0; if (!eq) { char rC[max_size], cC[max_size], aC[max_size]; - mp_tohex(&r, rC); + mp_tohex(&b, rC); mp_tohex(&c, cC); mp_tohex(&a, aC); std::cout << "a = " << std::hex << aC << std::endl; @@ -43,11 +35,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { std::cout << "a ** 2 = " << std::hex << rC << std::endl; } assert(eq); - mp_clear(&a); - mp_clear(&c); - mp_clear(&r); - BN_CTX_end(ctx); - BN_CTX_free(ctx); - return 0; + CLEANUP_AND_RETURN_THREE } diff --git a/security/nss/fuzz/mpi_sqrmod_target.cc b/security/nss/fuzz/mpi_sqrmod_target.cc index d3886dacd4370..ca403b5706319 100644 --- a/security/nss/fuzz/mpi_sqrmod_target.cc +++ b/security/nss/fuzz/mpi_sqrmod_target.cc @@ -14,17 +14,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < 3) { return 0; } - mp_int a, b, c; - BN_CTX *ctx = BN_CTX_new(); - BN_CTX_start(ctx); - BIGNUM *A = BN_CTX_get(ctx); - BIGNUM *B = BN_CTX_get(ctx); - BIGNUM *C = BN_CTX_get(ctx); - assert(mp_init(&a) == MP_OKAY); - assert(mp_init(&b) == MP_OKAY); - assert(mp_init(&c) == MP_OKAY); - size_t max_size = 4 * size + 1; - parse_input(data, size, A, &a); + + INIT_THREE_NUMBERS // We can't divide by 0. if (mp_cmp_z(&b) == 0) { @@ -41,11 +32,5 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { (void)BN_mod_sqr(C, A, B, ctx); check_equal(C, &c, max_size); - mp_clear(&a); - mp_clear(&b); - mp_clear(&c); - BN_CTX_end(ctx); - BN_CTX_free(ctx); - - return 0; + CLEANUP_AND_RETURN_THREE } diff --git a/security/nss/fuzz/mpi_sub_target.cc b/security/nss/fuzz/mpi_sub_target.cc index 1c8a4e90d6c0e..da20d74dabc94 100644 --- a/security/nss/fuzz/mpi_sub_target.cc +++ b/security/nss/fuzz/mpi_sub_target.cc @@ -14,7 +14,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < 3) { return 0; } - INIT_NUMBERS + INIT_FOUR_NUMBERS // Compare with OpenSSL subtraction assert(mp_sub(&a, &b, &c) == MP_OKAY); diff --git a/security/nss/fuzz/mpi_submod_target.cc b/security/nss/fuzz/mpi_submod_target.cc index d44facedacb05..26b2c5323de72 100644 --- a/security/nss/fuzz/mpi_submod_target.cc +++ b/security/nss/fuzz/mpi_submod_target.cc @@ -14,7 +14,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < 3) { return 0; } - INIT_NUMBERS + INIT_FOUR_NUMBERS auto modulus = get_modulus(data, size, ctx); // Compare with OpenSSL sub mod diff --git a/security/nss/fuzz/tls-client-no_fuzzer_mode.options b/security/nss/fuzz/tls-client-no_fuzzer_mode.options new file mode 100644 index 0000000000000..8b017d2ce6e8f --- /dev/null +++ b/security/nss/fuzz/tls-client-no_fuzzer_mode.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/tls_client_config.cc b/security/nss/fuzz/tls_client_config.cc new file mode 100644 index 0000000000000..78ab591e3961a --- /dev/null +++ b/security/nss/fuzz/tls_client_config.cc @@ -0,0 +1,35 @@ +/* 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/. */ + +#include "tls_client_config.h" + +const uint64_t CONFIG_FAIL_CERT_AUTH = 1; +const uint64_t CONFIG_ENABLE_EXTENDED_MS = 2; +const uint64_t CONFIG_REQUIRE_DH_NAMED_GROUPS = 4; +const uint64_t CONFIG_ENABLE_FALSE_START = 8; + +// XOR 64-bit chunks of data to build a bitmap of config options derived from +// the fuzzing input. This seems the only way to fuzz various options while +// still maintaining compatibility with BoringSSL or OpenSSL fuzzers. +ClientConfig::ClientConfig(const uint8_t* data, size_t len) { + for (size_t i = 0; i < len; i++) { + config_ ^= static_cast(data[i]) << (8 * (i % 8)); + } +} + +bool ClientConfig::FailCertificateAuthentication() { + return config_ & CONFIG_FAIL_CERT_AUTH; +} + +bool ClientConfig::EnableExtendedMasterSecret() { + return config_ & CONFIG_ENABLE_EXTENDED_MS; +} + +bool ClientConfig::RequireDhNamedGroups() { + return config_ & CONFIG_REQUIRE_DH_NAMED_GROUPS; +} + +bool ClientConfig::EnableFalseStart() { + return config_ & CONFIG_ENABLE_FALSE_START; +} diff --git a/security/nss/fuzz/tls_client_config.h b/security/nss/fuzz/tls_client_config.h new file mode 100644 index 0000000000000..9cf3cf208be22 --- /dev/null +++ b/security/nss/fuzz/tls_client_config.h @@ -0,0 +1,24 @@ +/* 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/. */ + +#ifndef tls_client_config_h__ +#define tls_client_config_h__ + +#include +#include + +class ClientConfig { + public: + ClientConfig(const uint8_t* data, size_t len); + + bool FailCertificateAuthentication(); + bool EnableExtendedMasterSecret(); + bool RequireDhNamedGroups(); + bool EnableFalseStart(); + + private: + uint64_t config_; +}; + +#endif // tls_client_config_h__ diff --git a/security/nss/fuzz/tls_client_target.cc b/security/nss/fuzz/tls_client_target.cc index 4d8ed9ee95c2c..d1dda12d4d4ae 100644 --- a/security/nss/fuzz/tls_client_target.cc +++ b/security/nss/fuzz/tls_client_target.cc @@ -11,6 +11,7 @@ #include "ssl.h" #include "shared.h" +#include "tls_client_config.h" #include "tls_client_socket.h" static PRStatus EnableAllProtocolVersions() { @@ -27,24 +28,26 @@ static PRStatus EnableAllProtocolVersions() { static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checksig, PRBool isServer) { - return SECSuccess; + assert(!isServer); + auto config = reinterpret_cast(arg); + return config->FailCertificateAuthentication() ? SECFailure : SECSuccess; } -static void SetSocketOptions(PRFileDesc* fd) { +static void SetSocketOptions(PRFileDesc* fd, + std::unique_ptr& config) { // Disable session cache for now. SECStatus rv = SSL_OptionSet(fd, SSL_NO_CACHE, true); assert(rv == SECSuccess); - rv = SSL_OptionSet(fd, SSL_ENABLE_EXTENDED_MASTER_SECRET, true); - assert(rv == SECSuccess); - - rv = SSL_OptionSet(fd, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, true); + rv = SSL_OptionSet(fd, SSL_ENABLE_EXTENDED_MASTER_SECRET, + config->EnableExtendedMasterSecret()); assert(rv == SECSuccess); - rv = SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true); + rv = SSL_OptionSet(fd, SSL_REQUIRE_DH_NAMED_GROUPS, + config->RequireDhNamedGroups()); assert(rv == SECSuccess); - rv = SSL_OptionSet(fd, SSL_ENABLE_ALPN, true); + rv = SSL_OptionSet(fd, SSL_ENABLE_FALSE_START, config->EnableFalseStart()); assert(rv == SECSuccess); rv = @@ -59,8 +62,19 @@ static void EnableAllCipherSuites(PRFileDesc* fd) { } } -static void SetupAuthCertificateHook(PRFileDesc* fd) { - SECStatus rv = SSL_AuthCertificateHook(fd, AuthCertificateHook, nullptr); +// This is only called when we set SSL_ENABLE_FALSE_START=1, +// so we can always just set *canFalseStart=true. +static SECStatus CanFalseStartCallback(PRFileDesc* fd, void* arg, + PRBool* canFalseStart) { + *canFalseStart = true; + return SECSuccess; +} + +static void SetupCallbacks(PRFileDesc* fd, ClientConfig* config) { + SECStatus rv = SSL_AuthCertificateHook(fd, AuthCertificateHook, config); + assert(rv == SECSuccess); + + rv = SSL_SetCanFalseStartCallback(fd, CanFalseStartCallback, nullptr); assert(rv == SECSuccess); } @@ -89,10 +103,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) { assert(db != nullptr); EnableAllProtocolVersions(); + std::unique_ptr config(new ClientConfig(data, len)); +#ifdef UNSAFE_FUZZER_MODE // Reset the RNG state. SECStatus rv = RNG_ResetForFuzzing(); assert(rv == SECSuccess); +#endif // Create and import dummy socket. std::unique_ptr socket(new DummyPrSocket(data, len)); @@ -104,9 +121,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) { // Probably not too important for clients. SSL_SetURL(ssl_fd, "server"); - SetSocketOptions(ssl_fd); + SetSocketOptions(ssl_fd, config); EnableAllCipherSuites(ssl_fd); - SetupAuthCertificateHook(ssl_fd); + SetupCallbacks(ssl_fd, config.get()); DoHandshake(ssl_fd); return 0; diff --git a/security/nss/gtests/nss_bogo_shim/config.json b/security/nss/gtests/nss_bogo_shim/config.json index 0a6864f73a8a9..7a52888189bbc 100644 --- a/security/nss/gtests/nss_bogo_shim/config.json +++ b/security/nss/gtests/nss_bogo_shim/config.json @@ -5,7 +5,6 @@ "#*HelloRetryRequest*":"(NSS=18, BoGo=16)", "#*KeyShare*":"(NSS=18, BoGo=16)", "#*EncryptedExtensions*":"(NSS=18, BoGo=16)", - "#*ServerHelloSignatureAlgorithms*":"(NSS=18, BoGo=16)", "#*SecondClientHello*":"(NSS=18, BoGo=16)", "#*IgnoreClientVersionOrder*":"(NSS=18, BoGo=16)", "Resume-Server-BinderWrongLength":"Alert disagreement (Bug 1317633)", @@ -13,27 +12,21 @@ "CheckRecordVersion-TLS*":"Bug 1317634", "GREASE-Server-TLS13":"BoringSSL GREASEs without a flag, but we ignore it", "TLS13-ExpectNoSessionTicketOnBadKEMode-Server":"Bug in NSS. Don't send ticket when not permitted by KE modes (Bug 1317635)", - "Resume-Server-InvalidPSKBinder":"(Bogo incorrectly expects 'illegal_parameter')", - "FallbackSCSV-VersionMatch":"Draft version mismatch (NSS=15, BoGo=14)", "*KeyUpdate*":"KeyUpdate Unimplemented", "ClientAuth-NoFallback-TLS13":"Disagreement about alerts. Bug 1294975", - "ClientAuth-SHA1-Fallback":"Disagreement about alerts. Bug 1294975", "SendWarningAlerts-TLS13":"NSS needs to trigger on warning alerts", "NoSupportedCurves":"This tests a non-spec behavior for TLS 1.2 and expects the wrong alert for TLS 1.3", "SendEmptyRecords":"Tests a non-spec behavior in BoGo where it chokes on too many empty records", "LargePlaintext":"NSS needs to check for over-long records. Bug 1294978", "TLS13-RC4-MD5-server":"This fails properly but returns an unexpected error. Not a bug but needs cleanup", - "*VersionTolerance":"BoGo expects us to negotiate 1.3 but we negotiate 1.2 because BoGo didn't send draft version", "*SSL3*":"NSS disables SSLv3", "*SSLv3*":"NSS disables SSLv3", "*AES256*":"Inconsistent support for AES256", "*AES128-SHA256*":"No support for Suite B ciphers", - "*CHACHA20-POLY1305-OLD*":"Old ChaCha/Poly", "DuplicateExtension*":"NSS sends unexpected_extension alert", "WeakDH":"NSS supports 768-bit DH", "SillyDH":"NSS supports 4097-bit DH", "SendWarningAlerts":"This appears to be Boring-specific", - "V2ClientHello-WarningAlertPrefix":"Bug 1292893", "TLS12-AES128-GCM-client":"Bug 1292895", "*TLS12-AES128-GCM-LargeRecord*":"Bug 1292895", "Renegotiate-Client-Forbidden-1":"Bug 1292898", @@ -51,11 +44,18 @@ "WrongMessageType-TLS13-ServerFinished":"nss updated/broken", "EncryptedExtensionsWithKeyShare":"nss updated/broken", "EmptyEncryptedExtensions":"nss updated/broken", - "ClientAuth-SHA1-Fallback-RSA":"We fail when the sig_algs_ext is empty", - "Downgrade-TLS12-*":"NSS implements downgrade detection", "TrailingMessageData-*": "Bug 1304575", "DuplicateKeyShares":"Bug 1304578", - "Resume-Server-TLS13-TLS13":"Bug 1314351" + "Resume-Server-TLS13-TLS13":"Bug 1314351", + "SkipEarlyData-Interleaved":"Bug 1336916", + "ECDSAKeyUsage-TLS1*":"Bug 1338194", + "PointFormat-Client-MissingUncompressed":"We ignore ec_point_formats extensions sent by servers.", + "SkipEarlyData-SecondClientHelloEarlyData":"Boring doesn't reject early_data in the 2nd CH but fails later with bad_record_mac.", + "SkipEarlyData-*TooMuchData":"Bug 1339373", + "UnsolicitedServerNameAck-TLS1*":"Boring wants us to fail with an unexpected_extension alert, we simply ignore ssl_server_name_xtn.", + "RequireAnyClientCertificate-TLS1*":"Bug 1339387", + "SendExtensionOnClientCertificate-TLS13":"Bug 1339392", + "ALPNClient-Mismatch-TLS1*":"Bug 1339418" }, "ErrorMap" : { ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:":"SSL_ERROR_NO_CYPHER_OVERLAP", diff --git a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc index f2fcd89cf867f..850d5cdeb964d 100644 --- a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc +++ b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc @@ -122,6 +122,11 @@ class TestAgent { cert_ = ReadCertificate(cfg_.get("cert-file")); if (!cert_) return false; } + + // Needed because certs are not entirely valid. + rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this); + if (rv != SECSuccess) return false; + if (cfg_.get("server")) { // Server rv = SSL_ConfigServerCert(ssl_fd_, cert_, key_, nullptr, 0); @@ -129,17 +134,11 @@ class TestAgent { std::cerr << "Couldn't configure server cert\n"; return false; } - } else { - // Client. - // Needed because server certs are not entirely valid. - rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this); + } else if (key_ && cert_) { + // Client. + rv = SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook, this); if (rv != SECSuccess) return false; - - if (key_ && cert_) { - rv = SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook, this); - if (rv != SECSuccess) return false; - } } return true; @@ -269,6 +268,47 @@ class TestAgent { rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE, false); if (rv != SECSuccess) return false; + auto alpn = cfg_.get("advertise-alpn"); + if (!alpn.empty()) { + assert(!cfg_.get("server")); + + rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_ALPN, PR_TRUE); + if (rv != SECSuccess) return false; + + rv = SSL_SetNextProtoNego( + ssl_fd_, reinterpret_cast(alpn.c_str()), + alpn.size()); + if (rv != SECSuccess) return false; + } + + if (cfg_.get("fallback-scsv")) { + rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_FALLBACK_SCSV, PR_TRUE); + if (rv != SECSuccess) return false; + } + + if (cfg_.get("false-start")) { + rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_FALSE_START, PR_TRUE); + if (rv != SECSuccess) return false; + } + + if (cfg_.get("enable-ocsp-stapling")) { + rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_OCSP_STAPLING, PR_TRUE); + if (rv != SECSuccess) return false; + } + + bool requireClientCert = cfg_.get("require-any-client-certificate"); + if (requireClientCert || cfg_.get("verify-peer")) { + assert(cfg_.get("server")); + + rv = SSL_OptionSet(ssl_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE); + if (rv != SECSuccess) return false; + + rv = SSL_OptionSet( + ssl_fd_, SSL_REQUIRE_CERTIFICATE, + requireClientCert ? SSL_REQUIRE_ALWAYS : SSL_REQUIRE_NO_ERROR); + if (rv != SECSuccess) return false; + } + if (!cfg_.get("server")) { // Needed to make resumption work. rv = SSL_SetURL(ssl_fd_, "server"); @@ -413,6 +453,28 @@ class TestAgent { } } + auto alpn = cfg_.get("expect-alpn"); + if (!alpn.empty()) { + SSLNextProtoState state; + char chosen[256]; + unsigned int chosen_len; + rv = SSL_GetNextProto(ssl_fd_, &state, + reinterpret_cast(chosen), + &chosen_len, sizeof(chosen)); + if (rv != SECSuccess) { + PRErrorCode err = PR_GetError(); + std::cerr << "SSL_GetNextProto failed with error=" << FormatError(err) + << std::endl; + return SECFailure; + } + + assert(chosen_len <= sizeof(chosen)); + if (std::string(chosen, chosen_len) != alpn) { + std::cerr << "Unexpected ALPN selection" << std::endl; + return SECFailure; + } + } + return SECSuccess; } @@ -437,7 +499,14 @@ std::unique_ptr ReadConfig(int argc, char** argv) { for (auto flag : kVersionDisableFlags) { cfg->AddEntry(flag, false); } + cfg->AddEntry("fallback-scsv", false); + cfg->AddEntry("false-start", false); + cfg->AddEntry("enable-ocsp-stapling", false); cfg->AddEntry("write-then-read", false); + cfg->AddEntry("require-any-client-certificate", false); + cfg->AddEntry("verify-peer", false); + cfg->AddEntry("advertise-alpn", ""); + cfg->AddEntry("expect-alpn", ""); auto rv = cfg->ParseArgs(argc, argv); switch (rv) { diff --git a/security/nss/gtests/pk11_gtest/manifest.mn b/security/nss/gtests/pk11_gtest/manifest.mn index cb78c8b3aeaab..453e09afd6d4b 100644 --- a/security/nss/gtests/pk11_gtest/manifest.mn +++ b/security/nss/gtests/pk11_gtest/manifest.mn @@ -9,6 +9,7 @@ MODULE = nss CPPSRCS = \ pk11_aeskeywrap_unittest.cc \ pk11_chacha20poly1305_unittest.cc \ + pk11_curve25519_unittest.cc \ pk11_ecdsa_unittest.cc \ pk11_export_unittest.cc \ pk11_pbkdf2_unittest.cc \ diff --git a/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc new file mode 100644 index 0000000000000..b2bd805c5df21 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc @@ -0,0 +1,117 @@ +/* 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/. */ + +#include +#include "nss.h" +#include "pk11pub.h" + +#include "gtest/gtest.h" +#include "scoped_ptrs.h" + +namespace nss_test { + +// +const uint8_t kPkcs8[] = { + 0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, + 0x47, 0x0f, 0x01, 0x04, 0x4c, 0x30, 0x4a, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, + 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, + 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a, 0xa1, 0x23, 0x03, 0x21, + 0x00, 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, + 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, + 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a}; +const uint8_t kSpki[] = { + 0x30, 0x39, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01, + 0x03, 0x21, 0x00, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, + 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, + 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f}; +const uint8_t kSecret[] = {0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, + 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, + 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, + 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42}; + +// A public key that's too short (31 bytes). +const uint8_t kSpkiShort[] = { + 0x30, 0x38, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01, + 0x03, 0x20, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, + 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, + 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f}; + +// A public key that's too long (33 bytes). +const uint8_t kSpkiLong[] = { + 0x30, 0x3a, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01, + 0x03, 0x22, 0x00, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, + 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, + 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f, 0x34}; + +static unsigned char* toUcharPtr(const uint8_t* v) { + return const_cast(static_cast(v)); +} + +class Pkcs11Curve25519Test : public ::testing::Test { + protected: + void Derive(const uint8_t* pkcs8, size_t pkcs8_len, const uint8_t* spki, + size_t spki_len, const uint8_t* secret, size_t secret_len, + bool expect_success) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_TRUE(slot); + + SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8), + static_cast(pkcs8_len)}; + + SECKEYPrivateKey* key = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key, + nullptr); + EXPECT_EQ(SECSuccess, rv); + + ScopedSECKEYPrivateKey privKey(key); + ASSERT_TRUE(privKey); + + SECItem spkiItem = {siBuffer, toUcharPtr(spki), + static_cast(spki_len)}; + + ScopedCERTSubjectPublicKeyInfo certSpki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem)); + ASSERT_TRUE(certSpki); + + ScopedSECKEYPublicKey pubKey(SECKEY_ExtractPublicKey(certSpki.get())); + ASSERT_TRUE(pubKey); + + ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF( + privKey.get(), pubKey.get(), false, nullptr, nullptr, CKM_ECDH1_DERIVE, + CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, nullptr)); + EXPECT_EQ(expect_success, !!symKey); + + if (expect_success) { + rv = PK11_ExtractKeyValue(symKey.get()); + EXPECT_EQ(SECSuccess, rv); + + SECItem* keyData = PK11_GetKeyData(symKey.get()); + EXPECT_EQ(secret_len, keyData->len); + EXPECT_EQ(memcmp(keyData->data, secret, secret_len), 0); + } + } +}; + +TEST_F(Pkcs11Curve25519Test, DeriveSharedSecret) { + Derive(kPkcs8, sizeof(kPkcs8), kSpki, sizeof(kSpki), kSecret, sizeof(kSecret), + true); +} + +TEST_F(Pkcs11Curve25519Test, DeriveSharedSecretShort) { + Derive(kPkcs8, sizeof(kPkcs8), kSpkiShort, sizeof(kSpkiShort), nullptr, 0, + false); +} + +TEST_F(Pkcs11Curve25519Test, DeriveSharedSecretLong) { + Derive(kPkcs8, sizeof(kPkcs8), kSpkiLong, sizeof(kSpkiLong), nullptr, 0, + false); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp index e01afff91cf9c..41578e7ca8740 100644 --- a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp +++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp @@ -13,6 +13,7 @@ 'sources': [ 'pk11_aeskeywrap_unittest.cc', 'pk11_chacha20poly1305_unittest.cc', + 'pk11_curve25519_unittest.cc', 'pk11_ecdsa_unittest.cc', 'pk11_pbkdf2_unittest.cc', 'pk11_prf_unittest.cc', diff --git a/security/nss/gtests/ssl_gtest/libssl_internals.c b/security/nss/gtests/ssl_gtest/libssl_internals.c index 14b5257f8a37f..dd168d2cdab72 100644 --- a/security/nss/gtests/ssl_gtest/libssl_internals.c +++ b/security/nss/gtests/ssl_gtest/libssl_internals.c @@ -367,3 +367,7 @@ SECStatus SSLInt_UsingShortHeaders(PRFileDesc *fd, PRBool *result) { return SECSuccess; } + +void SSLInt_SetTicketLifetime(uint32_t lifetime) { + ssl_ticket_lifetime = lifetime; +} diff --git a/security/nss/gtests/ssl_gtest/libssl_internals.h b/security/nss/gtests/ssl_gtest/libssl_internals.h index 342c3040a8802..9058f322ff9f8 100644 --- a/security/nss/gtests/ssl_gtest/libssl_internals.h +++ b/security/nss/gtests/ssl_gtest/libssl_internals.h @@ -49,5 +49,6 @@ SSLCipherAlgorithm SSLInt_CipherSpecToAlgorithm(PRBool isServer, unsigned char *SSLInt_CipherSpecToIv(PRBool isServer, ssl3CipherSpec *spec); SECStatus SSLInt_EnableShortHeaders(PRFileDesc *fd); SECStatus SSLInt_UsingShortHeaders(PRFileDesc *fd, PRBool *result); +void SSLInt_SetTicketLifetime(uint32_t lifetime); #endif // ndef libssl_internals_h_ diff --git a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc index 886ef48d3f770..c9bb390f18d4b 100644 --- a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc +++ b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc @@ -223,4 +223,35 @@ TEST_P(TlsConnectGeneric, OcspSuccess) { EXPECT_EQ(0U, capture_ocsp->extension().len()); } +TEST_P(TlsConnectGeneric, OcspHugeSuccess) { + EnsureTlsSetup(); + EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(), + SSL_ENABLE_OCSP_STAPLING, PR_TRUE)); + + uint8_t hugeOcspValue[16385]; + memset(hugeOcspValue, 0xa1, sizeof(hugeOcspValue)); + const SECItem hugeOcspItems[] = { + {siBuffer, const_cast(hugeOcspValue), sizeof(hugeOcspValue)}}; + const SECItemArray hugeOcspResponses = {const_cast(hugeOcspItems), + PR_ARRAY_SIZE(hugeOcspItems)}; + const SSLExtraServerCertData hugeOcspExtraData = { + ssl_auth_null, nullptr, &hugeOcspResponses, nullptr}; + + // The value should be available during the AuthCertificateCallback + client_->SetAuthCertificateCallback([&](TlsAgent* agent, bool checksig, + bool isServer) -> SECStatus { + const SECItemArray* ocsp = SSL_PeerStapledOCSPResponses(agent->ssl_fd()); + if (!ocsp) { + return SECFailure; + } + EXPECT_EQ(1U, ocsp->len) << "We only provide the first item"; + EXPECT_EQ(0, SECITEM_CompareItem(&hugeOcspItems[0], &ocsp->items[0])); + return SECSuccess; + }); + EXPECT_TRUE(server_->ConfigServerCert(TlsAgent::kServerRsa, true, + &hugeOcspExtraData)); + + Connect(); +} + } // namespace nspr_test diff --git a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc index 391b4c42234d5..93c1b85f3aff0 100644 --- a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc +++ b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc @@ -258,12 +258,15 @@ TEST_P(TlsCipherSuiteTest, ReadLimit) { // authentication tag. static const uint8_t payload[18] = {6}; DataBuffer record; - uint64_t epoch = 0; + uint64_t epoch; if (mode_ == DGRAM) { - epoch++; if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) { - epoch++; + epoch = 3; // Application traffic keys. + } else { + epoch = 1; } + } else { + epoch = 0; } TlsAgentTestBase::MakeRecord(mode_, kTlsApplicationDataType, version_, payload, sizeof(payload), &record, diff --git a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc index 8c96e09939d93..9b8d9fa46f3bb 100644 --- a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc +++ b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc @@ -201,6 +201,63 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicketForget) { SendReceive(); } +TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtClient) { + SSLInt_SetTicketLifetime(1); // one second + // This causes a ticket resumption. + ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); + Connect(); + SendReceive(); + + WAIT_(false, 1000); + + Reset(); + ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); + ExpectResumption(RESUME_NONE); + + // TLS 1.3 uses the pre-shared key extension instead. + SSLExtensionType xtn = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) + ? ssl_tls13_pre_shared_key_xtn + : ssl_session_ticket_xtn; + auto capture = std::make_shared(xtn); + client_->SetPacketFilter(capture); + Connect(); + + if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { + EXPECT_FALSE(capture->captured()); + } else { + EXPECT_TRUE(capture->captured()); + EXPECT_EQ(0U, capture->extension().len()); + } +} + +TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) { + SSLInt_SetTicketLifetime(1); // one second + // This causes a ticket resumption. + ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); + Connect(); + SendReceive(); + + Reset(); + ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); + ExpectResumption(RESUME_NONE); + + SSLExtensionType xtn = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) + ? ssl_tls13_pre_shared_key_xtn + : ssl_session_ticket_xtn; + auto capture = std::make_shared(xtn); + client_->SetPacketFilter(capture); + client_->StartConnect(); + server_->StartConnect(); + client_->Handshake(); + EXPECT_TRUE(capture->captured()); + EXPECT_LT(0U, capture->extension().len()); + + WAIT_(false, 1000); // Let the ticket expire on the server. + + Handshake(); + CheckConnected(); +} + // This callback switches out the "server" cert used on the server with // the "client" certificate, which should be the same type. static int32_t SwitchCertificates(TlsAgent* agent, const SECItem* srvNameArr, diff --git a/security/nss/gtests/ssl_gtest/tls_connect.cc b/security/nss/gtests/ssl_gtest/tls_connect.cc index f6269a0af1cca..b4317e0f76294 100644 --- a/security/nss/gtests/ssl_gtest/tls_connect.cc +++ b/security/nss/gtests/ssl_gtest/tls_connect.cc @@ -174,6 +174,7 @@ void TlsConnectTestBase::ClearServerCache() { void TlsConnectTestBase::SetUp() { SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str()); SSLInt_ClearSessionTicketKey(); + SSLInt_SetTicketLifetime(10); ClearStats(); Init(); } diff --git a/security/nss/lib/base/error.c b/security/nss/lib/base/error.c index ea1d5e3e8ddec..95a76cf79968a 100644 --- a/security/nss/lib/base/error.c +++ b/security/nss/lib/base/error.c @@ -55,6 +55,7 @@ static PRUintn error_stack_index = INVALID_TPD_INDEX; */ static PRCallOnceType error_call_once; +static const PRCallOnceType error_call_again; /* * error_once_function @@ -264,6 +265,8 @@ nss_DestroyErrorStack(void) { if (INVALID_TPD_INDEX != error_stack_index) { PR_SetThreadPrivate(error_stack_index, NULL); + error_stack_index = INVALID_TPD_INDEX; + error_call_once = error_call_again; /* allow to init again */ } return; } diff --git a/security/nss/lib/cryptohi/keyi.h b/security/nss/lib/cryptohi/keyi.h index 374a4ad9bf6ff..f8f5f7f7dae82 100644 --- a/security/nss/lib/cryptohi/keyi.h +++ b/security/nss/lib/cryptohi/keyi.h @@ -17,13 +17,6 @@ KeyType seckey_GetKeyType(SECOidTag pubKeyOid); SECStatus sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg); -/* - * Set the point encoding of a SECKEYPublicKey from the OID. - * This has to be called on any SECKEYPublicKey holding a SECKEYECPublicKey - * before it can be used. The encoding is used to dermine the public key size. - */ -SECStatus seckey_SetPointEncoding(PLArenaPool *arena, SECKEYPublicKey *pubKey); - SEC_END_PROTOS #endif /* _KEYHI_H_ */ diff --git a/security/nss/lib/cryptohi/keythi.h b/security/nss/lib/cryptohi/keythi.h index 1555ce2e27639..36896540f2c1a 100644 --- a/security/nss/lib/cryptohi/keythi.h +++ b/security/nss/lib/cryptohi/keythi.h @@ -125,9 +125,9 @@ typedef SECItem SECKEYECParams; struct SECKEYECPublicKeyStr { SECKEYECParams DEREncodedParams; - int size; /* size in bits */ - SECItem publicValue; /* encoded point */ - ECPointEncoding encoding; + int size; /* size in bits */ + SECItem publicValue; /* encoded point */ + ECPointEncoding encoding; /* deprecated, ignored */ }; typedef struct SECKEYECPublicKeyStr SECKEYECPublicKey; diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c index df976f46c74c1..9ea48b7677ec0 100644 --- a/security/nss/lib/cryptohi/seckey.c +++ b/security/nss/lib/cryptohi/seckey.c @@ -547,6 +547,23 @@ CERT_GetCertKeyType(const CERTSubjectPublicKeyInfo *spki) return seckey_GetKeyType(SECOID_GetAlgorithmTag(&spki->algorithm)); } +/* Ensure pubKey contains an OID */ +static SECStatus +seckey_HasCurveOID(const SECKEYPublicKey *pubKey) +{ + SECItem oid; + SECStatus rv; + PORTCheapArenaPool tmpArena; + + PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); + /* If we can decode it, an OID is available. */ + rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &oid, + SEC_ASN1_GET(SEC_ObjectIDTemplate), + &pubKey->u.ec.DEREncodedParams); + PORT_DestroyCheapArena(&tmpArena); + return rv; +} + static SECKEYPublicKey * seckey_ExtractPublicKey(const CERTSubjectPublicKeyInfo *spki) { @@ -639,7 +656,8 @@ seckey_ExtractPublicKey(const CERTSubjectPublicKeyInfo *spki) if (rv != SECSuccess) { break; } - rv = seckey_SetPointEncoding(arena, pubk); + pubk->u.ec.encoding = ECPoint_Undefined; + rv = seckey_HasCurveOID(pubk); if (rv == SECSuccess) { return pubk; } @@ -1162,16 +1180,16 @@ SECKEY_CopyPublicKey(const SECKEYPublicKey *pubk) break; case ecKey: copyk->u.ec.size = pubk->u.ec.size; - rv = SECITEM_CopyItem(arena, ©k->u.ec.DEREncodedParams, - &pubk->u.ec.DEREncodedParams); + rv = seckey_HasCurveOID(pubk); if (rv != SECSuccess) { break; } - rv = seckey_SetPointEncoding(arena, copyk); + rv = SECITEM_CopyItem(arena, ©k->u.ec.DEREncodedParams, + &pubk->u.ec.DEREncodedParams); if (rv != SECSuccess) { break; } - PORT_Assert(copyk->u.ec.encoding == pubk->u.ec.encoding); + copyk->u.ec.encoding = ECPoint_Undefined; rv = SECITEM_CopyItem(arena, ©k->u.ec.publicValue, &pubk->u.ec.publicValue); break; @@ -1253,10 +1271,7 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) if (rv != SECSuccess || pubk->u.ec.publicValue.len == 0) { break; } - rv = seckey_SetPointEncoding(arena, pubk); - if (rv != SECSuccess) { - break; - } + pubk->u.ec.encoding = ECPoint_Undefined; return pubk; default: break; @@ -1959,39 +1974,3 @@ SECKEY_GetECCOid(const SECKEYECParams *params) return oidData->offset; } - -/* Set curve encoding in SECKEYECPublicKey in pubKey from OID. - * If the encoding is not set, determining the key size of EC public keys will - * fail. - */ -SECStatus -seckey_SetPointEncoding(PLArenaPool *arena, SECKEYPublicKey *pubKey) -{ - SECItem oid; - SECOidTag tag; - SECStatus rv; - - /* decode the OID tag */ - rv = SEC_QuickDERDecodeItem(arena, &oid, SEC_ASN1_GET(SEC_ObjectIDTemplate), - &pubKey->u.ec.DEREncodedParams); - if (rv != SECSuccess) { - return SECFailure; - } - - tag = SECOID_FindOIDTag(&oid); - switch (tag) { - case SEC_OID_CURVE25519: - pubKey->u.ec.encoding = ECPoint_XOnly; - break; - case SEC_OID_SECG_EC_SECP256R1: - /* fall through */ - case SEC_OID_SECG_EC_SECP384R1: - /* fall through */ - case SEC_OID_SECG_EC_SECP521R1: - /* fall through */ - default: - /* unknown curve, default to uncompressed */ - pubKey->u.ec.encoding = ECPoint_Uncompressed; - } - return SECSuccess; -} diff --git a/security/nss/lib/freebl/blapi.h b/security/nss/lib/freebl/blapi.h index 38c3a9ff5c74f..a7a8aa99337e0 100644 --- a/security/nss/lib/freebl/blapi.h +++ b/security/nss/lib/freebl/blapi.h @@ -1599,7 +1599,6 @@ extern const SECHashObject *HASH_GetRawHashObject(HASH_HashType hashType); extern void BL_SetForkState(PRBool forked); -#ifndef NSS_DISABLE_ECC /* ** pepare an ECParam structure from DEREncoded params */ @@ -1609,7 +1608,11 @@ extern SECStatus EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams); extern SECStatus EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, const ECParams *srcParams); -#endif + +/* + * use the internal table to get the size in bytes of a single EC point + */ +extern int EC_GetPointSize(const ECParams *params); SEC_END_PROTOS diff --git a/security/nss/lib/freebl/blapit.h b/security/nss/lib/freebl/blapit.h index 7cf8fc6a0a516..2a17b5f469c34 100644 --- a/security/nss/lib/freebl/blapit.h +++ b/security/nss/lib/freebl/blapit.h @@ -377,7 +377,6 @@ struct ECParamsStr { SECItem DEREncoding; ECCurveName name; SECItem curveOID; - int pointSize; }; typedef struct ECParamsStr ECParams; diff --git a/security/nss/lib/freebl/drbg.c b/security/nss/lib/freebl/drbg.c index 9c3f76a4663fa..a55e91ce29604 100644 --- a/security/nss/lib/freebl/drbg.c +++ b/security/nss/lib/freebl/drbg.c @@ -398,7 +398,7 @@ static PRStatus rng_init(void) { PRUint8 bytes[PRNG_SEEDLEN * 2]; /* entropy + nonce */ -#ifndef UNSAFE_FUZZER_MODE +#ifndef UNSAFE_RNG_NO_URANDOM_SEED unsigned int numBytes; SECStatus rv = SECSuccess; #endif @@ -418,7 +418,7 @@ rng_init(void) return PR_FAILURE; } -#ifndef UNSAFE_FUZZER_MODE +#ifndef UNSAFE_RNG_NO_URANDOM_SEED /* Try to get some seed data for the RNG */ numBytes = (unsigned int)RNG_SystemRNG(bytes, sizeof bytes); PORT_Assert(numBytes == 0 || numBytes == sizeof bytes); diff --git a/security/nss/lib/freebl/ec.c b/security/nss/lib/freebl/ec.c index 2abf48257b551..669c9b147c2c2 100644 --- a/security/nss/lib/freebl/ec.c +++ b/security/nss/lib/freebl/ec.c @@ -233,7 +233,6 @@ ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, key->ecParams.type = ecParams->type; key->ecParams.fieldID.size = ecParams->fieldID.size; key->ecParams.fieldID.type = ecParams->fieldID.type; - key->ecParams.pointSize = ecParams->pointSize; if (ecParams->fieldID.type == ec_field_GFp || ecParams->fieldID.type == ec_field_plain) { CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime, @@ -262,7 +261,7 @@ ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID, &ecParams->curveOID)); - SECITEM_AllocItem(arena, &key->publicValue, ecParams->pointSize); + SECITEM_AllocItem(arena, &key->publicValue, EC_GetPointSize(ecParams)); len = ecParams->order.len; SECITEM_AllocItem(arena, &key->privateValue, len); @@ -579,7 +578,7 @@ ECDH_Derive(SECItem *publicValue, if (ecParams->fieldID.type == ec_field_plain) { const ECMethod *method; memset(derivedSecret, 0, sizeof(*derivedSecret)); - derivedSecret = SECITEM_AllocItem(NULL, derivedSecret, ecParams->pointSize); + derivedSecret = SECITEM_AllocItem(NULL, derivedSecret, EC_GetPointSize(ecParams)); if (derivedSecret == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; @@ -605,8 +604,8 @@ ECDH_Derive(SECItem *publicValue, MP_DIGITS(&k) = 0; memset(derivedSecret, 0, sizeof *derivedSecret); len = (ecParams->fieldID.size + 7) >> 3; - pointQ.len = ecParams->pointSize; - if ((pointQ.data = PORT_Alloc(ecParams->pointSize)) == NULL) + pointQ.len = EC_GetPointSize(ecParams); + if ((pointQ.data = PORT_Alloc(pointQ.len)) == NULL) goto cleanup; CHECK_MPI_OK(mp_init(&k)); @@ -653,7 +652,7 @@ ECDH_Derive(SECItem *publicValue, } if (pointQ.data) { - PORT_ZFree(pointQ.data, ecParams->pointSize); + PORT_ZFree(pointQ.data, pointQ.len); } #else PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); @@ -768,8 +767,8 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, ** ** Compute kG */ - kGpoint.len = ecParams->pointSize; - kGpoint.data = PORT_Alloc(ecParams->pointSize); + kGpoint.len = EC_GetPointSize(ecParams); + kGpoint.data = PORT_Alloc(kGpoint.len); if ((kGpoint.data == NULL) || (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint) != SECSuccess)) goto cleanup; @@ -888,7 +887,7 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, } if (kGpoint.data) { - PORT_ZFree(kGpoint.data, ecParams->pointSize); + PORT_ZFree(kGpoint.data, kGpoint.len); } if (err) { @@ -1011,7 +1010,7 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, * The incoming point has been verified in sftk_handlePublicKeyObject. */ - SECITEM_AllocItem(NULL, &pointC, ecParams->pointSize); + SECITEM_AllocItem(NULL, &pointC, EC_GetPointSize(ecParams)); if (pointC.data == NULL) { goto cleanup; } diff --git a/security/nss/lib/freebl/ecdecode.c b/security/nss/lib/freebl/ecdecode.c index eda3f0c2af053..e1f1eb8a5552e 100644 --- a/security/nss/lib/freebl/ecdecode.c +++ b/security/nss/lib/freebl/ecdecode.c @@ -85,7 +85,6 @@ EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, dstParams->type = srcParams->type; dstParams->fieldID.size = srcParams->fieldID.size; dstParams->fieldID.type = srcParams->fieldID.type; - dstParams->pointSize = srcParams->pointSize; if (srcParams->fieldID.type == ec_field_GFp || srcParams->fieldID.type == ec_field_plain) { CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.prime, @@ -135,7 +134,6 @@ gf_populate_params(ECCurveName name, ECFieldType field_type, ECParams *params) CHECK_OK(curveParams); params->fieldID.size = curveParams->size; params->fieldID.type = field_type; - params->pointSize = curveParams->pointSize; if (field_type == ec_field_GFp || field_type == ec_field_plain) { CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, @@ -294,4 +292,20 @@ EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams) } } +int +EC_GetPointSize(const ECParams *params) +{ + ECCurveName name = params->name; + const ECCurveParams *curveParams; + + if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve) || + ((curveParams = ecCurve_map[name]) == NULL)) { + /* unknown curve, calculate point size from params. assume standard curves with 2 points + * and a point compression indicator byte */ + int sizeInBytes = (params->fieldID.size + 7) / 8; + return sizeInBytes * 2 + 1; + } + return curveParams->pointSize; +} + #endif /* NSS_DISABLE_ECC */ diff --git a/security/nss/lib/freebl/ecl/ecp_25519.c b/security/nss/lib/freebl/ecl/ecp_25519.c index a8d41520eb2c0..1e7875fff2c93 100644 --- a/security/nss/lib/freebl/ecl/ecp_25519.c +++ b/security/nss/lib/freebl/ecl/ecp_25519.c @@ -79,8 +79,7 @@ ec_Curve25519_pt_validate(const SECItem *px) 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }; - /* The point must not be longer than 32 (it can be smaller). */ - if (px->len <= 32) { + if (px->len == 32) { p = px->data; } else { return SECFailure; diff --git a/security/nss/lib/freebl/ecl/uint128.c b/security/nss/lib/freebl/ecl/uint128.c index 22cbd023c1b29..5465875adef9c 100644 --- a/security/nss/lib/freebl/ecl/uint128.c +++ b/security/nss/lib/freebl/ecl/uint128.c @@ -31,6 +31,9 @@ init128x(uint64_t x) return ret; } +#define CONSTANT_TIME_CARRY(a, b) \ + ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1)) + /* arithmetic */ uint128_t @@ -38,7 +41,7 @@ add128(uint128_t a, uint128_t b) { uint128_t ret; ret.lo = a.lo + b.lo; - ret.hi = a.hi + b.hi + (ret.lo < b.lo); + ret.hi = a.hi + b.hi + CONSTANT_TIME_CARRY(ret.lo, b.lo); return ret; } diff --git a/security/nss/lib/freebl/freebl_base.gypi b/security/nss/lib/freebl/freebl_base.gypi index a2cf809ad5b10..7570eec88633d 100644 --- a/security/nss/lib/freebl/freebl_base.gypi +++ b/security/nss/lib/freebl/freebl_base.gypi @@ -159,6 +159,11 @@ }], ], }], + [ 'fuzz_oss==1', { + 'defines': [ + 'UNSAFE_RNG_NO_URANDOM_SEED', + ], + }], [ 'fuzz_tls==1', { 'sources': [ 'det_rng.c', diff --git a/security/nss/lib/freebl/ldvector.c b/security/nss/lib/freebl/ldvector.c index fb986a6dd15e8..2447a0c9f540b 100644 --- a/security/nss/lib/freebl/ldvector.c +++ b/security/nss/lib/freebl/ldvector.c @@ -294,9 +294,13 @@ static const struct FREEBLVectorStr vector = ChaCha20Poly1305_CreateContext, ChaCha20Poly1305_DestroyContext, ChaCha20Poly1305_Seal, - ChaCha20Poly1305_Open + ChaCha20Poly1305_Open, /* End of Version 3.018 */ + + EC_GetPointSize + + /* End of Version 3.019 */ }; const FREEBLVector* diff --git a/security/nss/lib/freebl/loader.c b/security/nss/lib/freebl/loader.c index 84876c12cb450..792171b086765 100644 --- a/security/nss/lib/freebl/loader.c +++ b/security/nss/lib/freebl/loader.c @@ -2116,3 +2116,11 @@ ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, ctx, output, outputLen, maxOutputLen, input, inputLen, nonce, nonceLen, ad, adLen); } + +int +EC_GetPointSize(const ECParams *params) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_EC_GetPointSize)(params); +} diff --git a/security/nss/lib/freebl/loader.h b/security/nss/lib/freebl/loader.h index ced03b5ca649d..ed392cc47eb28 100644 --- a/security/nss/lib/freebl/loader.h +++ b/security/nss/lib/freebl/loader.h @@ -10,7 +10,7 @@ #include "blapi.h" -#define FREEBL_VERSION 0x0312 +#define FREEBL_VERSION 0x0313 struct FREEBLVectorStr { @@ -732,6 +732,10 @@ struct FREEBLVectorStr { /* Version 3.018 came to here */ + int (*p_EC_GetPointSize)(const ECParams *); + + /* Version 3.019 came to here */ + /* Add new function pointers at the end of this struct and bump * FREEBL_VERSION at the beginning of this file. */ }; diff --git a/security/nss/lib/freebl/mpi/README b/security/nss/lib/freebl/mpi/README index 475549bade833..f1c66dff138bd 100644 --- a/security/nss/lib/freebl/mpi/README +++ b/security/nss/lib/freebl/mpi/README @@ -503,9 +503,6 @@ MP_MODARITH - Define true to include the modular arithmetic in your application, you can set this to zero to leave out all the modular routines. -MP_NUMTH - Define true to include number theoretic functions - such as mp_gcd(), mp_lcm(), and mp_invmod(). - MP_LOGTAB - If true, the file "logtab.h" is included, which is basically a static table of base 2 logarithms. These are used to compute how big the buffers for diff --git a/security/nss/lib/freebl/mpi/mpi-config.h b/security/nss/lib/freebl/mpi/mpi-config.h index f365592a428b7..c6f72b206f158 100644 --- a/security/nss/lib/freebl/mpi/mpi-config.h +++ b/security/nss/lib/freebl/mpi/mpi-config.h @@ -24,10 +24,6 @@ #define MP_MODARITH 1 /* include modular arithmetic ? */ #endif -#ifndef MP_NUMTH -#define MP_NUMTH 1 /* include number theoretic functions? */ -#endif - #ifndef MP_LOGTAB #define MP_LOGTAB 1 /* use table of logs instead of log()? */ #endif diff --git a/security/nss/lib/freebl/mpi/mpi.c b/security/nss/lib/freebl/mpi/mpi.c index f6f75439c1a95..e4b26453f2e0e 100644 --- a/security/nss/lib/freebl/mpi/mpi.c +++ b/security/nss/lib/freebl/mpi/mpi.c @@ -1695,7 +1695,6 @@ mp_iseven(const mp_int *a) /*------------------------------------------------------------------------*/ /* {{{ Number theoretic functions */ -#if MP_NUMTH /* {{{ mp_gcd(a, b, c) */ /* @@ -2376,7 +2375,6 @@ mp_invmod(const mp_int *a, const mp_int *m, mp_int *c) } /* end mp_invmod() */ /* }}} */ -#endif /* if MP_NUMTH */ /* }}} */ diff --git a/security/nss/lib/freebl/mpi/mpi.h b/security/nss/lib/freebl/mpi/mpi.h index 64ffe75d52433..97af0f069b70d 100644 --- a/security/nss/lib/freebl/mpi/mpi.h +++ b/security/nss/lib/freebl/mpi/mpi.h @@ -225,13 +225,11 @@ int mp_isodd(const mp_int *a); int mp_iseven(const mp_int *a); /* Number theoretic */ -#if MP_NUMTH mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c); mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c); mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y); mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c); mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c); -#endif /* end MP_NUMTH */ /* Input and output */ #if MP_IOFUNC diff --git a/security/nss/lib/freebl/mpi/mpprime.h b/security/nss/lib/freebl/mpi/mpprime.h index c47c618360ead..885bccd4b4858 100644 --- a/security/nss/lib/freebl/mpi/mpprime.h +++ b/security/nss/lib/freebl/mpi/mpprime.h @@ -13,6 +13,8 @@ #include "mpi.h" +SEC_BEGIN_PROTOS + extern const int prime_tab_size; /* number of primes available */ extern const mp_digit prime_tab[]; @@ -35,4 +37,6 @@ mp_err mpp_sieve(mp_int *trial, const mp_digit *primes, mp_size nPrimes, mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong, unsigned long *nTries); +SEC_END_PROTOS + #endif /* end _H_MP_PRIME_ */ diff --git a/security/nss/lib/pk11wrap/pk11akey.c b/security/nss/lib/pk11wrap/pk11akey.c index d086ed4e17e16..01d1d7fd99b3a 100644 --- a/security/nss/lib/pk11wrap/pk11akey.c +++ b/security/nss/lib/pk11wrap/pk11akey.c @@ -765,12 +765,10 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType, CK_OBJECT_HANDLE id) &pubKey->u.ec.DEREncodedParams); if (crv != CKR_OK) break; + pubKey->u.ec.encoding = ECPoint_Undefined; crv = pk11_get_Decoded_ECPoint(arena, &pubKey->u.ec.DEREncodedParams, value, &pubKey->u.ec.publicValue); - if (seckey_SetPointEncoding(arena, pubKey) != SECSuccess) { - crv |= CKR_GENERAL_ERROR; - } break; case fortezzaKey: case nullKey: diff --git a/security/nss/lib/pk11wrap/pk11skey.c b/security/nss/lib/pk11wrap/pk11skey.c index 850ec026b8658..e6301388e1d1c 100644 --- a/security/nss/lib/pk11wrap/pk11skey.c +++ b/security/nss/lib/pk11wrap/pk11skey.c @@ -2037,6 +2037,40 @@ PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, return NULL; } +/* Test for curves that are known to use a special encoding. + * Extend this function when additional curves are added. */ +static ECPointEncoding +pk11_ECGetPubkeyEncoding(const SECKEYPublicKey *pubKey) +{ + SECItem oid; + SECStatus rv; + PORTCheapArenaPool tmpArena; + ECPointEncoding encoding = ECPoint_Undefined; + + PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); + + /* decode the OID tag */ + rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &oid, + SEC_ASN1_GET(SEC_ObjectIDTemplate), + &pubKey->u.ec.DEREncodedParams); + if (rv == SECSuccess) { + SECOidTag tag = SECOID_FindOIDTag(&oid); + switch (tag) { + case SEC_OID_CURVE25519: + encoding = ECPoint_XOnly; + break; + case SEC_OID_SECG_EC_SECP256R1: + case SEC_OID_SECG_EC_SECP384R1: + case SEC_OID_SECG_EC_SECP521R1: + default: + /* unknown curve, default to uncompressed */ + encoding = ECPoint_Uncompressed; + } + } + PORT_DestroyCheapArena(&tmpArena); + return encoding; +} + /* Returns the size of the public key, or 0 if there * is an error. */ static CK_ULONG @@ -2044,10 +2078,11 @@ pk11_ECPubKeySize(SECKEYPublicKey *pubKey) { SECItem *publicValue = &pubKey->u.ec.publicValue; - if (pubKey->u.ec.encoding == ECPoint_XOnly) { + ECPointEncoding encoding = pk11_ECGetPubkeyEncoding(pubKey); + if (encoding == ECPoint_XOnly) { return publicValue->len; } - if (publicValue->data[0] == 0x04) { + if (encoding == ECPoint_Uncompressed) { /* key encoded in uncompressed form */ return ((publicValue->len - 1) / 2); } diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index 6148790f0800f..1e091589cffe5 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.c @@ -1799,7 +1799,7 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type, crv = sftk_Attribute2SSecItem(arena, &pubKey->u.ec.publicValue, object, CKA_EC_POINT); if (crv == CKR_OK) { - unsigned int keyLen = pubKey->u.ec.ecParams.pointSize; + unsigned int keyLen = EC_GetPointSize(&pubKey->u.ec.ecParams); /* special note: We can't just use the first byte to distinguish * between EC_POINT_FORM_UNCOMPRESSED and SEC_ASN1_OCTET_STRING. diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index e6e93752bf262..9f2024060983a 100644 --- a/security/nss/lib/softoken/pkcs11c.c +++ b/security/nss/lib/softoken/pkcs11c.c @@ -7240,14 +7240,9 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, ecPoint.data = mechParams->pPublicData; ecPoint.len = mechParams->ulPublicDataLen; - pubKeyLen = privKey->u.ec.ecParams.pointSize; + pubKeyLen = EC_GetPointSize(&privKey->u.ec.ecParams); - /* if the len is too small, can't be a valid point */ - if (ecPoint.len < pubKeyLen) { - goto ec_loser; - } - /* if the len is too large, must be an encoded point (length is - * equal case just falls through */ + /* if the len is too large, might be an encoded point */ if (ecPoint.len > pubKeyLen) { SECItem newPoint; diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index ea8fa77b69f80..11150a1dfc56d 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -2694,6 +2694,7 @@ ssl3_SendRecord(sslSocket *ss, SECStatus rv; PRInt32 totalSent = 0; PRBool capRecordVersion; + ssl3CipherSpec *spec; SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), @@ -2798,11 +2799,12 @@ ssl3_SendRecord(sslSocket *ss, PORT_Assert(IS_DTLS(ss) && (type == content_handshake || type == content_change_cipher_spec)); + spec = cwSpec; } else { - cwSpec = ss->ssl3.cwSpec; + spec = ss->ssl3.cwSpec; } - rv = ssl_ProtectRecord(ss, cwSpec, !IS_DTLS(ss) && capRecordVersion, + rv = ssl_ProtectRecord(ss, spec, !IS_DTLS(ss) && capRecordVersion, type, pIn, contentLen, wrBuf); if (rv == SECSuccess) { PRINT_BUF(50, (ss, "send (encrypted) record data:", @@ -3069,7 +3071,9 @@ ssl3_HandleNoCertificate(sslSocket *ss) (ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) { PRFileDesc *lower; - ss->sec.uncache(ss->sec.ci.sid); + if (!ss->opt.noCache) { + ss->sec.uncache(ss->sec.ci.sid); + } SSL3_SendAlert(ss, alert_fatal, bad_certificate); lower = ss->fd->lower; @@ -10277,7 +10281,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) goto loser; /* This is a fixed value. */ - rv = ssl3_AppendHandshakeNumber(ss, TLS_EX_SESS_TICKET_LIFETIME_HINT, 4); + rv = ssl3_AppendHandshakeNumber(ss, ssl_ticket_lifetime, 4); if (rv != SECSuccess) goto loser; diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c index 96aa55dad76bc..418629aa64e3a 100644 --- a/security/nss/lib/ssl/ssl3ecc.c +++ b/security/nss/lib/ssl/ssl3ecc.c @@ -303,7 +303,7 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, serverKeyPair->pubKey->u.ec.DEREncodedParams.len; clntPubKey.u.ec.DEREncodedParams.data = serverKeyPair->pubKey->u.ec.DEREncodedParams.data; - clntPubKey.u.ec.encoding = serverKeyPair->pubKey->u.ec.encoding; + clntPubKey.u.ec.encoding = ECPoint_Undefined; rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, 1, &b, &length); @@ -387,11 +387,7 @@ ssl_ImportECDHKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey, ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE); return SECFailure; } - if (ecGroup->name == ssl_grp_ec_curve25519) { - peerKey->u.ec.encoding = ECPoint_XOnly; - } else { - peerKey->u.ec.encoding = ECPoint_Uncompressed; - } + peerKey->u.ec.encoding = ECPoint_Undefined; /* copy publicValue in peerKey */ ecPoint.data = b; diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c index bdb0cbea62aca..04c8182cc299d 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/lib/ssl/ssl3exthandle.c @@ -850,6 +850,9 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } +PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */ +#define TLS_EX_SESS_TICKET_VERSION (0x0103) + /* * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket */ @@ -1567,8 +1570,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) * memory since the ticket is of no use. */ if (parsed_session_ticket->timestamp != 0 && - parsed_session_ticket->timestamp + - TLS_EX_SESS_TICKET_LIFETIME_HINT > + parsed_session_ticket->timestamp + ssl_ticket_lifetime > ssl_Time()) { sid = ssl3_NewSessionID(ss, PR_TRUE); @@ -1623,6 +1625,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); } sid->u.ssl3.srvName = parsed_session_ticket->srvName; + parsed_session_ticket->srvName.data = NULL; } if (parsed_session_ticket->alpnSelection.data != NULL) { sid->u.ssl3.alpnSelection = parsed_session_ticket->alpnSelection; @@ -1662,6 +1665,9 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) if (parsed_session_ticket->alpnSelection.data) { SECITEM_FreeItem(&parsed_session_ticket->alpnSelection, PR_FALSE); } + if (parsed_session_ticket->srvName.data) { + SECITEM_FreeItem(&parsed_session_ticket->srvName, PR_FALSE); + } PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket)); } diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index bf7f86422f9f8..e2997eff4c6b6 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -870,7 +870,6 @@ typedef struct SSL3HandshakeStateStr { TLS13CertificateRequest *certificateRequest; PRCList cipherSpecs; /* The cipher specs in the sequence they * will be applied. */ - ssl3CipherSpec *nullSpec; /* In case 0-RTT is rejected. */ sslZeroRttState zeroRttState; /* Are we doing a 0-RTT handshake? */ sslZeroRttIgnore zeroRttIgnore; /* Are we ignoring 0-RTT? */ ssl3CipherSuite zeroRttSuite; /* The cipher suite we used for 0-RTT. */ @@ -1222,16 +1221,12 @@ struct sslSocketStr { SSLProtocolVariant protocolVariant; }; -/* All the global data items declared here should be protected using the -** ssl_global_data_lock, which is a reader/writer lock. -*/ -extern NSSRWLock *ssl_global_data_lock; extern char ssl_debug; extern char ssl_trace; extern FILE *ssl_trace_iob; extern FILE *ssl_keylog_iob; -extern PRUint32 ssl_sid_timeout; extern PRUint32 ssl3_sid_timeout; +extern PRUint32 ssl_ticket_lifetime; extern const char *const ssl3_cipherName[]; @@ -1699,10 +1694,6 @@ SECStatus ssl_GetSessionTicketKeys(sslSocket *ss, unsigned char *keyName, PK11SymKey **encKey, PK11SymKey **macKey); void ssl_ResetSessionTicketKeys(); -/* Tell clients to consider tickets valid for this long. */ -#define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */ -#define TLS_EX_SESS_TICKET_VERSION (0x0103) - extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length); diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c index 616901300ca12..7ad1c6bc7a837 100644 --- a/security/nss/lib/ssl/sslnonce.c +++ b/security/nss/lib/ssl/sslnonce.c @@ -19,7 +19,6 @@ #include #endif -PRUint32 ssl_sid_timeout = 100; PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */ static sslSessionID *cache = NULL; @@ -471,7 +470,7 @@ ssl_TicketTimeValid(const NewSessionTicket *ticket) } endTime = ticket->received_timestamp + - (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_MSEC); + (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC); return endTime > PR_Now(); } diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c index bd9858296b1f1..edbb29fb0ac60 100644 --- a/security/nss/lib/ssl/tls13con.c +++ b/security/nss/lib/ssl/tls13con.c @@ -22,9 +22,10 @@ #include "tls13exthandle.h" typedef enum { - TrafficKeyEarlyApplicationData, - TrafficKeyHandshake, - TrafficKeyApplicationData + TrafficKeyClearText = 0, + TrafficKeyEarlyApplicationData = 1, + TrafficKeyHandshake = 2, + TrafficKeyApplicationData = 3 } TrafficKeyType; typedef enum { @@ -76,7 +77,6 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, const char *suffix, const SSL3Hashes *hashes, PK11SymKey **dest); -static void tls13_SetNullCipherSpec(sslSocket *ss, ssl3CipherSpec **specp); static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss); static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey); static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, @@ -1268,16 +1268,6 @@ tls13_HandleClientHelloPart2(sslSocket *ss, if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) { ss->ssl3.hs.zeroRttState = ssl_0rtt_sent; - - if (IS_DTLS(ss)) { - /* Save the null spec, which we should be currently reading. We will - * use this when 0-RTT sending is over. */ - ssl_GetSpecReadLock(ss); - ss->ssl3.hs.nullSpec = ss->ssl3.crSpec; - tls13_CipherSpecAddRef(ss->ssl3.hs.nullSpec); - PORT_Assert(ss->ssl3.hs.nullSpec->cipher_def->cipher == cipher_null); - ssl_ReleaseSpecReadLock(ss); - } } #ifndef PARANOID @@ -1726,9 +1716,13 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) { - /* Oh well, back to the start. */ - tls13_SetNullCipherSpec(ss, &ss->ssl3.cwSpec); ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored; + /* Restore the null cipher spec for writing. */ + ssl_GetSpecWriteLock(ss); + tls13_CipherSpecRelease(ss->ssl3.cwSpec); + ss->ssl3.cwSpec = ss->ssl3.crSpec; + PORT_Assert(ss->ssl3.cwSpec->cipher_def->cipher == cipher_null); + ssl_ReleaseSpecWriteLock(ss); } else { PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none); } @@ -2784,7 +2778,7 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, if ((*specp)->epoch == PR_UINT16_MAX) { return SECFailure; } - spec->epoch = (*specp)->epoch + 1; + spec->epoch = (PRUint16)type; if (!IS_DTLS(ss)) { spec->read_seq_num = spec->write_seq_num = 0; @@ -3734,17 +3728,10 @@ tls13_SendClientSecondRound(sslSocket *ss) return SECWouldBlock; } - if (ss->ssl3.hs.zeroRttState != ssl_0rtt_none) { - if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { - rv = tls13_SendEndOfEarlyData(ss); - if (rv != SECSuccess) { - return SECFailure; /* Error code already set. */ - } - } - if (IS_DTLS(ss) && !ss->ssl3.hs.helloRetry) { - /* Reset the counters so that the next epoch isn't set - * incorrectly. */ - tls13_SetNullCipherSpec(ss, &ss->ssl3.cwSpec); + if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { + rv = tls13_SendEndOfEarlyData(ss); + if (rv != SECSuccess) { + return SECFailure; /* Error code already set. */ } } @@ -3821,7 +3808,7 @@ tls13_SendNewSessionTicket(sslSocket *ss) ticket.flags |= ticket_allow_early_data; max_early_data_size_len = 8; /* type + len + value. */ } - ticket.ticket_lifetime_hint = TLS_EX_SESS_TICKET_LIFETIME_HINT; + ticket.ticket_lifetime_hint = ssl_ticket_lifetime; rv = ssl3_EncodeSessionTicket(ss, &ticket, &ticket_data); if (rv != SECSuccess) @@ -3840,7 +3827,7 @@ tls13_SendNewSessionTicket(sslSocket *ss) goto loser; /* This is a fixed value. */ - rv = ssl3_AppendHandshakeNumber(ss, TLS_EX_SESS_TICKET_LIFETIME_HINT, 4); + rv = ssl3_AppendHandshakeNumber(ss, ssl_ticket_lifetime, 4); if (rv != SECSuccess) goto loser; @@ -4335,12 +4322,6 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss) return rv; } - /* Null spec... */ - ssl_GetSpecReadLock(ss); - ss->ssl3.hs.nullSpec = ss->ssl3.cwSpec; - tls13_CipherSpecAddRef(ss->ssl3.hs.nullSpec); - ssl_ReleaseSpecReadLock(ss); - /* Cipher suite already set in tls13_SetupClientHello. */ ss->ssl3.hs.preliminaryInfo = 0; @@ -4383,21 +4364,6 @@ tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len) return len; } -/* 0-RTT data will be followed by a different cipher spec; this resets the - * current spec to the null spec so that the following state can be set as - * though 0-RTT didn't happen. TODO: work out if this is the best plan. */ -static void -tls13_SetNullCipherSpec(sslSocket *ss, ssl3CipherSpec **specp) -{ - PORT_Assert(ss->ssl3.hs.nullSpec); - - ssl_GetSpecWriteLock(ss); - tls13_CipherSpecRelease(*specp); - *specp = ss->ssl3.hs.nullSpec; - ssl_ReleaseSpecWriteLock(ss); - ss->ssl3.hs.nullSpec = NULL; -} - static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss) { @@ -4430,11 +4396,6 @@ tls13_HandleEndOfEarlyData(sslSocket *ss) PORT_Assert(TLS13_IN_HS_STATE(ss, ss->opt.requestCertificate ? wait_client_cert : wait_finished)); - if (IS_DTLS(ss)) { - /* Reset the cipher spec so that the epoch counter is properly reset. */ - tls13_SetNullCipherSpec(ss, &ss->ssl3.crSpec); - } - rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake, CipherSpecRead, PR_FALSE); if (rv != SECSuccess) { diff --git a/security/nss/lib/util/eccutil.h b/security/nss/lib/util/eccutil.h index 0d4caad280030..8c627e18b890e 100644 --- a/security/nss/lib/util/eccutil.h +++ b/security/nss/lib/util/eccutil.h @@ -5,10 +5,11 @@ #ifndef _FREEBL_H_ #define _FREEBL_H_ -/* point encoding type */ +/* deprecated */ typedef enum { ECPoint_Uncompressed, - ECPoint_XOnly + ECPoint_XOnly, + ECPoint_Undefined } ECPointEncoding; #endif /* _FREEBL_H_ */ diff --git a/security/nss/lib/util/secport.h b/security/nss/lib/util/secport.h index 0f4b08f33e96a..fb9ff4ebb569e 100644 --- a/security/nss/lib/util/secport.h +++ b/security/nss/lib/util/secport.h @@ -72,8 +72,8 @@ * and does not use a lock to protect accesses. This makes it cheaper but * less general. It is best used for arena pools that (a) are hot, (b) have * lifetimes bounded within a single function, and (c) don't need locking. - * Use PORT_InitArena() and PORT_DestroyArena() to initialize and finalize - * PORTCheapArenaPools. + * Use PORT_InitCheapArena() and PORT_DestroyCheapArena() to initialize and + * finalize PORTCheapArenaPools. * * All the other PORT_Arena* functions will operate safely with either * subclass. diff --git a/security/nss/tests/bogo/bogo.sh b/security/nss/tests/bogo/bogo.sh index 2b44f24d1dbe5..fc3245a2fbc38 100755 --- a/security/nss/tests/bogo/bogo.sh +++ b/security/nss/tests/bogo/bogo.sh @@ -25,7 +25,7 @@ bogo_init() BORING=${BORING:=boringssl} if [ ! -d "$BORING" ]; then git clone -q https://boringssl.googlesource.com/boringssl "$BORING" - git -C "$BORING" checkout -q ea80f9d5df4c302de391e999395e1c87f9c786b3 + git -C "$BORING" checkout -q 004bff3a1412fcc6ba168d4295a942f9b1e0866e fi SCRIPTNAME="bogo.sh" From 7d8b631cb97b70c2f1ecba8b39988709aae89692 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Tue, 21 Feb 2017 14:24:09 +0100 Subject: [PATCH 17/42] Bug 1341087 - Implement symbol equality comparison in Ion. r=h4writer --- js/src/jit-test/tests/symbol-equality.js | 23 +++++++++++++++++++ js/src/jit/Lowering.cpp | 10 ++++---- js/src/jit/MIR.cpp | 9 +++++++- js/src/jit/MIR.h | 3 +++ js/src/jit/TypePolicy.cpp | 7 ++++-- .../mips-shared/CodeGenerator-mips-shared.cpp | 7 ++++-- .../x86-shared/CodeGenerator-x86-shared.cpp | 2 +- 7 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 js/src/jit-test/tests/symbol-equality.js diff --git a/js/src/jit-test/tests/symbol-equality.js b/js/src/jit-test/tests/symbol-equality.js new file mode 100644 index 0000000000000..7459072d1e62e --- /dev/null +++ b/js/src/jit-test/tests/symbol-equality.js @@ -0,0 +1,23 @@ +setJitCompilerOption("ion.warmup.trigger", 10); + +function simpleEquality() { + for (var i = 0; i < 150; i++) { + var x = Symbol(); + var y = Symbol(); + assertEq(x === y, false); + assertEq(x !== y, true); + assertEq(x == y, false); + assertEq(x != y, true); + } +} + +function equalOperands() { + for (var i = 0; i < 150; i++) { + var x = Symbol(); + assertEq(x === x, true); + assertEq(x !== x, false); + } +} + +equalOperands(); +simpleEquality(); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index b21648972aa36..231ffa7a015f2 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -878,10 +878,11 @@ LIRGenerator::visitTest(MTest* test) return; } - // Compare and branch Int32 or Object pointers. + // Compare and branch Int32, Symbol or Object pointers. if (comp->isInt32Comparison() || comp->compareType() == MCompare::Compare_UInt32 || - comp->compareType() == MCompare::Compare_Object) + comp->compareType() == MCompare::Compare_Object || + comp->compareType() == MCompare::Compare_Symbol) { JSOp op = ReorderComparison(comp->jsop(), &left, &right); LAllocation lhs = useRegister(left); @@ -1123,10 +1124,11 @@ LIRGenerator::visitCompare(MCompare* comp) return; } - // Compare Int32 or Object pointers. + // Compare Int32, Symbol or Object pointers. if (comp->isInt32Comparison() || comp->compareType() == MCompare::Compare_UInt32 || - comp->compareType() == MCompare::Compare_Object) + comp->compareType() == MCompare::Compare_Object || + comp->compareType() == MCompare::Compare_Symbol) { JSOp op = ReorderComparison(comp->jsop(), &left, &right); LAllocation lhs = useRegister(left); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 7bea1e87fefda..139576a2917c3 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -3698,6 +3698,8 @@ MCompare::inputType() case Compare_String: case Compare_StrictString: return MIRType::String; + case Compare_Symbol: + return MIRType::Symbol; case Compare_Object: return MIRType::Object; case Compare_Unknown: @@ -3812,6 +3814,10 @@ MCompare::determineCompareType(JSOp op, MDefinition* left, MDefinition* right) if (!relationalEq && lhs == MIRType::String && rhs == MIRType::String) return Compare_String; + // Handle symbol comparisons. (Relaational compare will throw) + if (!relationalEq && lhs == MIRType::Symbol && rhs == MIRType::Symbol) + return Compare_Symbol; + // Handle strict string compare. if (strictEq && lhs == MIRType::String) return Compare_StrictString; @@ -4412,7 +4418,8 @@ MCompare::tryFoldEqualOperands(bool* result) compareType_ == Compare_Double || compareType_ == Compare_DoubleMaybeCoerceLHS || compareType_ == Compare_DoubleMaybeCoerceRHS || compareType_ == Compare_Float32 || compareType_ == Compare_String || compareType_ == Compare_StrictString || - compareType_ == Compare_Object || compareType_ == Compare_Bitwise); + compareType_ == Compare_Object || compareType_ == Compare_Bitwise || + compareType_ == Compare_Symbol); if (isDoubleComparison() || isFloat32Comparison()) { if (!operandsAreNeverNaN()) diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 799b530122390..1fa698bbb4240 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -4545,6 +4545,9 @@ class MCompare // String compared to String Compare_String, + // Symbol compared to Symbol + Compare_Symbol, + // Undefined compared to String // Null compared to String // Boolean compared to String diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp index ab237d987bea6..5229aec43e846 100644 --- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -206,8 +206,8 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) // Convert all inputs to the right input type MIRType type = compare->inputType(); - MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Double || - type == MIRType::Object || type == MIRType::String || type == MIRType::Float32); + MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Double || type == MIRType::Float32 || + type == MIRType::Object || type == MIRType::String || type == MIRType::Symbol); for (size_t i = 0; i < 2; i++) { MDefinition* in = def->getOperand(i); if (in->type() == type) @@ -251,6 +251,9 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) case MIRType::String: replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Infallible); break; + case MIRType::Symbol: + replace = MUnbox::New(alloc, in, MIRType::Symbol, MUnbox::Infallible); + break; default: MOZ_CRASH("Unknown compare specialization"); } diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index 2df56581f2a61..e0d9b6c0e9923 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -138,7 +138,9 @@ CodeGeneratorMIPSShared::visitCompare(LCompare* comp) const LDefinition* def = comp->getDef(0); #ifdef JS_CODEGEN_MIPS64 - if (mir->compareType() == MCompare::Compare_Object) { + if (mir->compareType() == MCompare::Compare_Object || + mir->compareType() == MCompare::Compare_Symbol) + { if (right->isGeneralReg()) masm.cmpPtrSet(cond, ToRegister(left), ToRegister(right), ToRegister(def)); else @@ -162,7 +164,8 @@ CodeGeneratorMIPSShared::visitCompareAndBranch(LCompareAndBranch* comp) Assembler::Condition cond = JSOpToCondition(mir->compareType(), comp->jsop()); #ifdef JS_CODEGEN_MIPS64 - if (mir->compareType() == MCompare::Compare_Object) { + if (mir->compareType() == MCompare::Compare_Object || + mir->compareType() == MCompare::Compare_Symbol) if (comp->right()->isGeneralReg()) { emitBranch(ToRegister(comp->left()), ToRegister(comp->right()), cond, comp->ifTrue(), comp->ifFalse()); diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index a0da371609b9b..7e650067b9335 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -148,7 +148,7 @@ void CodeGeneratorX86Shared::emitCompare(MCompare::CompareType type, const LAllocation* left, const LAllocation* right) { #ifdef JS_CODEGEN_X64 - if (type == MCompare::Compare_Object) { + if (type == MCompare::Compare_Object || type == MCompare::Compare_Symbol) { masm.cmpPtr(ToRegister(left), ToOperand(right)); return; } From 86f70ff8e0a8aa21d8aec0c0109b19b0b94d5ce1 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Tue, 21 Feb 2017 14:24:10 +0100 Subject: [PATCH 18/42] Bug 1341087 - Implement bitwise symbol equality comparison in Ion. r=h4writer --- js/src/jit-test/tests/symbol-equality.js | 18 ++++++++++++++++++ js/src/jit/IonBuilder.cpp | 17 ++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/js/src/jit-test/tests/symbol-equality.js b/js/src/jit-test/tests/symbol-equality.js index 7459072d1e62e..1b56273a7c098 100644 --- a/js/src/jit-test/tests/symbol-equality.js +++ b/js/src/jit-test/tests/symbol-equality.js @@ -19,5 +19,23 @@ function equalOperands() { } } +function bitwiseCompare() { + var ar = [true, false, Symbol(), null, undefined]; + var s = Symbol(); + ar.push(s); + + for (var i = 0; i < 150; i++) { + for (var j = 0; j < ar.length; j++) { + var equal = (j == ar.indexOf(s)); + + assertEq(ar[j] === s, equal); + assertEq(ar[j] !== s, !equal); + assertEq(ar[j] == s, equal); + assertEq(ar[j] != s, !equal); + } + } +} + equalOperands(); simpleEquality(); +bitwiseCompare(); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 25cb80ae8e036..d2637af2476f3 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -5534,9 +5534,8 @@ IonBuilder::jsop_compare(JSOp op, MDefinition* left, MDefinition* right) static bool ObjectOrSimplePrimitive(MDefinition* op) { - // Return true if op is either undefined/null/boolean/int32 or an object. + // Return true if op is either undefined/null/boolean/int32/symbol or an object. return !op->mightBeType(MIRType::String) - && !op->mightBeType(MIRType::Symbol) && !op->mightBeType(MIRType::Double) && !op->mightBeType(MIRType::Float32) && !op->mightBeType(MIRType::MagicOptimizedArguments) @@ -5595,14 +5594,14 @@ IonBuilder::compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefini // Try to emit a bitwise compare. Check if a bitwise compare equals the wanted // result for all observed operand types. - // Onlye allow loose and strict equality. + // Only allow loose and strict equality. if (op != JSOP_EQ && op != JSOP_NE && op != JSOP_STRICTEQ && op != JSOP_STRICTNE) { trackOptimizationOutcome(TrackedOutcome::RelationalCompare); return Ok(); } // Only primitive (not double/string) or objects are supported. - // I.e. Undefined/Null/Boolean/Int32 and Object + // I.e. Undefined/Null/Boolean/Int32/Symbol and Object if (!ObjectOrSimplePrimitive(left) || !ObjectOrSimplePrimitive(right)) { trackOptimizationOutcome(TrackedOutcome::OperandTypeNotBitwiseComparable); return Ok(); @@ -5638,10 +5637,14 @@ IonBuilder::compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefini return Ok(); } - // For loosy comparison of an object with a Boolean/Number/String + // For loosy comparison of an object with a Boolean/Number/String/Symbol // the valueOf the object is taken. Therefore not supported. - bool simpleLHS = left->mightBeType(MIRType::Boolean) || left->mightBeType(MIRType::Int32); - bool simpleRHS = right->mightBeType(MIRType::Boolean) || right->mightBeType(MIRType::Int32); + bool simpleLHS = left->mightBeType(MIRType::Boolean) || + left->mightBeType(MIRType::Int32) || + left->mightBeType(MIRType::Symbol); + bool simpleRHS = right->mightBeType(MIRType::Boolean) || + right->mightBeType(MIRType::Int32) || + right->mightBeType(MIRType::Symbol); if ((left->mightBeType(MIRType::Object) && simpleRHS) || (right->mightBeType(MIRType::Object) && simpleLHS)) { From 515c0b93e825d386a714c2636ccc4788c75c7ace Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Tue, 21 Feb 2017 14:24:10 +0100 Subject: [PATCH 19/42] Bug 1341087 - Implement symbol equality comparison in SharedIC. r=h4writer --- js/src/jit/MacroAssembler.h | 15 ++++++------- js/src/jit/SharedIC.cpp | 43 +++++++++++++++++++++++++++++++++++++ js/src/jit/SharedIC.h | 24 +++++++++++++++++++++ js/src/jit/SharedICList.h | 1 + 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 2e573fffe6fb3..62664430b53d1 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1603,10 +1603,6 @@ class MacroAssembler : public MacroAssemblerSpecific inline void storeCallResultValue(TypedOrValueRegister dest); - template - Register extractString(const T& source, Register scratch) { - return extractObject(source, scratch); - } using MacroAssemblerSpecific::store32; void store32(const RegisterOrInt32Constant& key, const Address& dest) { if (key.isRegister()) @@ -1698,11 +1694,14 @@ class MacroAssembler : public MacroAssemblerSpecific void checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index, Register temp, Label* failure); - Register extractString(const Address& address, Register scratch) { - return extractObject(address, scratch); + template + Register extractString(const T& source, Register scratch) { + return extractObject(source, scratch); } - Register extractString(const ValueOperand& value, Register scratch) { - return extractObject(value, scratch); + + template + Register extractSymbol(const T& source, Register scratch) { + return extractObject(source, scratch); } void debugAssertIsObject(const ValueOperand& val); diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index cf569a0c27820..a768c80cc3217 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -1534,6 +1534,17 @@ DoCompareFallback(JSContext* cx, void* payload, ICCompare_Fallback* stub_, Handl return true; } + if (lhs.isSymbol() && rhs.isSymbol() && !stub->hasStub(ICStub::Compare_Symbol)) { + JitSpew(JitSpew_BaselineIC, " Generating %s(Symbol, Symbol) stub", CodeName[op]); + ICCompare_Symbol::Compiler compiler(cx, op, engine); + ICStub* symbolStub = compiler.getStub(compiler.getStubSpace(info.outerScript(cx))); + if (!symbolStub) + return false; + + stub->addNewStub(symbolStub); + return true; + } + if (lhs.isObject() && rhs.isObject()) { MOZ_ASSERT(!stub->hasStub(ICStub::Compare_Object)); JitSpew(JitSpew_BaselineIC, " Generating %s(Object, Object) stub", CodeName[op]); @@ -1624,6 +1635,38 @@ ICCompare_String::Compiler::generateStubCode(MacroAssembler& masm) return true; } +// +// Compare_Symbol +// + +bool +ICCompare_Symbol::Compiler::generateStubCode(MacroAssembler& masm) +{ + Label failure; + masm.branchTestSymbol(Assembler::NotEqual, R0, &failure); + masm.branchTestSymbol(Assembler::NotEqual, R1, &failure); + + MOZ_ASSERT(IsEqualityOp(op)); + + Register left = masm.extractSymbol(R0, ExtractTemp0); + Register right = masm.extractSymbol(R1, ExtractTemp1); + + Label ifTrue; + masm.branchPtr(JSOpToCondition(op, /* signed = */true), left, right, &ifTrue); + + masm.moveValue(BooleanValue(false), R0); + EmitReturnFromIC(masm); + + masm.bind(&ifTrue); + masm.moveValue(BooleanValue(true), R0); + EmitReturnFromIC(masm); + + // Failure case - jump to next stub + masm.bind(&failure); + EmitStubGuardFailure(masm); + return true; +} + // // Compare_Boolean // diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index 8d2e0328c6a32..0d7a376478aad 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -2123,6 +2123,30 @@ class ICCompare_String : public ICStub }; }; +class ICCompare_Symbol : public ICStub +{ + friend class ICStubSpace; + + explicit ICCompare_Symbol(JitCode* stubCode) + : ICStub(ICStub::Compare_Symbol, stubCode) + {} + + public: + class Compiler : public ICMultiStubCompiler { + protected: + MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm); + + public: + Compiler(JSContext* cx, JSOp op, Engine engine) + : ICMultiStubCompiler(cx, ICStub::Compare_Symbol, op, engine) + {} + + ICStub* getStub(ICStubSpace* space) { + return newStub(space, getStubCode()); + } + }; +}; + class ICCompare_Boolean : public ICStub { friend class ICStubSpace; diff --git a/js/src/jit/SharedICList.h b/js/src/jit/SharedICList.h index d211b75f4a7ed..aac54ce39cb91 100644 --- a/js/src/jit/SharedICList.h +++ b/js/src/jit/SharedICList.h @@ -29,6 +29,7 @@ namespace jit { _(Compare_Double) \ _(Compare_NumberWithUndefined) \ _(Compare_String) \ + _(Compare_Symbol) \ _(Compare_Boolean) \ _(Compare_Object) \ _(Compare_ObjectWithUndefined) \ From e1f3393ad5372bf19124a43f4507e75a6b17d4d9 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Tue, 21 Feb 2017 08:43:50 -0500 Subject: [PATCH 20/42] Bug 1288993 - adjust target tasks to use correct taskcluster attributes. r=dustin MozReview-Commit-ID: 8g04JU31JLC --- taskcluster/taskgraph/target_tasks.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/taskcluster/taskgraph/target_tasks.py b/taskcluster/taskgraph/target_tasks.py index 80bb623ca19aa..40ce2e55b6a1f 100644 --- a/taskcluster/taskgraph/target_tasks.py +++ b/taskcluster/taskgraph/target_tasks.py @@ -153,14 +153,15 @@ def filter(task): def target_tasks_valgrind(full_task_graph, parameters): """Target tasks that only run on the cedar branch.""" def filter(task): - platform = task.attributes.get('build_platform') - # only select platforms + platform = task.attributes.get('test_platform') if platform not in ['linux64']: return False - if task.attributes.get('unittest_suite'): - if not (task.attributes['unittest_suite'].startswith('mochitest-valgrind')): - return False - return True + + if task.attributes.get('unittest_suite', '').startswith('mochitest') and \ + task.attributes.get('unittest_flavor', '').startswith('valgrind-plain'): + return True + return False + return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)] @@ -168,8 +169,8 @@ def filter(task): def target_tasks_code_coverage(full_task_graph, parameters): """Target tasks that generate coverage data.""" def filter(task): - platform = task.attributes.get('build_platform') - if platform not in ('linux64-ccov/opt', 'linux64-jsdcov/opt'): + platform = task.attributes.get('test_platform') + if platform not in ('linux64-ccov', 'linux64-jsdcov'): return False return True return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)] From 154129fc8ff3be15d88517645f417137efef2551 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Tue, 21 Feb 2017 06:46:22 -0700 Subject: [PATCH 21/42] Bug 1340537 - Don't trace parse task things if they cannot be GCed, r=jonco. --HG-- extra : rebase_source : 9f2601330438f20eb830fb14546adda836ef6bcb --- js/src/vm/HelperThreads.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 6f6f568055bfd..fed1e543a0c64 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -28,6 +28,8 @@ #include "jsobjinlines.h" #include "jsscriptinlines.h" +#include "vm/NativeObject-inl.h" + using namespace js; using mozilla::ArrayLength; @@ -352,6 +354,11 @@ ParseTask::trace(JSTracer* trc) { if (parseGlobal->runtimeFromAnyThread() != trc->runtime()) return; + Zone* zone = MaybeForwarded(parseGlobal)->zoneFromAnyThread(); + if (zone->usedByHelperThread()) { + MOZ_ASSERT(!zone->isCollecting()); + return; + } TraceManuallyBarrieredEdge(trc, &parseGlobal, "ParseTask::parseGlobal"); if (script) @@ -1229,7 +1236,7 @@ HelperThread::handleGCParallelWorkload(AutoLockHelperThreadState& locked) static void LeaveParseTaskZone(JSRuntime* rt, ParseTask* task) { - // Mark the zone as no longer in use by an JSContext, and available + // Mark the zone as no longer in use by a helper thread, and available // to be collected by the GC. rt->clearUsedByHelperThread(task->parseGlobal->zone()); } From 886c391f8f723d892e5d0437bd955ca32d091a10 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 21 Feb 2017 15:04:32 +0100 Subject: [PATCH 22/42] Bug 1334975 - Get rid of nsIFilePicker.show() use in gecko, r=Gijs, r=ochameau --- .../components/addons/controls.js | 31 ++-- devtools/client/aboutdebugging/test/head.js | 2 +- .../client/canvasdebugger/snapshotslist.js | 60 ++++---- devtools/client/jsonview/main.js | 10 +- devtools/client/jsonview/utils.js | 33 +++-- .../client/netmonitor/har/har-exporter.js | 32 ++-- devtools/client/netmonitor/har/har-utils.js | 15 +- .../client/performance/performance-view.js | 8 +- devtools/client/webide/content/newapp.js | 99 +++++++------ devtools/client/webide/content/simulator.js | 26 ++-- .../client/webide/modules/project-list.js | 2 +- devtools/client/webide/modules/utils.js | 17 ++- .../layout-debug/ui/content/layoutdebug.js | 30 ++-- .../pki/resources/content/certManager.js | 47 +++--- .../specialpowers/content/MockFilePicker.jsm | 11 +- .../components/apppicker/content/appPicker.js | 20 +-- .../printing/content/printdialog.js | 139 ++++++++++-------- toolkit/mozapps/downloads/nsHelperAppDlg.js | 80 +++++----- .../mozapps/extensions/content/extensions.js | 22 +-- .../mozapps/extensions/content/setting.xml | 10 +- .../test/browser/browser_inlinesettings.js | 52 +++++-- .../browser/browser_inlinesettings_info.js | 55 ++++--- toolkit/mozapps/handling/content/dialog.js | 54 +++---- widget/nsIFilePicker.idl | 2 + 24 files changed, 480 insertions(+), 377 deletions(-) diff --git a/devtools/client/aboutdebugging/components/addons/controls.js b/devtools/client/aboutdebugging/components/addons/controls.js index 7f985528c1f1c..aabcbf8802e1c 100644 --- a/devtools/client/aboutdebugging/components/addons/controls.js +++ b/devtools/client/aboutdebugging/components/addons/controls.js @@ -47,22 +47,23 @@ module.exports = createClass({ fp.init(window, Strings.GetStringFromName("selectAddonFromFile2"), Ci.nsIFilePicker.modeOpen); - let res = fp.show(); - if (res == Ci.nsIFilePicker.returnCancel || !fp.file) { - return; - } - let file = fp.file; - // AddonManager.installTemporaryAddon accepts either - // addon directory or final xpi file. - if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) { - file = file.parent; - } + fp.open(res => { + if (res == Ci.nsIFilePicker.returnCancel || !fp.file) { + return; + } + let file = fp.file; + // AddonManager.installTemporaryAddon accepts either + // addon directory or final xpi file. + if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) { + file = file.parent; + } - AddonManager.installTemporaryAddon(file) - .catch(e => { - console.error(e); - this.setState({ installError: e.message }); - }); + AddonManager.installTemporaryAddon(file) + .catch(e => { + console.error(e); + this.setState({ installError: e.message }); + }); + }); }, render() { diff --git a/devtools/client/aboutdebugging/test/head.js b/devtools/client/aboutdebugging/test/head.js index c7d6a9351be81..a3fe91e479dd2 100644 --- a/devtools/client/aboutdebugging/test/head.js +++ b/devtools/client/aboutdebugging/test/head.js @@ -113,7 +113,7 @@ function getTabList(document) { function* installAddon({document, path, name, isWebExtension}) { // Mock the file picker to select a test addon let MockFilePicker = SpecialPowers.MockFilePicker; - MockFilePicker.init(null); + MockFilePicker.init(window); let file = getSupportsFile(path); MockFilePicker.returnFiles = [file.file]; diff --git a/devtools/client/canvasdebugger/snapshotslist.js b/devtools/client/canvasdebugger/snapshotslist.js index e32194796e481..3c9774c4bbe7d 100644 --- a/devtools/client/canvasdebugger/snapshotslist.js +++ b/devtools/client/canvasdebugger/snapshotslist.js @@ -357,38 +357,40 @@ var SnapshotsListView = Heritage.extend(WidgetMethods, { fp.appendFilter(L10N.getStr("snapshotsList.saveDialogJSONFilter"), "*.json"); fp.appendFilter(L10N.getStr("snapshotsList.saveDialogAllFilter"), "*.*"); - if (fp.show() != Ci.nsIFilePicker.returnOK) { - return; - } - - let channel = NetUtil.newChannel({ - uri: NetUtil.newURI(fp.file), loadUsingSystemPrincipal: true}); - channel.contentType = "text/plain"; - - NetUtil.asyncFetch(channel, (inputStream, status) => { - if (!Components.isSuccessCode(status)) { - console.error("Could not import recorded animation frame snapshot file."); - return; - } - try { - let string = NetUtil.readInputStreamToString(inputStream, inputStream.available()); - var data = JSON.parse(string); - } catch (e) { - console.error("Could not read animation frame snapshot file."); - return; - } - if (data.fileType != CALLS_LIST_SERIALIZER_IDENTIFIER) { - console.error("Unrecognized animation frame snapshot file."); + fp.open(rv => { + if (rv != Ci.nsIFilePicker.returnOK) { return; } - // Add a `isLoadedFromDisk` flag on everything to avoid sending invalid - // requests to the backend, since we're not dealing with actors anymore. - let snapshotItem = this.addSnapshot(); - snapshotItem.isLoadedFromDisk = true; - data.calls.forEach(e => e.isLoadedFromDisk = true); - - this.customizeSnapshot(snapshotItem, data.calls, data); + let channel = NetUtil.newChannel({ + uri: NetUtil.newURI(fp.file), loadUsingSystemPrincipal: true}); + channel.contentType = "text/plain"; + + NetUtil.asyncFetch(channel, (inputStream, status) => { + if (!Components.isSuccessCode(status)) { + console.error("Could not import recorded animation frame snapshot file."); + return; + } + try { + let string = NetUtil.readInputStreamToString(inputStream, inputStream.available()); + var data = JSON.parse(string); + } catch (e) { + console.error("Could not read animation frame snapshot file."); + return; + } + if (data.fileType != CALLS_LIST_SERIALIZER_IDENTIFIER) { + console.error("Unrecognized animation frame snapshot file."); + return; + } + + // Add a `isLoadedFromDisk` flag on everything to avoid sending invalid + // requests to the backend, since we're not dealing with actors anymore. + let snapshotItem = this.addSnapshot(); + snapshotItem.isLoadedFromDisk = true; + data.calls.forEach(e => e.isLoadedFromDisk = true); + + this.customizeSnapshot(snapshotItem, data.calls, data); + }); }); }, diff --git a/devtools/client/jsonview/main.js b/devtools/client/jsonview/main.js index a438e2e349ca0..eb552649717b6 100644 --- a/devtools/client/jsonview/main.js +++ b/devtools/client/jsonview/main.js @@ -50,11 +50,11 @@ var JsonView = { * in the parent process. */ onSave: function (message) { - let value = message.data; - let file = JsonViewUtils.getTargetFile(); - if (file) { - JsonViewUtils.saveToFile(file, value); - } + JsonViewUtils.getTargetFile(file => { + if (file) { + JsonViewUtils.saveToFile(file, message.data); + } + }); } }; diff --git a/devtools/client/jsonview/utils.js b/devtools/client/jsonview/utils.js index a70afdc68cadf..c1f61d05488a6 100644 --- a/devtools/client/jsonview/utils.js +++ b/devtools/client/jsonview/utils.js @@ -23,21 +23,24 @@ const OPEN_FLAGS = { * Open File Save As dialog and let the user to pick proper file location. */ exports.getTargetFile = function () { - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); - - let win = getMostRecentBrowserWindow(); - fp.init(win, null, Ci.nsIFilePicker.modeSave); - fp.appendFilter("JSON Files", "*.json; *.jsonp;"); - fp.appendFilters(Ci.nsIFilePicker.filterText); - fp.appendFilters(Ci.nsIFilePicker.filterAll); - fp.filterIndex = 0; - - let rv = fp.show(); - if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) { - return fp.file; - } - - return null; + return new Promise(resolve => { + let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); + + let win = getMostRecentBrowserWindow(); + fp.init(win, null, Ci.nsIFilePicker.modeSave); + fp.appendFilter("JSON Files", "*.json; *.jsonp;"); + fp.appendFilters(Ci.nsIFilePicker.filterText); + fp.appendFilters(Ci.nsIFilePicker.filterAll); + fp.filterIndex = 0; + + fp.open(rv => { + if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) { + resolve(fp.file); + } else { + resolve(null); + } + }); + }); }; /** diff --git a/devtools/client/netmonitor/har/har-exporter.js b/devtools/client/netmonitor/har/har-exporter.js index 6316176c7e793..fae44585f8b36 100644 --- a/devtools/client/netmonitor/har/har-exporter.js +++ b/devtools/client/netmonitor/har/har-exporter.js @@ -70,22 +70,22 @@ const HarExporter = { // Get target file for exported data. Bail out, if the user // presses cancel. - let file = HarUtils.getTargetFile(options.defaultFileName, - options.jsonp, options.compress); - - if (!file) { - return Promise.resolve(); - } - - trace.log("HarExporter.save; " + options.defaultFileName, options); - - return this.fetchHarData(options).then(jsonString => { - if (!HarUtils.saveToFile(file, jsonString, options.compress)) { - let msg = "Failed to save HAR file at: " + options.defaultFileName; - console.error(msg); - } - return jsonString; - }); + return HarUtils.getTargetFile(options.defaultFileName, options.jsonp, + options.compress).then(file => { + if (!file) { + return null; + } + + trace.log("HarExporter.save; " + options.defaultFileName, options); + + return this.fetchHarData(options).then(jsonString => { + if (!HarUtils.saveToFile(file, jsonString, options.compress)) { + let msg = "Failed to save HAR file at: " + options.defaultFileName; + console.error(msg); + } + return jsonString; + }); + }); }, /** diff --git a/devtools/client/netmonitor/har/har-utils.js b/devtools/client/netmonitor/har/har-utils.js index 5e0592afa9d10..082d31ee11375 100644 --- a/devtools/client/netmonitor/har/har-utils.js +++ b/devtools/client/netmonitor/har/har-utils.js @@ -56,7 +56,7 @@ var HarUtils = { * Open File Save As dialog and let the user pick the proper file * location for generated HAR log. */ - getTargetFile: function (fileName, jsonp, compress) { + getTargetFile: function (fileName, jsonp, compress, cb) { let browser = getMostRecentBrowserWindow(); let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); @@ -68,12 +68,13 @@ var HarUtils = { fp.defaultString = this.getHarFileName(fileName, jsonp, compress); - let rv = fp.show(); - if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) { - return fp.file; - } - - return null; + fp.open(rv => { + if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) { + cb(fp.file); + } else { + cb(null); + } + }); }, getHarFileName: function (defaultFileName, jsonp, compress) { diff --git a/devtools/client/performance/performance-view.js b/devtools/client/performance/performance-view.js index 2efc3cdd20f85..526f3a8ec27e7 100644 --- a/devtools/client/performance/performance-view.js +++ b/devtools/client/performance/performance-view.js @@ -359,9 +359,11 @@ var PerformanceView = { fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json"); fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*"); - if (fp.show() == Ci.nsIFilePicker.returnOK) { - this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file); - } + fp.open(rv => { + if (rv == Ci.nsIFilePicker.returnOK) { + this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file); + } + }); }, /** diff --git a/devtools/client/webide/content/newapp.js b/devtools/client/webide/content/newapp.js index 5e52e3417bb82..12a25dc53a937 100644 --- a/devtools/client/webide/content/newapp.js +++ b/devtools/client/webide/content/newapp.js @@ -110,62 +110,65 @@ function doOK() { return false; } - let folder; - /* Chrome mochitest support */ - let testOptions = window.arguments[0].testOptions; - if (testOptions) { - folder = testOptions.folder; - } else { - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); - fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder); - let res = fp.show(); - if (res == Ci.nsIFilePicker.returnCancel) { - console.error("No directory selected"); - return false; + let promise = new Promise((resolve, reject) => { + let testOptions = window.arguments[0].testOptions; + if (testOptions) { + resolve(testOptions.folder); + } else { + let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); + fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder); + fp.open(res => { + if (res == Ci.nsIFilePicker.returnCancel) { + console.error("No directory selected"); + reject(null); + } else { + resolve(fp.file); + } + }); } - folder = fp.file; - } - - // Create subfolder with fs-friendly name of project - let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase(); - let win = Services.wm.getMostRecentWindow("devtools:webide"); - folder.append(subfolder); - - try { - folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - } catch (e) { - win.UI.reportError("error_folderCreationFailed"); - window.close(); - return false; - } - - // Download boilerplate zip - let template = gTemplateList[templatelistNode.selectedIndex]; - let source = template.file; - let target = folder.clone(); - target.append(subfolder + ".zip"); + }); let bail = (e) => { console.error(e); window.close(); }; - Downloads.fetch(source, target).then(() => { - ZipUtils.extractFiles(target, folder); - target.remove(false); - AppProjects.addPackaged(folder).then((project) => { - window.arguments[0].location = project.location; - AppManager.validateAndUpdateProject(project).then(() => { - if (project.manifest) { - project.manifest.name = projectName; - AppManager.writeManifest(project).then(() => { - AppManager.validateAndUpdateProject(project).then( - () => {window.close();}, bail); - }, bail); - } else { - bail("Manifest not found"); - } + promise.then(folder => { + // Create subfolder with fs-friendly name of project + let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase(); + let win = Services.wm.getMostRecentWindow("devtools:webide"); + folder.append(subfolder); + + try { + folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + } catch (e) { + win.UI.reportError("error_folderCreationFailed"); + window.close(); + return; + } + + // Download boilerplate zip + let template = gTemplateList[templatelistNode.selectedIndex]; + let source = template.file; + let target = folder.clone(); + target.append(subfolder + ".zip"); + Downloads.fetch(source, target).then(() => { + ZipUtils.extractFiles(target, folder); + target.remove(false); + AppProjects.addPackaged(folder).then((project) => { + window.arguments[0].location = project.location; + AppManager.validateAndUpdateProject(project).then(() => { + if (project.manifest) { + project.manifest.name = projectName; + AppManager.writeManifest(project).then(() => { + AppManager.validateAndUpdateProject(project).then( + () => {window.close();}, bail); + }, bail); + } else { + bail("Manifest not found"); + } + }, bail); }, bail); }, bail); }, bail); diff --git a/devtools/client/webide/content/simulator.js b/devtools/client/webide/content/simulator.js index ddc1cbed12dbe..60fbd03c6cca1 100644 --- a/devtools/client/webide/content/simulator.js +++ b/devtools/client/webide/content/simulator.js @@ -289,12 +289,13 @@ var SimulatorEditor = { case "version": switch (input.value) { case "pick": - let file = utils.getCustomBinary(window); - if (file) { - this.version = file.path; - } - // Whatever happens, don't stay on the "pick" option. - this.updateVersionSelector(); + utils.getCustomBinary(window).then(file => { + if (file) { + this.version = file.path; + } + // Whatever happens, don't stay on the "pick" option. + this.updateVersionSelector(); + }); break; case "custom": this.version = input[input.selectedIndex].textContent; @@ -306,12 +307,13 @@ var SimulatorEditor = { case "profile": switch (input.value) { case "pick": - let directory = utils.getCustomProfile(window); - if (directory) { - this.profile = directory.path; - } - // Whatever happens, don't stay on the "pick" option. - this.updateProfileSelector(); + utils.getCustomProfile(window).then(directory => { + if (directory) { + this.profile = directory.path; + } + // Whatever happens, don't stay on the "pick" option. + this.updateProfileSelector(); + }); break; case "custom": this.profile = input[input.selectedIndex].textContent; diff --git a/devtools/client/webide/modules/project-list.js b/devtools/client/webide/modules/project-list.js index 10766dd4f251d..dee62b0045ed0 100644 --- a/devtools/client/webide/modules/project-list.js +++ b/devtools/client/webide/modules/project-list.js @@ -92,7 +92,7 @@ ProjectList.prototype = { let parentWindow = this._parentWindow; let UI = this._UI; return UI.busyUntil(Task.spawn(function* () { - let directory = utils.getPackagedDirectory(parentWindow, location); + let directory = yield utils.getPackagedDirectory(parentWindow, location); if (!directory) { // User cancelled directory selection diff --git a/devtools/client/webide/modules/utils.js b/devtools/client/webide/modules/utils.js index 7a19c70440d67..5438cbc28185b 100644 --- a/devtools/client/webide/modules/utils.js +++ b/devtools/client/webide/modules/utils.js @@ -15,15 +15,20 @@ exports.doesFileExist = doesFileExist; function _getFile(location, ...pickerParams) { if (location) { - return new FileUtils.File(location); + return Promise.resolve(new FileUtils.File(location)); } let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); fp.init(...pickerParams); - let res = fp.show(); - if (res == Ci.nsIFilePicker.returnCancel) { - return null; - } - return fp.file; + + return new Promise(resolve => { + fp.open(res => { + if (res == Ci.nsIFilePicker.returnCancel) { + resolve(null); + } else { + resolve(fp.file); + } + }); + }); } function getCustomBinary(window, location) { diff --git a/layout/tools/layout-debug/ui/content/layoutdebug.js b/layout/tools/layout-debug/ui/content/layoutdebug.js index ff9cec09e8f8c..19af4cdf51f04 100644 --- a/layout/tools/layout-debug/ui/content/layoutdebug.js +++ b/layout/tools/layout-debug/ui/content/layoutdebug.js @@ -167,10 +167,12 @@ function openFile() .createInstance(nsIFilePicker); fp.init(window, "Select a File", nsIFilePicker.modeOpen); fp.appendFilters(nsIFilePicker.filterHTML | nsIFilePicker.filterAll); - if (fp.show() == nsIFilePicker.returnOK && fp.fileURL.spec && - fp.fileURL.spec.length > 0) { - gBrowser.loadURI(fp.fileURL.spec); - } + fp.open(rv => { + if (rv == nsIFilePicker.returnOK && fp.fileURL.spec && + fp.fileURL.spec.length > 0) { + gBrowser.loadURI(fp.fileURL.spec); + } + }); } const LDB_RDFNS = "http://mozilla.org/newlayout/LDB-rdf#"; const NC_RDFNS = "http://home.netscape.com/NC-rdf#"; @@ -264,17 +266,19 @@ RTestIndexList.prototype = { fp.init(window, "New Regression Test List", nsIFilePicker.modeOpen); fp.appendFilters(nsIFilePicker.filterAll); fp.defaultString = "rtest.lst"; - if (fp.show() != nsIFilePicker.returnOK) - return; - - var file = fp.file.persistentDescriptor; - var resource = this.mRDFService.GetResource(file); - var literal = this.mRDFService.GetLiteral(file); - this.mDataSource.Assert(this.mLDB_Root, this.mNC_Child, resource, true); - this.mDataSource.Assert(resource, this.mNC_Name, literal, true); + fp.open(rv => { + if (rv != nsIFilePicker.returnOK) { + return; + } - this.save(); + var file = fp.file.persistentDescriptor; + var resource = this.mRDFService.GetResource(file); + var literal = this.mRDFService.GetLiteral(file); + this.mDataSource.Assert(this.mLDB_Root, this.mNC_Child, resource, true); + this.mDataSource.Assert(resource, this.mNC_Name, literal, true); + this.save(); + }); }, remove : function(file) diff --git a/security/manager/pki/resources/content/certManager.js b/security/manager/pki/resources/content/certManager.js index b9804d0af91a2..037f4760716e8 100644 --- a/security/manager/pki/resources/content/certManager.js +++ b/security/manager/pki/resources/content/certManager.js @@ -332,10 +332,11 @@ function backupCerts() fp.appendFilter(bundle.getString("file_browse_PKCS12_spec"), "*.p12"); fp.appendFilters(nsIFilePicker.filterAll); - var rv = fp.show(); - if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) { - certdb.exportPKCS12File(fp.file, selected_certs.length, selected_certs); - } + fp.open(rv => { + if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) { + certdb.exportPKCS12File(fp.file, selected_certs.length, selected_certs); + } + }); } function backupAllCerts() @@ -367,7 +368,11 @@ function restoreCerts() fp.appendFilter(bundle.getString("file_browse_Certificate_spec"), gCertFileTypes); fp.appendFilters(nsIFilePicker.filterAll); - if (fp.show() == nsIFilePicker.returnOK) { + fp.open(rv => { + if (rv != nsIFilePicker.returnOK) { + return; + } + // If this is an X509 user certificate, import it as one. var isX509FileType = false; @@ -407,7 +412,7 @@ function restoreCerts() caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT); caTreeView.selection.clearSelection(); enableBackupAllButton(); - } + }); } function exportCerts() @@ -485,11 +490,13 @@ function addCACerts() fp.appendFilter(bundle.getString("file_browse_Certificate_spec"), gCertFileTypes); fp.appendFilters(nsIFilePicker.filterAll); - if (fp.show() == nsIFilePicker.returnOK) { - certdb.importCertsFromFile(fp.file, nsIX509Cert.CA_CERT); - caTreeView.loadCerts(nsIX509Cert.CA_CERT); - caTreeView.selection.clearSelection(); - } + fp.open(rv => { + if (rv == nsIFilePicker.returnOK) { + certdb.importCertsFromFile(fp.file, nsIX509Cert.CA_CERT); + caTreeView.loadCerts(nsIX509Cert.CA_CERT); + caTreeView.selection.clearSelection(); + } + }); } function onSmartCardChange() @@ -519,14 +526,16 @@ function addEmailCert() fp.appendFilter(bundle.getString("file_browse_Certificate_spec"), gCertFileTypes); fp.appendFilters(nsIFilePicker.filterAll); - if (fp.show() == nsIFilePicker.returnOK) { - certdb.importCertsFromFile(fp.file, nsIX509Cert.EMAIL_CERT); - var certcache = certdb.getCerts(); - emailTreeView.loadCertsFromCache(certcache, nsIX509Cert.EMAIL_CERT); - emailTreeView.selection.clearSelection(); - caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT); - caTreeView.selection.clearSelection(); - } + fp.open(rv => { + if (rv == nsIFilePicker.returnOK) { + certdb.importCertsFromFile(fp.file, nsIX509Cert.EMAIL_CERT); + var certcache = certdb.getCerts(); + emailTreeView.loadCertsFromCache(certcache, nsIX509Cert.EMAIL_CERT); + emailTreeView.selection.clearSelection(); + caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT); + caTreeView.selection.clearSelection(); + } + }); } function addException() diff --git a/testing/specialpowers/content/MockFilePicker.jsm b/testing/specialpowers/content/MockFilePicker.jsm index 4c93cd0e2b4c3..0a2ca4c0e326e 100644 --- a/testing/specialpowers/content/MockFilePicker.jsm +++ b/testing/specialpowers/content/MockFilePicker.jsm @@ -76,6 +76,7 @@ this.MockFilePicker = { this.returnFiles = []; this.returnValue = null; this.showCallback = null; + this.afterOpenCallback = null; this.shown = false; this.showing = false; }, @@ -210,6 +211,9 @@ MockFilePickerInstance.prototype = { }; }, show: function() { + throw "This is not implemented"; + }, + _openInternal: function() { MockFilePicker.displayDirectory = this.displayDirectory; MockFilePicker.shown = true; if (typeof MockFilePicker.showCallback == "function") { @@ -224,12 +228,17 @@ MockFilePickerInstance.prototype = { this.window.setTimeout(function() { let result = Components.interfaces.nsIFilePicker.returnCancel; try { - result = this.show(); + result = this._openInternal(); } catch(ex) { } if (aFilePickerShownCallback) { aFilePickerShownCallback.done(result); } + if (typeof MockFilePicker.afterOpenCallback == "function") { + this.window.setTimeout(() => { + MockFilePicker.afterOpenCallback(this); + }, 0); + } }.bind(this), 0); } }; diff --git a/toolkit/components/apppicker/content/appPicker.js b/toolkit/components/apppicker/content/appPicker.js index 469a6ca23197b..d746a85d94347 100644 --- a/toolkit/components/apppicker/content/appPicker.js +++ b/toolkit/components/apppicker/content/appPicker.js @@ -193,15 +193,17 @@ AppPicker.prototype = fp.displayDirectory = fileLoc.get(startLocation, Components.interfaces.nsILocalFile); - if (fp.show() == nsIFilePicker.returnOK && fp.file) { - var localHandlerApp = - Components.classes["@mozilla.org/uriloader/local-handler-app;1"]. - createInstance(Components.interfaces.nsILocalHandlerApp); - localHandlerApp.executable = fp.file; - - this._incomingParams.handlerApp = localHandlerApp; - window.close(); - } + fp.open(rv => { + if (rv == nsIFilePicker.returnOK && fp.file) { + var localHandlerApp = + Components.classes["@mozilla.org/uriloader/local-handler-app;1"]. + createInstance(Components.interfaces.nsILocalHandlerApp); + localHandlerApp.executable = fp.file; + + this._incomingParams.handlerApp = localHandlerApp; + window.close(); + } + }); return true; } } diff --git a/toolkit/components/printing/content/printdialog.js b/toolkit/components/printing/content/printdialog.js index f42bdf08f976e..77bb565c22468 100644 --- a/toolkit/components/printing/content/printdialog.js +++ b/toolkit/components/printing/content/printdialog.js @@ -302,7 +302,11 @@ function onLoad() { // --------------------------------------------------- function onAccept() { - if (gPrintSettings != null) { + let promise; + + if (gPrintSettings == null) { + promise = Promise.resolve(); + } else { var print_howToEnableUI = gPrintSetInterface.kFrameEnableNone; // save these out so they can be picked up by the device spec @@ -310,66 +314,75 @@ function onAccept() { print_howToEnableUI = gPrintSettings.howToEnableFrameUI; gPrintSettings.printToFile = dialog.fileCheck.checked; - if (gPrintSettings.printToFile && !chooseFile()) - return false; - - if (dialog.allpagesRadio.selected) { - gPrintSettings.printRange = gPrintSetInterface.kRangeAllPages; - } else if (dialog.rangeRadio.selected) { - gPrintSettings.printRange = gPrintSetInterface.kRangeSpecifiedPageRange; - } else if (dialog.selectionRadio.selected) { - gPrintSettings.printRange = gPrintSetInterface.kRangeSelection; + if (gPrintSettings.printToFile) { + promise = chooseFile(); + } else { + promise = Promise.resolve(); } - gPrintSettings.startPageRange = dialog.frompageInput.value; - gPrintSettings.endPageRange = dialog.topageInput.value; - gPrintSettings.numCopies = dialog.numCopiesInput.value; - - var frametype = gPrintSetInterface.kNoFrames; - if (print_howToEnableUI != gPrintSetInterface.kFrameEnableNone) { - if (dialog.aslaidoutRadio.selected) { - frametype = gPrintSetInterface.kFramesAsIs; - } else if (dialog.selectedframeRadio.selected) { - frametype = gPrintSetInterface.kSelectedFrame; - } else if (dialog.eachframesepRadio.selected) { - frametype = gPrintSetInterface.kEachFrameSep; - } else { - frametype = gPrintSetInterface.kSelectedFrame; + + promise = promise.then(() => { + if (dialog.allpagesRadio.selected) { + gPrintSettings.printRange = gPrintSetInterface.kRangeAllPages; + } else if (dialog.rangeRadio.selected) { + gPrintSettings.printRange = gPrintSetInterface.kRangeSpecifiedPageRange; + } else if (dialog.selectionRadio.selected) { + gPrintSettings.printRange = gPrintSetInterface.kRangeSelection; } - } - gPrintSettings.printFrameType = frametype; - if (doDebug) { - dump("onAccept*********************************************\n"); - dump("frametype " + frametype + "\n"); - dump("numCopies " + gPrintSettings.numCopies + "\n"); - dump("printRange " + gPrintSettings.printRange + "\n"); - dump("printerName " + gPrintSettings.printerName + "\n"); - dump("startPageRange " + gPrintSettings.startPageRange + "\n"); - dump("endPageRange " + gPrintSettings.endPageRange + "\n"); - dump("printToFile " + gPrintSettings.printToFile + "\n"); - } + gPrintSettings.startPageRange = dialog.frompageInput.value; + gPrintSettings.endPageRange = dialog.topageInput.value; + gPrintSettings.numCopies = dialog.numCopiesInput.value; + + var frametype = gPrintSetInterface.kNoFrames; + if (print_howToEnableUI != gPrintSetInterface.kFrameEnableNone) { + if (dialog.aslaidoutRadio.selected) { + frametype = gPrintSetInterface.kFramesAsIs; + } else if (dialog.selectedframeRadio.selected) { + frametype = gPrintSetInterface.kSelectedFrame; + } else if (dialog.eachframesepRadio.selected) { + frametype = gPrintSetInterface.kEachFrameSep; + } else { + frametype = gPrintSetInterface.kSelectedFrame; + } + } + gPrintSettings.printFrameType = frametype; + if (doDebug) { + dump("onAccept*********************************************\n"); + dump("frametype " + frametype + "\n"); + dump("numCopies " + gPrintSettings.numCopies + "\n"); + dump("printRange " + gPrintSettings.printRange + "\n"); + dump("printerName " + gPrintSettings.printerName + "\n"); + dump("startPageRange " + gPrintSettings.startPageRange + "\n"); + dump("endPageRange " + gPrintSettings.endPageRange + "\n"); + dump("printToFile " + gPrintSettings.printToFile + "\n"); + } + }); } - var saveToPrefs = false; + promise.then(() => { + var saveToPrefs = false; - saveToPrefs = gPrefs.getBoolPref("print.save_print_settings"); + saveToPrefs = gPrefs.getBoolPref("print.save_print_settings"); - if (saveToPrefs && printService != null) { - var flags = gPrintSetInterface.kInitSavePaperSize | - gPrintSetInterface.kInitSaveEdges | - gPrintSetInterface.kInitSaveInColor | - gPrintSetInterface.kInitSaveShrinkToFit | - gPrintSetInterface.kInitSaveScaling; - printService.savePrintSettingsToPrefs(gPrintSettings, true, flags); - } + if (saveToPrefs && printService != null) { + var flags = gPrintSetInterface.kInitSavePaperSize | + gPrintSetInterface.kInitSaveEdges | + gPrintSetInterface.kInitSaveInColor | + gPrintSetInterface.kInitSaveShrinkToFit | + gPrintSetInterface.kInitSaveScaling; + printService.savePrintSettingsToPrefs(gPrintSettings, true, flags); + } - // set return value to "print" - if (paramBlock) { - paramBlock.SetInt(0, 1); - } else { - dump("*** FATAL ERROR: No paramBlock\n"); - } + // set return value to "print" + if (paramBlock) { + paramBlock.SetInt(0, 1); + } else { + dump("*** FATAL ERROR: No paramBlock\n"); + } - return true; + window.close(); + }); + + return false; } // --------------------------------------------------- @@ -387,19 +400,17 @@ function onCancel() { // --------------------------------------------------- const nsIFilePicker = Components.interfaces.nsIFilePicker; function chooseFile() { - try { + return new Promise(resolve => { var fp = Components.classes["@mozilla.org/filepicker;1"] .createInstance(nsIFilePicker); fp.init(window, dialog.fpDialog.getAttribute("label"), nsIFilePicker.modeSave); fp.appendFilters(nsIFilePicker.filterAll); - if (fp.show() != Components.interfaces.nsIFilePicker.returnCancel && - fp.file && fp.file.path) { - gPrintSettings.toFileName = fp.file.path; - return true; - } - } catch (ex) { - dump(ex); - } - - return false; + fp.open(rv => { + if (rv != Components.interfaces.nsIFilePicker.returnCancel && + fp.file && fp.file.path) { + gPrintSettings.toFileName = fp.file.path; + resolve(null); + } + }); + }); } diff --git a/toolkit/mozapps/downloads/nsHelperAppDlg.js b/toolkit/mozapps/downloads/nsHelperAppDlg.js index dd9f7269fa92e..2d37f7681f1b3 100644 --- a/toolkit/mozapps/downloads/nsHelperAppDlg.js +++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js @@ -316,53 +316,55 @@ nsUnknownContentTypeDialog.prototype = { if (lastDir && isUsableDirectory(lastDir)) picker.displayDirectory = lastDir; - if (picker.show() == nsIFilePicker.returnCancel) { - // null result means user cancelled. - aLauncher.saveDestinationAvailable(null); - return; - } + picker.open(returnValue => { + if (returnValue == nsIFilePicker.returnCancel) { + // null result means user cancelled. + aLauncher.saveDestinationAvailable(null); + return; + } - // Be sure to save the directory the user chose through the Save As... - // dialog as the new browser.download.dir since the old one - // didn't exist. - result = picker.file; + // Be sure to save the directory the user chose through the Save As... + // dialog as the new browser.download.dir since the old one + // didn't exist. + result = picker.file; - if (result) { - try { - // Remove the file so that it's not there when we ensure non-existence later; - // this is safe because for the file to exist, the user would have had to - // confirm that he wanted the file overwritten. - // Only remove file if final name exists - if (result.exists() && this.getFinalLeafName(result.leafName) == result.leafName) - result.remove(false); - } - catch (ex) { - // As it turns out, the failure to remove the file, for example due to - // permission error, will be handled below eventually somehow. - } + if (result) { + try { + // Remove the file so that it's not there when we ensure non-existence later; + // this is safe because for the file to exist, the user would have had to + // confirm that he wanted the file overwritten. + // Only remove file if final name exists + if (result.exists() && this.getFinalLeafName(result.leafName) == result.leafName) + result.remove(false); + } + catch (ex) { + // As it turns out, the failure to remove the file, for example due to + // permission error, will be handled below eventually somehow. + } - var newDir = result.parent.QueryInterface(Components.interfaces.nsILocalFile); + var newDir = result.parent.QueryInterface(Components.interfaces.nsILocalFile); - // Do not store the last save directory as a pref inside the private browsing mode - gDownloadLastDir.setFile(aLauncher.source, newDir); + // Do not store the last save directory as a pref inside the private browsing mode + gDownloadLastDir.setFile(aLauncher.source, newDir); - try { - result = this.validateLeafName(newDir, result.leafName, null); - } - catch (ex) { - // When the chosen download directory is write-protected, - // display an informative error message. - // In all cases, download will be stopped. - - if (ex.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) { - this.displayBadPermissionAlert(); - aLauncher.saveDestinationAvailable(null); - return; + try { + result = this.validateLeafName(newDir, result.leafName, null); } + catch (ex) { + // When the chosen download directory is write-protected, + // display an informative error message. + // In all cases, download will be stopped. + + if (ex.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) { + this.displayBadPermissionAlert(); + aLauncher.saveDestinationAvailable(null); + return; + } + } } - } - aLauncher.saveDestinationAvailable(result); + aLauncher.saveDestinationAvailable(result); + }); }.bind(this)); }.bind(this)).then(null, Components.utils.reportError); }, diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index 6f74c1d2117a3..aa28014e155f4 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -1391,17 +1391,19 @@ var gViewController = { fp.appendFilters(nsIFilePicker.filterAll); } catch (e) { } - if (fp.show() != nsIFilePicker.returnOK) - return; + fp.open(result => { + if (result != nsIFilePicker.returnOK) + return; - let browser = getBrowserElement(); - let files = fp.files; - while (files.hasMoreElements()) { - let file = files.getNext(); - AddonManager.getInstallForFile(file, install => { - AddonManager.installAddonFromAOM(browser, document.documentURI, install); - }); - } + let browser = getBrowserElement(); + let files = fp.files; + while (files.hasMoreElements()) { + let file = files.getNext(); + AddonManager.getInstallForFile(file, install => { + AddonManager.installAddonFromAOM(browser, document.documentURI, install); + }); + } + }); } }, diff --git a/toolkit/mozapps/extensions/content/setting.xml b/toolkit/mozapps/extensions/content/setting.xml index 1ae4d92657017..80957917cd987 100644 --- a/toolkit/mozapps/extensions/content/setting.xml +++ b/toolkit/mozapps/extensions/content/setting.xml @@ -374,10 +374,12 @@ } } catch (e) {} } - if (filePicker.show() != Ci.nsIFilePicker.returnCancel) { - this.value = filePicker.file.path; - this.inputChanged(); - } + filePicker.open(rv => { + if (rv != Ci.nsIFilePicker.returnCancel && filePicker.file) { + this.value = filePicker.file.path; + this.inputChanged(); + } + }); ]]> diff --git a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js index 20fd868d43204..9317715171b8c 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js +++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js @@ -277,20 +277,25 @@ add_test(function() { is(input.color, "#FF9900", "Color picker should have updated value"); is(Services.prefs.getCharPref("extensions.inlinesettings1.color"), "#FF9900", "Color pref should have been updated"); - try { - ok(!settings[6].hasAttribute("first-row"), "Not the first row"); - var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button"); - input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input"); - is(input.value, "", "Label value should be empty"); - is(input.tooltipText, "", "Label tooltip should be empty"); + ok(!settings[6].hasAttribute("first-row"), "Not the first row"); + var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button"); + input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input"); + is(input.value, "", "Label value should be empty"); + is(input.tooltipText, "", "Label tooltip should be empty"); - var testFile = Services.dirsvc.get("ProfD", Ci.nsIFile); - testFile.append("\u2622"); - var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile); + var testFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + testFile.append("\u2622"); + var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile); - MockFilePicker.returnFiles = [testFile]; - MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK; + MockFilePicker.returnFiles = [testFile]; + MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK; + + let promise = new Promise(resolve => { + MockFilePicker.afterOpenCallback = resolve; EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + }); + + promise.then(() => { is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file"); is(input.value, testFile.path, "Label value should match file chosen"); is(input.tooltipText, testFile.path, "Label tooltip should match file chosen"); @@ -298,7 +303,12 @@ add_test(function() { MockFilePicker.returnFiles = [curProcD]; MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel; - EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + + return new Promise(resolve => { + MockFilePicker.afterOpenCallback = resolve; + EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + }); + }).then(() => { is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file"); is(input.value, testFile.path, "Label value should not have changed"); is(input.tooltipText, testFile.path, "Label tooltip should not have changed"); @@ -312,7 +322,12 @@ add_test(function() { MockFilePicker.returnFiles = [testFile]; MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK; - EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + + return new Promise(resolve => { + MockFilePicker.afterOpenCallback = resolve; + EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + }); + }).then(() => { is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory"); is(input.value, testFile.path, "Label value should match file chosen"); is(input.tooltipText, testFile.path, "Label tooltip should match file chosen"); @@ -320,7 +335,12 @@ add_test(function() { MockFilePicker.returnFiles = [curProcD]; MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel; - EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + + return new Promise(resolve => { + MockFilePicker.afterOpenCallback = resolve; + EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + }); + }).then(() => { is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory"); is(input.value, testFile.path, "Label value should not have changed"); is(input.tooltipText, testFile.path, "Label tooltip should not have changed"); @@ -329,12 +349,12 @@ add_test(function() { var unsizedInput = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input"); var sizedInput = gManagerWindow.document.getAnonymousElementByAttribute(settings[8], "anonid", "input"); is(unsizedInput.clientWidth > sizedInput.clientWidth, true, "Input with size attribute should be smaller than input without"); - } finally { + }).then(() => { button = gManagerWindow.document.getElementById("detail-prefs-btn"); is_element_hidden(button, "Preferences button should not be visible"); gCategoryUtilities.openType("extension", run_next_test); - } + }); }); }); diff --git a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js index 2fb40111496b7..d8249072ed9a3 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js +++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js @@ -269,23 +269,28 @@ add_test(function() { is(input.color, "#FF9900", "Color picker should have updated value"); is(Services.prefs.getCharPref("extensions.inlinesettings1.color"), "#FF9900", "Color pref should have been updated"); - try { - ok(!settings[6].hasAttribute("first-row"), "Not the first row"); - var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button"); + ok(!settings[6].hasAttribute("first-row"), "Not the first row"); + var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button"); - // Workaround for bug 1155324 - we need to ensure that the button is scrolled into view. - button.scrollIntoView(); + // Workaround for bug 1155324 - we need to ensure that the button is scrolled into view. + button.scrollIntoView(); - input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input"); - is(input.value, "", "Label value should be empty"); - is(input.tooltipText, "", "Label tooltip should be empty"); + input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input"); + is(input.value, "", "Label value should be empty"); + is(input.tooltipText, "", "Label tooltip should be empty"); - var profD = Services.dirsvc.get("ProfD", Ci.nsIFile); - var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile); + var profD = Services.dirsvc.get("ProfD", Ci.nsIFile); + var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile); - MockFilePicker.returnFiles = [profD]; - MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK; + MockFilePicker.returnFiles = [profD]; + MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK; + + let promise = new Promise(resolve => { + MockFilePicker.afterOpenCallback = resolve; EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + }); + + promise.then(() => { is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file"); is(input.value, profD.path, "Label value should match file chosen"); is(input.tooltipText, profD.path, "Label tooltip should match file chosen"); @@ -293,7 +298,12 @@ add_test(function() { MockFilePicker.returnFiles = [curProcD]; MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel; - EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + + return promise = new Promise(resolve => { + MockFilePicker.afterOpenCallback = resolve; + EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + }); + }).then(() => { is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file"); is(input.value, profD.path, "Label value should not have changed"); is(input.tooltipText, profD.path, "Label tooltip should not have changed"); @@ -307,7 +317,12 @@ add_test(function() { MockFilePicker.returnFiles = [profD]; MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK; - EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + + return new Promise(resolve => { + MockFilePicker.afterOpenCallback = resolve; + EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + }); + }).then(() => { is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory"); is(input.value, profD.path, "Label value should match file chosen"); is(input.tooltipText, profD.path, "Label tooltip should match file chosen"); @@ -315,18 +330,22 @@ add_test(function() { MockFilePicker.returnFiles = [curProcD]; MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel; - EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + + return new Promise(resolve => { + MockFilePicker.afterOpenCallback = resolve; + EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); + }); + }).then(() => { is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory"); is(input.value, profD.path, "Label value should not have changed"); is(input.tooltipText, profD.path, "Label tooltip should not have changed"); is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should not have changed"); - - } finally { + }).then(() => { button = gManagerWindow.document.getElementById("detail-prefs-btn"); is_element_hidden(button, "Preferences button should not be visible"); gCategoryUtilities.openType("extension", run_next_test); - } + }); }); }); diff --git a/toolkit/mozapps/handling/content/dialog.js b/toolkit/mozapps/handling/content/dialog.js index 479fa0c1e4ba2..860acab0f10c9 100644 --- a/toolkit/mozapps/handling/content/dialog.js +++ b/toolkit/mozapps/handling/content/dialog.js @@ -166,35 +166,37 @@ var dialog = { fp.init(window, title, Ci.nsIFilePicker.modeOpen); fp.appendFilters(Ci.nsIFilePicker.filterApps); - if (fp.show() == Ci.nsIFilePicker.returnOK && fp.file) { - let uri = Cc["@mozilla.org/network/util;1"]. - getService(Ci.nsIIOService). - newFileURI(fp.file); - - let handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]. - createInstance(Ci.nsILocalHandlerApp); - handlerApp.executable = fp.file; - - // if this application is already in the list, select it and don't add it again - let parent = document.getElementById("items"); - for (let i = 0; i < parent.childNodes.length; ++i) { - let elm = parent.childNodes[i]; - if (elm.obj instanceof Ci.nsILocalHandlerApp && elm.obj.equals(handlerApp)) { - parent.selectedItem = elm; - parent.ensureSelectedElementIsVisible(); - return; + fp.open(rv => { + if (rv == Ci.nsIFilePicker.returnOK && fp.file) { + let uri = Cc["@mozilla.org/network/util;1"]. + getService(Ci.nsIIOService). + newFileURI(fp.file); + + let handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]. + createInstance(Ci.nsILocalHandlerApp); + handlerApp.executable = fp.file; + + // if this application is already in the list, select it and don't add it again + let parent = document.getElementById("items"); + for (let i = 0; i < parent.childNodes.length; ++i) { + let elm = parent.childNodes[i]; + if (elm.obj instanceof Ci.nsILocalHandlerApp && elm.obj.equals(handlerApp)) { + parent.selectedItem = elm; + parent.ensureSelectedElementIsVisible(); + return; + } } - } - let elm = document.createElement("richlistitem"); - elm.setAttribute("type", "handler"); - elm.setAttribute("name", fp.file.leafName); - elm.setAttribute("image", "moz-icon://" + uri.spec + "?size=32"); - elm.obj = handlerApp; + let elm = document.createElement("richlistitem"); + elm.setAttribute("type", "handler"); + elm.setAttribute("name", fp.file.leafName); + elm.setAttribute("image", "moz-icon://" + uri.spec + "?size=32"); + elm.obj = handlerApp; - parent.selectedItem = parent.insertBefore(elm, parent.firstChild); - parent.ensureSelectedElementIsVisible(); - } + parent.selectedItem = parent.insertBefore(elm, parent.firstChild); + parent.ensureSelectedElementIsVisible(); + } + }); }, /** diff --git a/widget/nsIFilePicker.idl b/widget/nsIFilePicker.idl index 62efe93ecf2ce..6d5fc55beaf46 100644 --- a/widget/nsIFilePicker.idl +++ b/widget/nsIFilePicker.idl @@ -165,6 +165,8 @@ interface nsIFilePicker : nsISupports attribute boolean addToRecentDocs; /** + * This method is **deprecated**. Please use open() + * * Show File Dialog. The dialog is displayed modally. * * @return returnOK if the user selects OK, returnCancel if the user selects cancel From 0963d188746a17de38c5abe4cb7404092c541a52 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 21 Feb 2017 15:04:47 +0100 Subject: [PATCH 23/42] Bug 1335539 - Get rid of nsIDOMWindowUtils.wrapDOMFile, r=smaug, r=Gijs --- .../general/browser_extension_permissions.js | 4 +- .../general/browser_save_link-perwindowpb.js | 2 +- ...browser_save_link_when_window_navigates.js | 2 +- .../browser_save_private_link_perwindowpb.js | 2 +- .../test/general/browser_save_video.js | 2 +- .../test/general/browser_save_video_frame.js | 2 +- ...browser_privatebrowsing_downloadLastDir.js | 2 +- ...owser_privatebrowsing_downloadLastDir_c.js | 2 +- .../test/browser_addons_install.js | 6 +- devtools/client/aboutdebugging/test/head.js | 5 +- .../client/webide/test/test_simulators.html | 10 +- dom/base/nsDOMWindowUtils.cpp | 21 -- dom/base/test/mochitest.ini | 1 - dom/base/test/test_bug793311.html | 35 ---- dom/file/FileBlobImpl.h | 10 + dom/file/FileCreatorHelper.cpp | 29 ++- dom/file/FileCreatorHelper.h | 2 + dom/interfaces/base/nsIDOMWindowUtils.idl | 6 - dom/ipc/ContentChild.cpp | 4 +- dom/ipc/ContentChild.h | 2 +- dom/ipc/ContentParent.cpp | 4 +- dom/ipc/ContentParent.h | 1 + dom/ipc/PContent.ipdl | 3 +- dom/ipc/tests/test_bug1086684.html | 4 +- dom/webidl/File.webidl | 1 + .../test/test_bug536567_perwindowpb.html | 2 +- mobile/android/components/FilePicker.js | 12 +- .../specialpowers/content/MockFilePicker.jsm | 181 ++++++++++++------ .../test_chrome_ext_downloads_saveAs.html | 3 +- toolkit/components/filepicker/nsFilePicker.js | 75 ++++---- .../tests/browser_input_file_tooltips.js | 7 +- .../browser/browser_save_resend_postdata.js | 4 +- .../test/browser/browser_bug567127.js | 2 +- .../test/browser/browser_inlinesettings.js | 8 +- .../browser/browser_inlinesettings_info.js | 8 +- 35 files changed, 256 insertions(+), 208 deletions(-) delete mode 100644 dom/base/test/test_bug793311.html diff --git a/browser/base/content/test/general/browser_extension_permissions.js b/browser/base/content/test/general/browser_extension_permissions.js index 17564c453a4ed..ee64f8b764fb0 100644 --- a/browser/base/content/test/general/browser_extension_permissions.js +++ b/browser/base/content/test/general/browser_extension_permissions.js @@ -107,14 +107,14 @@ const INSTALL_FUNCTIONS = [ let MockFilePicker = SpecialPowers.MockFilePicker; MockFilePicker.init(window); - MockFilePicker.returnFiles = [file]; + MockFilePicker.setFiles([file]); + MockFilePicker.afterOpenCallback = MockFilePicker.cleanup; await BrowserOpenAddonsMgr("addons://list/extension"); let contentWin = gBrowser.selectedTab.linkedBrowser.contentWindow; // Do the install... contentWin.gViewController.doCommand("cmd_installFromFile"); - MockFilePicker.cleanup(); }, async function installSearch(filename) { diff --git a/browser/base/content/test/general/browser_save_link-perwindowpb.js b/browser/base/content/test/general/browser_save_link-perwindowpb.js index a9ab9e61cd4cf..e497d8b6f8386 100644 --- a/browser/base/content/test/general/browser_save_link-perwindowpb.js +++ b/browser/base/content/test/general/browser_save_link-perwindowpb.js @@ -40,7 +40,7 @@ function triggerSave(aWindow, aCallback) { fileName = fp.defaultString; info("fileName: " + fileName); destFile.append(fileName); - MockFilePicker.returnFiles = [destFile]; + MockFilePicker.setFiles([destFile]); MockFilePicker.filterIndex = 1; // kSaveAsType_URL info("done showCallback"); }; diff --git a/browser/base/content/test/general/browser_save_link_when_window_navigates.js b/browser/base/content/test/general/browser_save_link_when_window_navigates.js index 9e9b1c3a73cc6..854d33714561f 100644 --- a/browser/base/content/test/general/browser_save_link_when_window_navigates.js +++ b/browser/base/content/test/general/browser_save_link_when_window_navigates.js @@ -45,7 +45,7 @@ function triggerSave(aWindow, aCallback) { fileName = fp.defaultString; info("fileName: " + fileName); destFile.append(fileName); - MockFilePicker.returnFiles = [destFile]; + MockFilePicker.setFiles([destFile]); MockFilePicker.filterIndex = 1; // kSaveAsType_URL info("done showCallback"); }; diff --git a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js index 77b3b5bc58c15..5c876284ae8bb 100644 --- a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js +++ b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js @@ -58,7 +58,7 @@ function promiseImageDownloaded() { MockFilePicker.showCallback = function(fp) { fileName = fp.defaultString; destFile.append(fileName); - MockFilePicker.returnFiles = [destFile]; + MockFilePicker.setFiles([destFile]); MockFilePicker.filterIndex = 1; // kSaveAsType_URL }; diff --git a/browser/base/content/test/general/browser_save_video.js b/browser/base/content/test/general/browser_save_video.js index 96b05006779b6..2759d98755eab 100644 --- a/browser/base/content/test/general/browser_save_video.js +++ b/browser/base/content/test/general/browser_save_video.js @@ -34,7 +34,7 @@ add_task(function* () { MockFilePicker.showCallback = function(fp) { fileName = fp.defaultString; destFile.append(fileName); - MockFilePicker.returnFiles = [destFile]; + MockFilePicker.setFiles([destFile]); MockFilePicker.filterIndex = 1; // kSaveAsType_URL }; diff --git a/browser/base/content/test/general/browser_save_video_frame.js b/browser/base/content/test/general/browser_save_video_frame.js index 4c829045663e9..654fe11715407 100644 --- a/browser/base/content/test/general/browser_save_video_frame.js +++ b/browser/base/content/test/general/browser_save_video_frame.js @@ -85,7 +85,7 @@ add_task(function*() { MockFilePicker.displayDirectory = destDir; MockFilePicker.showCallback = function(fp) { destFile.append(fp.defaultString); - MockFilePicker.returnFiles = [destFile]; + MockFilePicker.setFiles([destFile]); MockFilePicker.filterIndex = 1; // kSaveAsType_URL }; diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js index de75eac4c2999..655d469b86155 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js @@ -55,7 +55,7 @@ function test() { is(gDownloadLastDir.file.path, aDisplayDir.path, "gDownloadLastDir should be the expected display dir"); - MockFilePicker.returnFiles = [aFile]; + MockFilePicker.setFiles([aFile]); MockFilePicker.displayDirectory = null; launcher.saveDestinationAvailable = function (file) { diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js index 5a04d1999dfb1..19012d5173004 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js @@ -62,7 +62,7 @@ function test() { is(gDownloadLastDir.file.path, aDisplayDir.path, "gDownloadLastDir should be the expected display dir"); - MockFilePicker.returnFiles = [aFile]; + MockFilePicker.setFiles([aFile]); MockFilePicker.displayDirectory = null; aWin.promiseTargetFile(params).then(function() { // File picker should start with expected display dir. diff --git a/devtools/client/aboutdebugging/test/browser_addons_install.js b/devtools/client/aboutdebugging/test/browser_addons_install.js index 4c3a97c9fc2f4..300fd208b9b2b 100644 --- a/devtools/client/aboutdebugging/test/browser_addons_install.js +++ b/devtools/client/aboutdebugging/test/browser_addons_install.js @@ -23,7 +23,7 @@ add_task(function* () { }); add_task(function* () { - let { tab, document } = yield openAboutDebugging("addons"); + let { tab, document, window } = yield openAboutDebugging("addons"); yield waitForInitialAddonList(document); // Start an observer that looks for the install error before @@ -33,9 +33,9 @@ add_task(function* () { // Mock the file picker to select a test addon let MockFilePicker = SpecialPowers.MockFilePicker; - MockFilePicker.init(null); + MockFilePicker.init(window); let file = getSupportsFile("addons/bad/manifest.json"); - MockFilePicker.returnFiles = [file.file]; + MockFilePicker.setFiles([file.file]); // Trigger the file picker by clicking on the button document.getElementById("load-addon-from-file").click(); diff --git a/devtools/client/aboutdebugging/test/head.js b/devtools/client/aboutdebugging/test/head.js index a3fe91e479dd2..1e04d188f0102 100644 --- a/devtools/client/aboutdebugging/test/head.js +++ b/devtools/client/aboutdebugging/test/head.js @@ -35,12 +35,13 @@ function* openAboutDebugging(page, win) { let tab = yield addTab(url, { window: win }); let browser = tab.linkedBrowser; let document = browser.contentDocument; + let window = browser.contentWindow; if (!document.querySelector(".app")) { yield waitForMutation(document.body, { childList: true }); } - return { tab, document }; + return { tab, document, window }; } /** @@ -115,7 +116,7 @@ function* installAddon({document, path, name, isWebExtension}) { let MockFilePicker = SpecialPowers.MockFilePicker; MockFilePicker.init(window); let file = getSupportsFile(path); - MockFilePicker.returnFiles = [file.file]; + MockFilePicker.setFiles([file.file]); let addonList = getAddonList(document); let addonListMutation = waitForMutation(addonList, { childList: true }); diff --git a/devtools/client/webide/test/test_simulators.html b/devtools/client/webide/test/test_simulators.html index 204881512dcef..285c3566e870e 100644 --- a/devtools/client/webide/test/test_simulators.html +++ b/devtools/client/webide/test/test_simulators.html @@ -190,7 +190,7 @@ // Pick custom binary, but act like the user aborted the file picker. - MockFilePicker.returnFiles = []; + MockFilePicker.setFiles([]); yield set(form.version, "pick"); is(form.version.value, sim20.addonID, "Version selector reverted to last valid choice after customization abort"); @@ -198,10 +198,10 @@ // Pick custom binary, and actually follow through. (success, verify value = "custom" and textContent = custom path) - MockFilePicker.useAnyFile(); + yield MockFilePicker.useAnyFile(); yield set(form.version, "pick"); - let fakeBinary = MockFilePicker.returnFiles[0]; + let fakeBinary = MockFilePicker.file; ok(form.version.value == "custom", "Version selector was set to a new custom binary"); ok(form.version.classList.contains("custom"), "Version selector is now customized"); @@ -221,7 +221,7 @@ is(form.profile.value, "default", "Default simulator profile"); ok(!form.profile.classList.contains("custom"), "Profile selector is not customized"); - MockFilePicker.returnFiles = []; + MockFilePicker.setFiles([]); yield set(form.profile, "pick"); is(form.profile.value, "default", "Profile selector reverted to last valid choice after customization abort"); @@ -229,7 +229,7 @@ let fakeProfile = FileUtils.getDir("TmpD", []); - MockFilePicker.returnFiles = [ fakeProfile ]; + MockFilePicker.setFiles([ fakeProfile ]); yield set(form.profile, "pick"); ok(form.profile.value == "custom", "Profile selector was set to a new custom directory"); diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 40ae9485c2b1a..f44cd5a681770 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -2810,27 +2810,6 @@ nsDOMWindowUtils::GetContainerElement(nsIDOMElement** aResult) return NS_OK; } -NS_IMETHODIMP -nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile, - nsISupports **aDOMFile) -{ - if (!aFile) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr window = do_QueryReferent(mWindow); - NS_ENSURE_STATE(window); - - nsPIDOMWindowInner* innerWindow = window->GetCurrentInnerWindow(); - if (!innerWindow) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr blob = File::CreateFromFile(innerWindow, aFile); - blob.forget(aDOMFile); - return NS_OK; -} - #ifdef DEBUG static bool CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredRegion) diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index af97a8d75ea94..611da9b081f82 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -532,7 +532,6 @@ skip-if = toolkit == 'android' #bug 687032 [test_bug787778.html] [test_bug789315.html] [test_bug789856.html] -[test_bug793311.html] [test_bug804395.html] [test_bug809003.html] [test_bug810494.html] diff --git a/dom/base/test/test_bug793311.html b/dom/base/test/test_bug793311.html deleted file mode 100644 index 5c1e8e7d391d3..0000000000000 --- a/dom/base/test/test_bug793311.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - Test for Bug 793311 - - - - - -Mozilla Bug 793311 -

- -
-
- - diff --git a/dom/file/FileBlobImpl.h b/dom/file/FileBlobImpl.h index 4bb20c65eafcb..c7315cc489f9d 100644 --- a/dom/file/FileBlobImpl.h +++ b/dom/file/FileBlobImpl.h @@ -50,6 +50,16 @@ class FileBlobImpl : public BaseBlobImpl virtual bool IsSizeUnknown() const override { return false; } virtual bool IsDateUnknown() const override { return false; } + void SetName(const nsAString& aName) + { + mName = aName; + } + + void SetType(const nsAString& aType) + { + mContentType = aType; + } + protected: virtual ~FileBlobImpl() = default; diff --git a/dom/file/FileCreatorHelper.cpp b/dom/file/FileCreatorHelper.cpp index 00094c892d5df..a40df1c7d6894 100644 --- a/dom/file/FileCreatorHelper.cpp +++ b/dom/file/FileCreatorHelper.cpp @@ -82,7 +82,8 @@ FileCreatorHelper::CreateFileInternal(nsPIDOMWindowInner* aWindow, RefPtr blobImpl; aRv = CreateBlobImpl(aFile, aBag.mType, aBag.mName, lastModifiedPassed, - lastModified, aIsFromNsIFile, getter_AddRefs(blobImpl)); + lastModified, aBag.mExistenceCheck, aIsFromNsIFile, + getter_AddRefs(blobImpl)); if (aRv.Failed()) { return nullptr; } @@ -130,7 +131,8 @@ FileCreatorHelper::SendRequest(nsIFile* aFile, } cc->FileCreationRequest(uuid, this, path, aBag.mType, aBag.mName, - aBag.mLastModified, aIsFromNsIFile); + aBag.mLastModified, aBag.mExistenceCheck, + aIsFromNsIFile); } void @@ -151,6 +153,7 @@ FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath, const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, + bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl) { @@ -161,7 +164,7 @@ FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath, } return CreateBlobImpl(file, aType, aName, aLastModifiedPassed, aLastModified, - aIsFromNsIFile, aBlobImpl); + aExistenceCheck, aIsFromNsIFile, aBlobImpl); } /* static */ nsresult @@ -170,9 +173,29 @@ FileCreatorHelper::CreateBlobImpl(nsIFile* aFile, const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, + bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl) { + if (!aExistenceCheck) { + RefPtr impl = new FileBlobImpl(aFile); + + if (!aName.IsEmpty()) { + impl->SetName(aName); + } + + if (!aType.IsEmpty()) { + impl->SetType(aType); + } + + if (aLastModifiedPassed) { + impl->SetLastModified(aLastModified); + } + + impl.forget(aBlobImpl); + return NS_OK; + } + RefPtr impl = new MultipartBlobImpl(EmptyString()); nsresult rv = impl->InitializeChromeFile(aFile, aType, aName, aLastModifiedPassed, diff --git a/dom/file/FileCreatorHelper.h b/dom/file/FileCreatorHelper.h index 12cd7e72800a2..bef7914c289ef 100644 --- a/dom/file/FileCreatorHelper.h +++ b/dom/file/FileCreatorHelper.h @@ -51,6 +51,7 @@ class FileCreatorHelper final const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, + bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl); @@ -68,6 +69,7 @@ class FileCreatorHelper final const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, + bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl); diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index ddc514a29b270..29732c9794d15 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1563,12 +1563,6 @@ interface nsIDOMWindowUtils : nsISupports { in AString value1, in AString value2); - /** - * Wrap an nsIFile in an DOM File - * Returns a File object. - */ - nsISupports wrapDOMFile(in nsIFile aFile); - /** * Get the type of the currently focused html input, if any. */ diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 2134466e8d791..f3859eb2cdfb1 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -3175,6 +3175,7 @@ ContentChild::FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper, const nsAString& aType, const nsAString& aName, const Optional& aLastModified, + bool aExistenceCheck, bool aIsFromNsIFile) { MOZ_ASSERT(aHelper); @@ -3188,7 +3189,8 @@ ContentChild::FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper, Unused << SendFileCreationRequest(aUUID, nsString(aFullPath), nsString(aType), nsString(aName), lastModifiedPassed, - lastModified, aIsFromNsIFile); + lastModified, aExistenceCheck, + aIsFromNsIFile); mFileCreationPending.Put(aUUID, aHelper); } diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index b6549f55432af..5444870c89477 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -633,7 +633,7 @@ class ContentChild final : public PContentChild const nsAString& aFullPath, const nsAString& aType, const nsAString& aName, const Optional& aLastModified, - bool aIsFromNsIFile); + bool aExistenceCheck, bool aIsFromNsIFile); private: static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 3f371010f8667..830c6ab3c8aac 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -5020,13 +5020,15 @@ ContentParent::RecvFileCreationRequest(const nsID& aID, const nsString& aName, const bool& aLastModifiedPassed, const int64_t& aLastModified, + const bool& aExistenceCheck, const bool& aIsFromNsIFile) { RefPtr blobImpl; nsresult rv = FileCreatorHelper::CreateBlobImplForIPC(aFullPath, aType, aName, aLastModifiedPassed, - aLastModified, aIsFromNsIFile, + aLastModified, aExistenceCheck, + aIsFromNsIFile, getter_AddRefs(blobImpl)); if (NS_WARN_IF(NS_FAILED(rv))) { if (!SendFileCreationResponse(aID, FileCreationErrorResult(rv))) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 4a2de11ccc516..92c57e11ed09c 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -1113,6 +1113,7 @@ class ContentParent final : public PContentParent const nsString& aType, const nsString& aName, const bool& aLastModifiedPassed, const int64_t& aLastModified, + const bool& aExistenceCheck, const bool& aIsFromNsIFile) override; virtual mozilla::ipc::IPCResult RecvAccumulateChildHistograms( diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index a80382d1034ac..40eabfd39d99e 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -1177,7 +1177,8 @@ parent: async FileCreationRequest(nsID aID, nsString aFullPath, nsString aType, nsString aName, bool lastModifiedPassed, - int64_t lastModified, bool aIsFromNsIFile); + int64_t lastModified, bool aExistenceCheck, + bool aIsFromNsIFile); async StoreAndBroadcastBlobURLRegistration(nsCString url, PBlob blob, Principal principal); diff --git a/dom/ipc/tests/test_bug1086684.html b/dom/ipc/tests/test_bug1086684.html index 962826ec6bcaf..72377f042d037 100644 --- a/dom/ipc/tests/test_bug1086684.html +++ b/dom/ipc/tests/test_bug1086684.html @@ -9,7 +9,7 @@ - + + + + +Mozilla Bug 793311 +

+ +
+
+ + diff --git a/dom/file/FileBlobImpl.h b/dom/file/FileBlobImpl.h index c7315cc489f9d..4bb20c65eafcb 100644 --- a/dom/file/FileBlobImpl.h +++ b/dom/file/FileBlobImpl.h @@ -50,16 +50,6 @@ class FileBlobImpl : public BaseBlobImpl virtual bool IsSizeUnknown() const override { return false; } virtual bool IsDateUnknown() const override { return false; } - void SetName(const nsAString& aName) - { - mName = aName; - } - - void SetType(const nsAString& aType) - { - mContentType = aType; - } - protected: virtual ~FileBlobImpl() = default; diff --git a/dom/file/FileCreatorHelper.cpp b/dom/file/FileCreatorHelper.cpp index a40df1c7d6894..00094c892d5df 100644 --- a/dom/file/FileCreatorHelper.cpp +++ b/dom/file/FileCreatorHelper.cpp @@ -82,8 +82,7 @@ FileCreatorHelper::CreateFileInternal(nsPIDOMWindowInner* aWindow, RefPtr blobImpl; aRv = CreateBlobImpl(aFile, aBag.mType, aBag.mName, lastModifiedPassed, - lastModified, aBag.mExistenceCheck, aIsFromNsIFile, - getter_AddRefs(blobImpl)); + lastModified, aIsFromNsIFile, getter_AddRefs(blobImpl)); if (aRv.Failed()) { return nullptr; } @@ -131,8 +130,7 @@ FileCreatorHelper::SendRequest(nsIFile* aFile, } cc->FileCreationRequest(uuid, this, path, aBag.mType, aBag.mName, - aBag.mLastModified, aBag.mExistenceCheck, - aIsFromNsIFile); + aBag.mLastModified, aIsFromNsIFile); } void @@ -153,7 +151,6 @@ FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath, const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, - bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl) { @@ -164,7 +161,7 @@ FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath, } return CreateBlobImpl(file, aType, aName, aLastModifiedPassed, aLastModified, - aExistenceCheck, aIsFromNsIFile, aBlobImpl); + aIsFromNsIFile, aBlobImpl); } /* static */ nsresult @@ -173,29 +170,9 @@ FileCreatorHelper::CreateBlobImpl(nsIFile* aFile, const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, - bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl) { - if (!aExistenceCheck) { - RefPtr impl = new FileBlobImpl(aFile); - - if (!aName.IsEmpty()) { - impl->SetName(aName); - } - - if (!aType.IsEmpty()) { - impl->SetType(aType); - } - - if (aLastModifiedPassed) { - impl->SetLastModified(aLastModified); - } - - impl.forget(aBlobImpl); - return NS_OK; - } - RefPtr impl = new MultipartBlobImpl(EmptyString()); nsresult rv = impl->InitializeChromeFile(aFile, aType, aName, aLastModifiedPassed, diff --git a/dom/file/FileCreatorHelper.h b/dom/file/FileCreatorHelper.h index bef7914c289ef..12cd7e72800a2 100644 --- a/dom/file/FileCreatorHelper.h +++ b/dom/file/FileCreatorHelper.h @@ -51,7 +51,6 @@ class FileCreatorHelper final const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, - bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl); @@ -69,7 +68,6 @@ class FileCreatorHelper final const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, - bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl); diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 29732c9794d15..ddc514a29b270 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1563,6 +1563,12 @@ interface nsIDOMWindowUtils : nsISupports { in AString value1, in AString value2); + /** + * Wrap an nsIFile in an DOM File + * Returns a File object. + */ + nsISupports wrapDOMFile(in nsIFile aFile); + /** * Get the type of the currently focused html input, if any. */ diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index f3859eb2cdfb1..2134466e8d791 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -3175,7 +3175,6 @@ ContentChild::FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper, const nsAString& aType, const nsAString& aName, const Optional& aLastModified, - bool aExistenceCheck, bool aIsFromNsIFile) { MOZ_ASSERT(aHelper); @@ -3189,8 +3188,7 @@ ContentChild::FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper, Unused << SendFileCreationRequest(aUUID, nsString(aFullPath), nsString(aType), nsString(aName), lastModifiedPassed, - lastModified, aExistenceCheck, - aIsFromNsIFile); + lastModified, aIsFromNsIFile); mFileCreationPending.Put(aUUID, aHelper); } diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 5444870c89477..b6549f55432af 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -633,7 +633,7 @@ class ContentChild final : public PContentChild const nsAString& aFullPath, const nsAString& aType, const nsAString& aName, const Optional& aLastModified, - bool aExistenceCheck, bool aIsFromNsIFile); + bool aIsFromNsIFile); private: static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 830c6ab3c8aac..3f371010f8667 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -5020,15 +5020,13 @@ ContentParent::RecvFileCreationRequest(const nsID& aID, const nsString& aName, const bool& aLastModifiedPassed, const int64_t& aLastModified, - const bool& aExistenceCheck, const bool& aIsFromNsIFile) { RefPtr blobImpl; nsresult rv = FileCreatorHelper::CreateBlobImplForIPC(aFullPath, aType, aName, aLastModifiedPassed, - aLastModified, aExistenceCheck, - aIsFromNsIFile, + aLastModified, aIsFromNsIFile, getter_AddRefs(blobImpl)); if (NS_WARN_IF(NS_FAILED(rv))) { if (!SendFileCreationResponse(aID, FileCreationErrorResult(rv))) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 92c57e11ed09c..4a2de11ccc516 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -1113,7 +1113,6 @@ class ContentParent final : public PContentParent const nsString& aType, const nsString& aName, const bool& aLastModifiedPassed, const int64_t& aLastModified, - const bool& aExistenceCheck, const bool& aIsFromNsIFile) override; virtual mozilla::ipc::IPCResult RecvAccumulateChildHistograms( diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 40eabfd39d99e..a80382d1034ac 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -1177,8 +1177,7 @@ parent: async FileCreationRequest(nsID aID, nsString aFullPath, nsString aType, nsString aName, bool lastModifiedPassed, - int64_t lastModified, bool aExistenceCheck, - bool aIsFromNsIFile); + int64_t lastModified, bool aIsFromNsIFile); async StoreAndBroadcastBlobURLRegistration(nsCString url, PBlob blob, Principal principal); diff --git a/dom/ipc/tests/test_bug1086684.html b/dom/ipc/tests/test_bug1086684.html index 72377f042d037..962826ec6bcaf 100644 --- a/dom/ipc/tests/test_bug1086684.html +++ b/dom/ipc/tests/test_bug1086684.html @@ -9,7 +9,7 @@ -