summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-02-08 12:06:30 +0100
committerwolfbeast <mcwerewolf@gmail.com>2018-02-08 12:06:30 +0100
commit44cd9f2a915a4879371c5e0b059acc3e5a2378b0 (patch)
tree8cb1a4758b16d9caae55f525b73f5fca3824b4f7
parentf8d1830b530cd553d788b3579d41725d35c4da7f (diff)
parentb62fce0dc0c77a5788c331db32b3996e4020e2a5 (diff)
downloadUXP-44cd9f2a915a4879371c5e0b059acc3e5a2378b0.tar
UXP-44cd9f2a915a4879371c5e0b059acc3e5a2378b0.tar.gz
UXP-44cd9f2a915a4879371c5e0b059acc3e5a2378b0.tar.lz
UXP-44cd9f2a915a4879371c5e0b059acc3e5a2378b0.tar.xz
UXP-44cd9f2a915a4879371c5e0b059acc3e5a2378b0.zip
Merge branch 'ported-upstream'
-rw-r--r--browser/components/downloads/DownloadsCommon.jsm8
-rw-r--r--browser/components/extensions/ext-browserAction.js3
-rw-r--r--browser/components/extensions/ext-pageAction.js3
-rw-r--r--browser/components/extensions/schemas/page_action.json1
-rw-r--r--editor/libeditor/CompositionTransaction.cpp20
-rw-r--r--editor/libeditor/CompositionTransaction.h2
-rw-r--r--editor/libeditor/CreateElementTransaction.cpp13
-rw-r--r--editor/libeditor/CreateElementTransaction.h2
-rw-r--r--editor/libeditor/DeleteNodeTransaction.cpp1
-rw-r--r--editor/libeditor/DeleteNodeTransaction.h2
-rw-r--r--editor/libeditor/DeleteRangeTransaction.cpp27
-rw-r--r--editor/libeditor/DeleteRangeTransaction.h2
-rw-r--r--editor/libeditor/DeleteTextTransaction.cpp18
-rw-r--r--editor/libeditor/DeleteTextTransaction.h2
-rw-r--r--editor/libeditor/EditorBase.cpp7
-rw-r--r--editor/libeditor/InsertNodeTransaction.cpp18
-rw-r--r--editor/libeditor/InsertNodeTransaction.h2
-rw-r--r--editor/libeditor/InsertTextTransaction.cpp11
-rw-r--r--editor/libeditor/InsertTextTransaction.h2
-rw-r--r--editor/libeditor/JoinNodeTransaction.cpp20
-rw-r--r--editor/libeditor/JoinNodeTransaction.h2
-rw-r--r--editor/libeditor/PlaceholderTransaction.cpp14
-rw-r--r--editor/libeditor/PlaceholderTransaction.h2
-rw-r--r--editor/libeditor/SplitNodeTransaction.cpp28
-rw-r--r--editor/libeditor/SplitNodeTransaction.h2
-rw-r--r--editor/libeditor/StyleSheetTransactions.cpp2
-rw-r--r--editor/libeditor/StyleSheetTransactions.h4
-rw-r--r--js/src/jit-test/tests/debug/bug1353356.js65
-rw-r--r--js/src/vm/Stack.cpp14
-rw-r--r--js/src/wasm/WasmModule.cpp8
-rw-r--r--layout/base/nsDocumentViewer.cpp6
-rw-r--r--storage/mozStorageAsyncStatementExecution.cpp215
-rw-r--r--storage/mozStorageAsyncStatementExecution.h13
-rw-r--r--toolkit/components/jsdownloads/src/DownloadIntegration.jsm31
34 files changed, 352 insertions, 218 deletions
diff --git a/browser/components/downloads/DownloadsCommon.jsm b/browser/components/downloads/DownloadsCommon.jsm
index b6684817d..90f14f2d8 100644
--- a/browser/components/downloads/DownloadsCommon.jsm
+++ b/browser/components/downloads/DownloadsCommon.jsm
@@ -42,6 +42,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
+ "resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
@@ -460,8 +462,12 @@ this.DownloadsCommon = {
throw new Error("aOwnerWindow must be a dom-window object");
}
+ let isWindowsExe = AppConstants.platform == "win" &&
+ aFile.leafName.toLowerCase().endsWith(".exe");
+
let promiseShouldLaunch;
- if (aFile.isExecutable()) {
+ // Don't prompt on Windows for .exe since there will be a native prompt.
+ if (aFile.isExecutable() && !isWindowsExe) {
// We get a prompter for the provided window here, even though anchoring
// to the most recently active window should work as well.
promiseShouldLaunch =
diff --git a/browser/components/extensions/ext-browserAction.js b/browser/components/extensions/ext-browserAction.js
index 407366e2c..2c82ac701 100644
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -497,6 +497,9 @@ extensions.registerSchemaAPI("browserAction", "addon_parent", context => {
// For internal consistency, we currently resolve both relative to the
// calling context.
let url = details.popup && context.uri.resolve(details.popup);
+ if (url && !context.checkLoadURL(url)) {
+ return Promise.reject({message: `Access denied for URL ${url}`});
+ }
BrowserAction.for(extension).setProperty(tab, "popup", url);
},
diff --git a/browser/components/extensions/ext-pageAction.js b/browser/components/extensions/ext-pageAction.js
index 153f05d7a..5bf3a9c70 100644
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -273,6 +273,9 @@ extensions.registerSchemaAPI("pageAction", "addon_parent", context => {
// For internal consistency, we currently resolve both relative to the
// calling context.
let url = details.popup && context.uri.resolve(details.popup);
+ if (url && !context.checkLoadURL(url)) {
+ return Promise.reject({message: `Access denied for URL ${url}`});
+ }
PageAction.for(extension).setProperty(tab, "popup", url);
},
diff --git a/browser/components/extensions/schemas/page_action.json b/browser/components/extensions/schemas/page_action.json
index f4f9ee8db..126378ca5 100644
--- a/browser/components/extensions/schemas/page_action.json
+++ b/browser/components/extensions/schemas/page_action.json
@@ -173,6 +173,7 @@
{
"name": "setPopup",
"type": "function",
+ "async": true,
"description": "Sets the html document to be opened as a popup when the user clicks on the page action's icon.",
"parameters": [
{
diff --git a/editor/libeditor/CompositionTransaction.cpp b/editor/libeditor/CompositionTransaction.cpp
index 25938fa60..bde53d2e5 100644
--- a/editor/libeditor/CompositionTransaction.cpp
+++ b/editor/libeditor/CompositionTransaction.cpp
@@ -33,7 +33,7 @@ CompositionTransaction::CompositionTransaction(
, mReplaceLength(aReplaceLength)
, mRanges(aTextRangeArray)
, mStringToInsert(aStringToInsert)
- , mEditorBase(aEditorBase)
+ , mEditorBase(&aEditorBase)
, mRangeUpdater(aRangeUpdater)
, mFixed(false)
{
@@ -45,6 +45,7 @@ CompositionTransaction::~CompositionTransaction()
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(CompositionTransaction, EditTransactionBase,
+ mEditorBase,
mTextNode)
// mRangeList can't lead to cycles
@@ -60,9 +61,13 @@ NS_IMPL_RELEASE_INHERITED(CompositionTransaction, EditTransactionBase)
NS_IMETHODIMP
CompositionTransaction::DoTransaction()
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
// Fail before making any changes if there's no selection controller
nsCOMPtr<nsISelectionController> selCon;
- mEditorBase.GetSelectionController(getter_AddRefs(selCon));
+ mEditorBase->GetSelectionController(getter_AddRefs(selCon));
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
// Advance caret: This requires the presentation shell to get the selection.
@@ -108,9 +113,13 @@ CompositionTransaction::DoTransaction()
NS_IMETHODIMP
CompositionTransaction::UndoTransaction()
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
// Get the selection first so we'll fail before making any changes if we
// can't get it
- RefPtr<Selection> selection = mEditorBase.GetSelection();
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
nsresult rv = mTextNode->DeleteData(mOffset, mStringToInsert.Length());
@@ -171,7 +180,10 @@ CompositionTransaction::GetTxnDescription(nsAString& aString)
nsresult
CompositionTransaction::SetSelectionForRanges()
{
- return SetIMESelection(mEditorBase, mTextNode, mOffset,
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ return SetIMESelection(*mEditorBase, mTextNode, mOffset,
mStringToInsert.Length(), mRanges);
}
diff --git a/editor/libeditor/CompositionTransaction.h b/editor/libeditor/CompositionTransaction.h
index acb3d8beb..c2134bedd 100644
--- a/editor/libeditor/CompositionTransaction.h
+++ b/editor/libeditor/CompositionTransaction.h
@@ -90,7 +90,7 @@ private:
nsString mStringToInsert;
// The editor, which is used to get the selection controller.
- EditorBase& mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
RangeUpdater* mRangeUpdater;
diff --git a/editor/libeditor/CreateElementTransaction.cpp b/editor/libeditor/CreateElementTransaction.cpp
index 5e4bd961c..5e2b9e1ad 100644
--- a/editor/libeditor/CreateElementTransaction.cpp
+++ b/editor/libeditor/CreateElementTransaction.cpp
@@ -50,6 +50,7 @@ CreateElementTransaction::~CreateElementTransaction()
NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTransaction,
EditTransactionBase,
+ mEditorBase,
mParent,
mNewNode,
mRefNode)
@@ -63,7 +64,9 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP
CreateElementTransaction::DoTransaction()
{
- MOZ_ASSERT(mEditorBase && mTag && mParent);
+ if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTag) || NS_WARN_IF(!mParent)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
mNewNode = mEditorBase->CreateHTMLContent(mTag);
NS_ENSURE_STATE(mNewNode);
@@ -106,7 +109,9 @@ CreateElementTransaction::DoTransaction()
NS_IMETHODIMP
CreateElementTransaction::UndoTransaction()
{
- MOZ_ASSERT(mEditorBase && mParent);
+ if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mParent)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
ErrorResult rv;
mParent->RemoveChild(*mNewNode, rv);
@@ -117,7 +122,9 @@ CreateElementTransaction::UndoTransaction()
NS_IMETHODIMP
CreateElementTransaction::RedoTransaction()
{
- MOZ_ASSERT(mEditorBase && mParent);
+ if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mParent)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
// First, reset mNewNode so it has no attributes or content
// XXX We never actually did this, we only cleared mNewNode's contents if it
diff --git a/editor/libeditor/CreateElementTransaction.h b/editor/libeditor/CreateElementTransaction.h
index 70fecceae..fd5abb8a8 100644
--- a/editor/libeditor/CreateElementTransaction.h
+++ b/editor/libeditor/CreateElementTransaction.h
@@ -57,7 +57,7 @@ protected:
virtual ~CreateElementTransaction();
// The document into which the new node will be inserted.
- EditorBase* mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
// The tag (mapping to object type) for the new element.
nsCOMPtr<nsIAtom> mTag;
diff --git a/editor/libeditor/DeleteNodeTransaction.cpp b/editor/libeditor/DeleteNodeTransaction.cpp
index 7f485b066..ae9951e28 100644
--- a/editor/libeditor/DeleteNodeTransaction.cpp
+++ b/editor/libeditor/DeleteNodeTransaction.cpp
@@ -23,6 +23,7 @@ DeleteNodeTransaction::~DeleteNodeTransaction()
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteNodeTransaction, EditTransactionBase,
+ mEditorBase,
mNode,
mParent,
mRefNode)
diff --git a/editor/libeditor/DeleteNodeTransaction.h b/editor/libeditor/DeleteNodeTransaction.h
index d0bc0dd46..369bbdf56 100644
--- a/editor/libeditor/DeleteNodeTransaction.h
+++ b/editor/libeditor/DeleteNodeTransaction.h
@@ -55,7 +55,7 @@ protected:
nsCOMPtr<nsIContent> mRefNode;
// The editor for this transaction.
- EditorBase* mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
// Range updater object.
RangeUpdater* mRangeUpdater;
diff --git a/editor/libeditor/DeleteRangeTransaction.cpp b/editor/libeditor/DeleteRangeTransaction.cpp
index 977de4873..16d2344ba 100644
--- a/editor/libeditor/DeleteRangeTransaction.cpp
+++ b/editor/libeditor/DeleteRangeTransaction.cpp
@@ -33,6 +33,7 @@ DeleteRangeTransaction::DeleteRangeTransaction()
NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteRangeTransaction,
EditAggregateTransaction,
+ mEditorBase,
mRange)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteRangeTransaction)
@@ -62,7 +63,9 @@ DeleteRangeTransaction::Init(EditorBase* aEditorBase,
NS_IMETHODIMP
DeleteRangeTransaction::DoTransaction()
{
- MOZ_ASSERT(mRange && mEditorBase);
+ if (NS_WARN_IF(!mRange) || NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
// build the child transactions
nsCOMPtr<nsINode> startParent = mRange->GetStartParent();
@@ -111,16 +114,18 @@ DeleteRangeTransaction::DoTransaction()
NS_IMETHODIMP
DeleteRangeTransaction::UndoTransaction()
{
- MOZ_ASSERT(mRange && mEditorBase);
-
+ if (NS_WARN_IF(!mRange) || NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
return EditAggregateTransaction::UndoTransaction();
}
NS_IMETHODIMP
DeleteRangeTransaction::RedoTransaction()
{
- MOZ_ASSERT(mRange && mEditorBase);
-
+ if (NS_WARN_IF(!mRange) || NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
return EditAggregateTransaction::RedoTransaction();
}
@@ -136,6 +141,10 @@ DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
int32_t aStartOffset,
int32_t aEndOffset)
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
// see what kind of node we have
if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
// if the node is a chardata node, then delete chardata content
@@ -185,6 +194,10 @@ DeleteRangeTransaction::CreateTxnsToDeleteContent(nsINode* aNode,
int32_t aOffset,
nsIEditor::EDirection aAction)
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
// see what kind of node we have
if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
// if the node is a chardata node, then delete chardata content
@@ -217,6 +230,10 @@ DeleteRangeTransaction::CreateTxnsToDeleteContent(nsINode* aNode,
nsresult
DeleteRangeTransaction::CreateTxnsToDeleteNodesBetween()
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
nsresult rv = iter->Init(mRange);
diff --git a/editor/libeditor/DeleteRangeTransaction.h b/editor/libeditor/DeleteRangeTransaction.h
index 9b60a5ba2..9bb4f520a 100644
--- a/editor/libeditor/DeleteRangeTransaction.h
+++ b/editor/libeditor/DeleteRangeTransaction.h
@@ -67,7 +67,7 @@ protected:
RefPtr<nsRange> mRange;
// The editor for this transaction.
- EditorBase* mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
// Range updater object.
RangeUpdater* mRangeUpdater;
diff --git a/editor/libeditor/DeleteTextTransaction.cpp b/editor/libeditor/DeleteTextTransaction.cpp
index 6de3181da..624aeaa3c 100644
--- a/editor/libeditor/DeleteTextTransaction.cpp
+++ b/editor/libeditor/DeleteTextTransaction.cpp
@@ -25,7 +25,7 @@ DeleteTextTransaction::DeleteTextTransaction(
uint32_t aOffset,
uint32_t aNumCharsToDelete,
RangeUpdater* aRangeUpdater)
- : mEditorBase(aEditorBase)
+ : mEditorBase(&aEditorBase)
, mCharData(&aCharData)
, mOffset(aOffset)
, mNumCharsToDelete(aNumCharsToDelete)
@@ -36,6 +36,7 @@ DeleteTextTransaction::DeleteTextTransaction(
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteTextTransaction, EditTransactionBase,
+ mEditorBase,
mCharData)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteTextTransaction)
@@ -45,7 +46,7 @@ nsresult
DeleteTextTransaction::Init()
{
// Do nothing if the node is read-only
- if (!mEditorBase.IsModifiableNode(mCharData)) {
+ if (NS_WARN_IF(!mEditorBase) || !mEditorBase->IsModifiableNode(mCharData)) {
return NS_ERROR_FAILURE;
}
@@ -55,7 +56,9 @@ DeleteTextTransaction::Init()
NS_IMETHODIMP
DeleteTextTransaction::DoTransaction()
{
- MOZ_ASSERT(mCharData);
+ if (NS_WARN_IF(!mCharData) || NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
// Get the text that we're about to delete
nsresult rv = mCharData->SubstringData(mOffset, mNumCharsToDelete,
@@ -69,8 +72,8 @@ DeleteTextTransaction::DoTransaction()
}
// Only set selection to deletion point if editor gives permission
- if (mEditorBase.GetShouldTxnSetSelection()) {
- RefPtr<Selection> selection = mEditorBase.GetSelection();
+ if (mEditorBase->GetShouldTxnSetSelection()) {
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
rv = selection->Collapse(mCharData, mOffset);
NS_ASSERTION(NS_SUCCEEDED(rv),
@@ -86,8 +89,9 @@ DeleteTextTransaction::DoTransaction()
NS_IMETHODIMP
DeleteTextTransaction::UndoTransaction()
{
- MOZ_ASSERT(mCharData);
-
+ if (NS_WARN_IF(!mCharData)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
return mCharData->InsertData(mOffset, mDeletedText);
}
diff --git a/editor/libeditor/DeleteTextTransaction.h b/editor/libeditor/DeleteTextTransaction.h
index 855d14349..0c8dafbc3 100644
--- a/editor/libeditor/DeleteTextTransaction.h
+++ b/editor/libeditor/DeleteTextTransaction.h
@@ -53,7 +53,7 @@ public:
protected:
// The provider of basic editing operations.
- EditorBase& mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
// The CharacterData node to operate upon.
RefPtr<nsGenericDOMDataNode> mCharData;
diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp
index 13505b2d3..b793f39b8 100644
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -466,6 +466,13 @@ EditorBase::PreDestroy(bool aDestroyingFrames)
mSpellcheckCheckboxState = eTriUnset;
mRootElement = nullptr;
+ // Transaction may grab this instance. Therefore, they should be released
+ // here for stopping the circular reference with this instance.
+ if (mTxnMgr) {
+ mTxnMgr->Clear();
+ mTxnMgr = nullptr;
+ }
+
mDidPreDestroy = true;
return NS_OK;
}
diff --git a/editor/libeditor/InsertNodeTransaction.cpp b/editor/libeditor/InsertNodeTransaction.cpp
index 6af33b74f..6317b8c15 100644
--- a/editor/libeditor/InsertNodeTransaction.cpp
+++ b/editor/libeditor/InsertNodeTransaction.cpp
@@ -28,7 +28,7 @@ InsertNodeTransaction::InsertNodeTransaction(nsIContent& aNode,
: mNode(&aNode)
, mParent(&aParent)
, mOffset(aOffset)
- , mEditorBase(aEditorBase)
+ , mEditorBase(&aEditorBase)
{
}
@@ -37,6 +37,7 @@ InsertNodeTransaction::~InsertNodeTransaction()
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertNodeTransaction, EditTransactionBase,
+ mEditorBase,
mNode,
mParent)
@@ -48,7 +49,9 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP
InsertNodeTransaction::DoTransaction()
{
- MOZ_ASSERT(mNode && mParent);
+ if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mNode) || NS_WARN_IF(!mParent)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
uint32_t count = mParent->GetChildCount();
if (mOffset > static_cast<int32_t>(count) || mOffset == -1) {
@@ -59,15 +62,15 @@ InsertNodeTransaction::DoTransaction()
// Note, it's ok for ref to be null. That means append.
nsCOMPtr<nsIContent> ref = mParent->GetChildAt(mOffset);
- mEditorBase.MarkNodeDirty(GetAsDOMNode(mNode));
+ mEditorBase->MarkNodeDirty(GetAsDOMNode(mNode));
ErrorResult rv;
mParent->InsertBefore(*mNode, ref, rv);
NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
// Only set selection to insertion point if editor gives permission
- if (mEditorBase.GetShouldTxnSetSelection()) {
- RefPtr<Selection> selection = mEditorBase.GetSelection();
+ if (mEditorBase->GetShouldTxnSetSelection()) {
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
// Place the selection just after the inserted element
selection->Collapse(mParent, mOffset + 1);
@@ -80,8 +83,9 @@ InsertNodeTransaction::DoTransaction()
NS_IMETHODIMP
InsertNodeTransaction::UndoTransaction()
{
- MOZ_ASSERT(mNode && mParent);
-
+ if (NS_WARN_IF(!mNode) || NS_WARN_IF(!mParent)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
ErrorResult rv;
mParent->RemoveChild(*mNode, rv);
return rv.StealNSResult();
diff --git a/editor/libeditor/InsertNodeTransaction.h b/editor/libeditor/InsertNodeTransaction.h
index 5af7b8aff..1b9739d6c 100644
--- a/editor/libeditor/InsertNodeTransaction.h
+++ b/editor/libeditor/InsertNodeTransaction.h
@@ -50,7 +50,7 @@ protected:
int32_t mOffset;
// The editor for this transaction.
- EditorBase& mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
};
} // namespace mozilla
diff --git a/editor/libeditor/InsertTextTransaction.cpp b/editor/libeditor/InsertTextTransaction.cpp
index 009b2d023..0434b2dd5 100644
--- a/editor/libeditor/InsertTextTransaction.cpp
+++ b/editor/libeditor/InsertTextTransaction.cpp
@@ -26,7 +26,7 @@ InsertTextTransaction::InsertTextTransaction(Text& aTextNode,
: mTextNode(&aTextNode)
, mOffset(aOffset)
, mStringToInsert(aStringToInsert)
- , mEditorBase(aEditorBase)
+ , mEditorBase(&aEditorBase)
, mRangeUpdater(aRangeUpdater)
{
}
@@ -36,6 +36,7 @@ InsertTextTransaction::~InsertTextTransaction()
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction, EditTransactionBase,
+ mEditorBase,
mTextNode)
NS_IMPL_ADDREF_INHERITED(InsertTextTransaction, EditTransactionBase)
@@ -50,12 +51,16 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP
InsertTextTransaction::DoTransaction()
{
+ if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert);
NS_ENSURE_SUCCESS(rv, rv);
// Only set selection to insertion point if editor gives permission
- if (mEditorBase.GetShouldTxnSetSelection()) {
- RefPtr<Selection> selection = mEditorBase.GetSelection();
+ if (mEditorBase->GetShouldTxnSetSelection()) {
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
DebugOnly<nsresult> rv =
selection->Collapse(mTextNode, mOffset + mStringToInsert.Length());
diff --git a/editor/libeditor/InsertTextTransaction.h b/editor/libeditor/InsertTextTransaction.h
index f97f20e37..b6867ad76 100644
--- a/editor/libeditor/InsertTextTransaction.h
+++ b/editor/libeditor/InsertTextTransaction.h
@@ -76,7 +76,7 @@ private:
nsString mStringToInsert;
// The editor, which we'll need to get the selection.
- EditorBase& mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
RangeUpdater* mRangeUpdater;
};
diff --git a/editor/libeditor/JoinNodeTransaction.cpp b/editor/libeditor/JoinNodeTransaction.cpp
index 228d1f4d6..50727cce1 100644
--- a/editor/libeditor/JoinNodeTransaction.cpp
+++ b/editor/libeditor/JoinNodeTransaction.cpp
@@ -21,7 +21,7 @@ using namespace dom;
JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase,
nsINode& aLeftNode,
nsINode& aRightNode)
- : mEditorBase(aEditorBase)
+ : mEditorBase(&aEditorBase)
, mLeftNode(&aLeftNode)
, mRightNode(&aRightNode)
, mOffset(0)
@@ -29,6 +29,7 @@ JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase,
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction, EditTransactionBase,
+ mEditorBase,
mLeftNode,
mRightNode,
mParent)
@@ -39,7 +40,8 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
nsresult
JoinNodeTransaction::CheckValidity()
{
- if (!mEditorBase.IsModifiableNode(mLeftNode->GetParentNode())) {
+ if (NS_WARN_IF(!mEditorBase) ||
+ !mEditorBase->IsModifiableNode(mLeftNode->GetParentNode())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@@ -50,6 +52,12 @@ JoinNodeTransaction::CheckValidity()
NS_IMETHODIMP
JoinNodeTransaction::DoTransaction()
{
+ if (NS_WARN_IF(!mEditorBase) ||
+ NS_WARN_IF(!mLeftNode) ||
+ NS_WARN_IF(!mRightNode)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
// Get the parent node
nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode();
NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER);
@@ -65,7 +73,7 @@ JoinNodeTransaction::DoTransaction()
mParent = leftParent;
mOffset = mLeftNode->Length();
- return mEditorBase.JoinNodesImpl(mRightNode, mLeftNode, mParent);
+ return mEditorBase->JoinNodesImpl(mRightNode, mLeftNode, mParent);
}
//XXX: What if instead of split, we just deleted the unneeded children of
@@ -73,7 +81,11 @@ JoinNodeTransaction::DoTransaction()
NS_IMETHODIMP
JoinNodeTransaction::UndoTransaction()
{
- MOZ_ASSERT(mParent);
+ if (NS_WARN_IF(!mParent) ||
+ NS_WARN_IF(!mRightNode) ||
+ NS_WARN_IF(!mLeftNode)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
// First, massage the existing node so it is in its post-split state
ErrorResult rv;
diff --git a/editor/libeditor/JoinNodeTransaction.h b/editor/libeditor/JoinNodeTransaction.h
index 84208cb45..827d9dfaf 100644
--- a/editor/libeditor/JoinNodeTransaction.h
+++ b/editor/libeditor/JoinNodeTransaction.h
@@ -47,7 +47,7 @@ public:
NS_DECL_EDITTRANSACTIONBASE
protected:
- EditorBase& mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
// The nodes to operate upon. After the merge, mRightNode remains and
// mLeftNode is removed from the content tree.
diff --git a/editor/libeditor/PlaceholderTransaction.cpp b/editor/libeditor/PlaceholderTransaction.cpp
index 1031b45ab..fa808afad 100644
--- a/editor/libeditor/PlaceholderTransaction.cpp
+++ b/editor/libeditor/PlaceholderTransaction.cpp
@@ -35,6 +35,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTransaction,
if (tmp->mStartSel) {
ImplCycleCollectionUnlink(*tmp->mStartSel);
}
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorBase);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSel);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -43,6 +44,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTransaction,
if (tmp->mStartSel) {
ImplCycleCollectionTraverse(cb, *tmp->mStartSel, "mStartSel", 0);
}
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorBase);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -76,6 +78,10 @@ PlaceholderTransaction::DoTransaction()
NS_IMETHODIMP
PlaceholderTransaction::UndoTransaction()
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
// Undo transactions.
nsresult rv = EditAggregateTransaction::UndoTransaction();
NS_ENSURE_SUCCESS(rv, rv);
@@ -91,6 +97,10 @@ PlaceholderTransaction::UndoTransaction()
NS_IMETHODIMP
PlaceholderTransaction::RedoTransaction()
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
// Redo transactions.
nsresult rv = EditAggregateTransaction::RedoTransaction();
NS_ENSURE_SUCCESS(rv, rv);
@@ -261,6 +271,10 @@ PlaceholderTransaction::Commit()
nsresult
PlaceholderTransaction::RememberEndingSelection()
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
mEndSel.SaveSelection(selection);
diff --git a/editor/libeditor/PlaceholderTransaction.h b/editor/libeditor/PlaceholderTransaction.h
index 867a82ce3..8193239be 100644
--- a/editor/libeditor/PlaceholderTransaction.h
+++ b/editor/libeditor/PlaceholderTransaction.h
@@ -84,7 +84,7 @@ protected:
SelectionState mEndSel;
// The editor for this transaction.
- EditorBase* mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
};
} // namespace mozilla
diff --git a/editor/libeditor/SplitNodeTransaction.cpp b/editor/libeditor/SplitNodeTransaction.cpp
index 113ff7a61..8965b5399 100644
--- a/editor/libeditor/SplitNodeTransaction.cpp
+++ b/editor/libeditor/SplitNodeTransaction.cpp
@@ -19,7 +19,7 @@ using namespace dom;
SplitNodeTransaction::SplitNodeTransaction(EditorBase& aEditorBase,
nsIContent& aNode,
int32_t aOffset)
- : mEditorBase(aEditorBase)
+ : mEditorBase(&aEditorBase)
, mExistingRightNode(&aNode)
, mOffset(aOffset)
{
@@ -30,6 +30,7 @@ SplitNodeTransaction::~SplitNodeTransaction()
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitNodeTransaction, EditTransactionBase,
+ mEditorBase,
mParent,
mNewLeftNode)
@@ -41,6 +42,10 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP
SplitNodeTransaction::DoTransaction()
{
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
// Create a new node
ErrorResult rv;
// Don't use .downcast directly because AsContent has an assertion we want
@@ -48,16 +53,16 @@ SplitNodeTransaction::DoTransaction()
NS_ASSERTION(!rv.Failed() && clone, "Could not create clone");
NS_ENSURE_TRUE(!rv.Failed() && clone, rv.StealNSResult());
mNewLeftNode = dont_AddRef(clone.forget().take()->AsContent());
- mEditorBase.MarkNodeDirty(mExistingRightNode->AsDOMNode());
+ mEditorBase->MarkNodeDirty(mExistingRightNode->AsDOMNode());
// Get the parent node
mParent = mExistingRightNode->GetParentNode();
NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
// Insert the new node
- rv = mEditorBase.SplitNodeImpl(*mExistingRightNode, mOffset, *mNewLeftNode);
- if (mEditorBase.GetShouldTxnSetSelection()) {
- RefPtr<Selection> selection = mEditorBase.GetSelection();
+ rv = mEditorBase->SplitNodeImpl(*mExistingRightNode, mOffset, *mNewLeftNode);
+ if (mEditorBase->GetShouldTxnSetSelection()) {
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
rv = selection->Collapse(mNewLeftNode, mOffset);
}
@@ -67,10 +72,14 @@ SplitNodeTransaction::DoTransaction()
NS_IMETHODIMP
SplitNodeTransaction::UndoTransaction()
{
- MOZ_ASSERT(mNewLeftNode && mParent);
+ if (NS_WARN_IF(!mEditorBase) ||
+ NS_WARN_IF(!mNewLeftNode) ||
+ NS_WARN_IF(!mParent)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
// This assumes Do inserted the new node in front of the prior existing node
- return mEditorBase.JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
+ return mEditorBase->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
}
/* Redo cannot simply resplit the right node, because subsequent transactions
@@ -80,7 +89,10 @@ SplitNodeTransaction::UndoTransaction()
NS_IMETHODIMP
SplitNodeTransaction::RedoTransaction()
{
- MOZ_ASSERT(mNewLeftNode && mParent);
+ if (NS_WARN_IF(!mNewLeftNode) ||
+ NS_WARN_IF(!mParent)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
ErrorResult rv;
// First, massage the existing node so it is in its post-split state
diff --git a/editor/libeditor/SplitNodeTransaction.h b/editor/libeditor/SplitNodeTransaction.h
index 36119518b..4c50143ec 100644
--- a/editor/libeditor/SplitNodeTransaction.h
+++ b/editor/libeditor/SplitNodeTransaction.h
@@ -49,7 +49,7 @@ public:
protected:
virtual ~SplitNodeTransaction();
- EditorBase& mEditorBase;
+ RefPtr<EditorBase> mEditorBase;
// The node to operate upon.
nsCOMPtr<nsIContent> mExistingRightNode;
diff --git a/editor/libeditor/StyleSheetTransactions.cpp b/editor/libeditor/StyleSheetTransactions.cpp
index 6a31a16e2..cf32898a9 100644
--- a/editor/libeditor/StyleSheetTransactions.cpp
+++ b/editor/libeditor/StyleSheetTransactions.cpp
@@ -57,6 +57,7 @@ AddStyleSheetTransaction::AddStyleSheetTransaction()
NS_IMPL_CYCLE_COLLECTION_INHERITED(AddStyleSheetTransaction,
EditTransactionBase,
+ mEditor,
mSheet)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AddStyleSheetTransaction)
@@ -111,6 +112,7 @@ RemoveStyleSheetTransaction::RemoveStyleSheetTransaction()
NS_IMPL_CYCLE_COLLECTION_INHERITED(RemoveStyleSheetTransaction,
EditTransactionBase,
+ mEditor,
mSheet)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RemoveStyleSheetTransaction)
diff --git a/editor/libeditor/StyleSheetTransactions.h b/editor/libeditor/StyleSheetTransactions.h
index bf615b263..d6855981b 100644
--- a/editor/libeditor/StyleSheetTransactions.h
+++ b/editor/libeditor/StyleSheetTransactions.h
@@ -36,7 +36,7 @@ public:
protected:
// The editor that created this transaction.
- nsIEditor* mEditor;
+ nsCOMPtr<nsIEditor> mEditor;
// The style sheet to add.
RefPtr<mozilla::StyleSheet> mSheet;
};
@@ -62,7 +62,7 @@ public:
protected:
// The editor that created this transaction.
- nsIEditor* mEditor;
+ nsCOMPtr<nsIEditor> mEditor;
// The style sheet to remove.
RefPtr<StyleSheet> mSheet;
diff --git a/js/src/jit-test/tests/debug/bug1353356.js b/js/src/jit-test/tests/debug/bug1353356.js
new file mode 100644
index 000000000..389bb7860
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1353356.js
@@ -0,0 +1,65 @@
+// |jit-test| allow-oom; --fuzzing-safe
+
+var lfLogBuffer = `
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-endofdata
+ setJitCompilerOption("ion.warmup.trigger", 4);
+ var g = newGlobal();
+ g.debuggeeGlobal = this;
+ g.eval("(" + function () {
+ dbg = new Debugger(debuggeeGlobal);
+ dbg.onExceptionUnwind = function (frame, exc) {
+ var s = '!';
+ for (var f = frame; f; f = f.older)
+ debuggeeGlobal.log += s;
+ };
+ } + ")();");
+ j('Number.prototype.toSource.call([])');
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-selectmode 4
+//corefuzz-dcd-endofdata
+}
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-selectmode 5
+//corefuzz-dcd-endofdata
+oomTest(() => i({
+ new : (true ),
+ thisprops: true
+}));
+`;
+lfLogBuffer = lfLogBuffer.split('\n');
+var lfRunTypeId = -1;
+var lfCodeBuffer = "";
+while (true) {
+ var line = lfLogBuffer.shift();
+ if (line == null) {
+ break;
+ } else if (line == "//corefuzz-dcd-endofdata") {
+ loadFile(lfCodeBuffer);
+ lfCodeBuffer = "";
+ loadFile(line);
+ } else {
+ lfCodeBuffer += line + "\n";
+ }
+}
+if (lfCodeBuffer) loadFile(lfCodeBuffer);
+function loadFile(lfVarx) {
+ try {
+ if (lfVarx.indexOf("//corefuzz-dcd-selectmode ") === 0) {
+ lfRunTypeId = parseInt(lfVarx.split(" ")[1]) % 6;
+ } else {
+ switch (lfRunTypeId) {
+ case 4:
+ oomTest(function() {
+ let m = parseModule(lfVarx);
+ });
+ break;
+ default:
+ evaluate(lfVarx);
+ }
+ }
+ } catch (lfVare) {}
+}
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index 7978d8dbc..439bb1ed4 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1517,11 +1517,7 @@ jit::JitActivation::getRematerializedFrame(JSContext* cx, const JitFrameIterator
uint8_t* top = iter.fp();
RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
if (!p) {
- RematerializedFrameVector empty(cx);
- if (!rematerializedFrames_->add(p, top, Move(empty))) {
- ReportOutOfMemory(cx);
- return nullptr;
- }
+ RematerializedFrameVector frames(cx);
// The unit of rematerialization is an uninlined frame and its inlined
// frames. Since inlined frames do not exist outside of snapshots, it
@@ -1536,9 +1532,11 @@ jit::JitActivation::getRematerializedFrame(JSContext* cx, const JitFrameIterator
// be in the activation's compartment.
AutoCompartment ac(cx, compartment_);
- if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover,
- p->value()))
- {
+ if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover, frames))
+ return nullptr;
+
+ if (!rematerializedFrames_->add(p, top, Move(frames))) {
+ ReportOutOfMemory(cx);
return nullptr;
}
diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp
index be7ddba8f..b24e01a40 100644
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -1007,12 +1007,16 @@ Module::instantiate(JSContext* cx,
maybeBytecode = bytecode_.get();
auto codeSegment = CodeSegment::create(cx, code_, linkData_, *metadata_, memory);
- if (!codeSegment)
+ if (!codeSegment) {
+ ReportOutOfMemory(cx);
return false;
+ }
auto code = cx->make_unique<Code>(Move(codeSegment), *metadata_, maybeBytecode);
- if (!code)
+ if (!code) {
+ ReportOutOfMemory(cx);
return false;
+ }
instance.set(WasmInstanceObject::create(cx,
Move(code),
diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp
index a1105ae52..782ac332c 100644
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -544,6 +544,12 @@ nsDocumentViewer::~nsDocumentViewer()
mDocument->Destroy();
}
+ if (mPrintEngine) {
+ mPrintEngine->Destroy();
+ mPrintEngine = nullptr;
+ }
+
+ MOZ_RELEASE_ASSERT(mDestroyRefCount == 0);
NS_ASSERTION(!mPresShell && !mPresContext,
"User did not call nsIContentViewer::Destroy");
if (mPresShell || mPresContext) {
diff --git a/storage/mozStorageAsyncStatementExecution.cpp b/storage/mozStorageAsyncStatementExecution.cpp
index add32131a..e1d344aca 100644
--- a/storage/mozStorageAsyncStatementExecution.cpp
+++ b/storage/mozStorageAsyncStatementExecution.cpp
@@ -40,122 +40,6 @@ namespace storage {
#define MAX_ROWS_PER_RESULT 15
////////////////////////////////////////////////////////////////////////////////
-//// Local Classes
-
-namespace {
-
-typedef AsyncExecuteStatements::ExecutionState ExecutionState;
-typedef AsyncExecuteStatements::StatementDataArray StatementDataArray;
-
-/**
- * Notifies a callback with a result set.
- */
-class CallbackResultNotifier : public Runnable
-{
-public:
- CallbackResultNotifier(mozIStorageStatementCallback *aCallback,
- mozIStorageResultSet *aResults,
- AsyncExecuteStatements *aEventStatus) :
- mCallback(aCallback)
- , mResults(aResults)
- , mEventStatus(aEventStatus)
- {
- }
-
- NS_IMETHOD Run() override
- {
- NS_ASSERTION(mCallback, "Trying to notify about results without a callback!");
-
- if (mEventStatus->shouldNotify()) {
- // Hold a strong reference to the callback while notifying it, so that if
- // it spins the event loop, the callback won't be released and freed out
- // from under us.
- nsCOMPtr<mozIStorageStatementCallback> callback = mCallback;
-
- (void)callback->HandleResult(mResults);
- }
-
- return NS_OK;
- }
-
-private:
- mozIStorageStatementCallback *mCallback;
- nsCOMPtr<mozIStorageResultSet> mResults;
- RefPtr<AsyncExecuteStatements> mEventStatus;
-};
-
-/**
- * Notifies the calling thread that an error has occurred.
- */
-class ErrorNotifier : public Runnable
-{
-public:
- ErrorNotifier(mozIStorageStatementCallback *aCallback,
- mozIStorageError *aErrorObj,
- AsyncExecuteStatements *aEventStatus) :
- mCallback(aCallback)
- , mErrorObj(aErrorObj)
- , mEventStatus(aEventStatus)
- {
- }
-
- NS_IMETHOD Run() override
- {
- if (mEventStatus->shouldNotify() && mCallback) {
- // Hold a strong reference to the callback while notifying it, so that if
- // it spins the event loop, the callback won't be released and freed out
- // from under us.
- nsCOMPtr<mozIStorageStatementCallback> callback = mCallback;
-
- (void)callback->HandleError(mErrorObj);
- }
-
- return NS_OK;
- }
-
-private:
- mozIStorageStatementCallback *mCallback;
- nsCOMPtr<mozIStorageError> mErrorObj;
- RefPtr<AsyncExecuteStatements> mEventStatus;
-};
-
-/**
- * Notifies the calling thread that the statement has finished executing. Takes
- * ownership of the StatementData so it is released on the proper thread.
- */
-class CompletionNotifier : public Runnable
-{
-public:
- /**
- * This takes ownership of the callback and the StatementData. They are
- * released on the thread this is dispatched to (which should always be the
- * calling thread).
- */
- CompletionNotifier(mozIStorageStatementCallback *aCallback,
- ExecutionState aReason)
- : mCallback(aCallback)
- , mReason(aReason)
- {
- }
-
- NS_IMETHOD Run() override
- {
- if (mCallback) {
- (void)mCallback->HandleCompletion(mReason);
- NS_RELEASE(mCallback);
- }
-
- return NS_OK;
- }
-
-private:
- mozIStorageStatementCallback *mCallback;
- ExecutionState mReason;
-};
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
//// AsyncExecuteStatements
/* static */
@@ -208,16 +92,19 @@ AsyncExecuteStatements::AsyncExecuteStatements(StatementDataArray &aStatements,
, mCancelRequested(false)
, mMutex(aConnection->sharedAsyncExecutionMutex)
, mDBMutex(aConnection->sharedDBMutex)
- , mRequestStartDate(TimeStamp::Now())
+, mRequestStartDate(TimeStamp::Now())
{
(void)mStatements.SwapElements(aStatements);
NS_ASSERTION(mStatements.Length(), "We weren't given any statements!");
- NS_IF_ADDREF(mCallback);
}
AsyncExecuteStatements::~AsyncExecuteStatements()
{
+ MOZ_ASSERT(!mCallback, "Never called the Completion callback!");
MOZ_ASSERT(!mHasTransaction, "There should be no transaction at this point");
+ if (mCallback) {
+ NS_ProxyRelease(mCallingThread, mCallback.forget());
+ }
}
bool
@@ -255,7 +142,7 @@ AsyncExecuteStatements::bindExecuteAndProcessStatement(StatementData &aData,
BindingParamsArray::iterator end = paramsArray->end();
while (itr != end && continueProcessing) {
// Bind the data to our statement.
- nsCOMPtr<IStorageBindingParamsInternal> bindingInternal =
+ nsCOMPtr<IStorageBindingParamsInternal> bindingInternal =
do_QueryInterface(*itr);
nsCOMPtr<mozIStorageError> error = bindingInternal->bind(aStatement);
if (error) {
@@ -462,16 +349,30 @@ AsyncExecuteStatements::notifyComplete()
mHasTransaction = false;
}
- // Always generate a completion notification; it is what guarantees that our
- // destruction does not happen here on the async thread.
- RefPtr<CompletionNotifier> completionEvent =
- new CompletionNotifier(mCallback, mState);
-
- // We no longer own mCallback (the CompletionNotifier takes ownership).
- mCallback = nullptr;
+ // This will take ownership of mCallback and make sure its destruction will
+ // happen on the owner thread.
+ Unused << mCallingThread->Dispatch(
+ NewRunnableMethod(this, &AsyncExecuteStatements::notifyCompleteOnCallingThread),
+ NS_DISPATCH_NORMAL);
- (void)mCallingThread->Dispatch(completionEvent, NS_DISPATCH_NORMAL);
+ return NS_OK;
+}
+nsresult
+AsyncExecuteStatements::notifyCompleteOnCallingThread() {
+#ifdef DEBUG
+ bool onCallingThread = false;
+ (void)mCallingThread->IsOnCurrentThread(&onCallingThread);
+ MOZ_ASSERT(onCallingThread);
+#endif
+ // Take ownership of mCallback and responsibility for freeing it when we
+ // release it. Any notifyResultsOnCallingThread and notifyErrorOnCallingThread
+ // calls on the stack spinning the event loop have guaranteed their safety by
+ // creating their own strong reference before invoking the callback.
+ nsCOMPtr<mozIStorageStatementCallback> callback = mCallback.forget();
+ if (callback) {
+ Unused << callback->HandleCompletion(mState);
+ }
return NS_OK;
}
@@ -500,27 +401,63 @@ AsyncExecuteStatements::notifyError(mozIStorageError *aError)
if (!mCallback)
return NS_OK;
- RefPtr<ErrorNotifier> notifier =
- new ErrorNotifier(mCallback, aError, this);
- NS_ENSURE_TRUE(notifier, NS_ERROR_OUT_OF_MEMORY);
+ Unused << mCallingThread->Dispatch(
+ NewRunnableMethod<nsCOMPtr<mozIStorageError>>(this, &AsyncExecuteStatements::notifyErrorOnCallingThread, aError),
+ NS_DISPATCH_NORMAL);
- return mCallingThread->Dispatch(notifier, NS_DISPATCH_NORMAL);
+ return NS_OK;
+}
+
+nsresult
+AsyncExecuteStatements::notifyErrorOnCallingThread(mozIStorageError *aError) {
+#ifdef DEBUG
+ bool onCallingThread = false;
+ (void)mCallingThread->IsOnCurrentThread(&onCallingThread);
+ MOZ_ASSERT(onCallingThread);
+#endif
+ // Acquire our own strong reference so that if the callback spins a nested
+ // event loop and notifyCompleteOnCallingThread is executed, forgetting
+ // mCallback, we still have a valid/strong reference that won't be freed until
+ // we exit.
+ nsCOMPtr<mozIStorageStatementCallback> callback = mCallback;
+ if (shouldNotify() && callback) {
+ Unused << callback->HandleError(aError);
+ }
+ return NS_OK;
}
nsresult
AsyncExecuteStatements::notifyResults()
{
mMutex.AssertNotCurrentThreadOwns();
- NS_ASSERTION(mCallback, "notifyResults called without a callback!");
+ MOZ_ASSERT(mCallback, "notifyResults called without a callback!");
- RefPtr<CallbackResultNotifier> notifier =
- new CallbackResultNotifier(mCallback, mResultSet, this);
- NS_ENSURE_TRUE(notifier, NS_ERROR_OUT_OF_MEMORY);
+ // This takes ownership of mResultSet, a new one will be generated in
+ // buildAndNotifyResults() when further results will arrive.
+ Unused << mCallingThread->Dispatch(
+ NewRunnableMethod<RefPtr<ResultSet>>(this, &AsyncExecuteStatements::notifyResultsOnCallingThread, mResultSet.forget()),
+ NS_DISPATCH_NORMAL);
- nsresult rv = mCallingThread->Dispatch(notifier, NS_DISPATCH_NORMAL);
- if (NS_SUCCEEDED(rv))
- mResultSet = nullptr; // we no longer own it on success
- return rv;
+ return NS_OK;
+}
+
+nsresult
+AsyncExecuteStatements::notifyResultsOnCallingThread(ResultSet *aResultSet)
+{
+#ifdef DEBUG
+ bool onCallingThread = false;
+ (void)mCallingThread->IsOnCurrentThread(&onCallingThread);
+ MOZ_ASSERT(onCallingThread);
+#endif
+ // Acquire our own strong reference so that if the callback spins a nested
+ // event loop and notifyCompleteOnCallingThread is executed, forgetting
+ // mCallback, we still have a valid/strong reference that won't be freed until
+ // we exit.
+ nsCOMPtr<mozIStorageStatementCallback> callback = mCallback;
+ if (shouldNotify() && callback) {
+ Unused << callback->HandleResult(aResultSet);
+ }
+ return NS_OK;
}
NS_IMPL_ISUPPORTS(
diff --git a/storage/mozStorageAsyncStatementExecution.h b/storage/mozStorageAsyncStatementExecution.h
index c8493fd77..14ea49c2d 100644
--- a/storage/mozStorageAsyncStatementExecution.h
+++ b/storage/mozStorageAsyncStatementExecution.h
@@ -82,6 +82,14 @@ public:
*/
bool shouldNotify();
+ /**
+ * Used by notifyComplete(), notifyError() and notifyResults() to notify on
+ * the calling thread.
+ */
+ nsresult notifyCompleteOnCallingThread();
+ nsresult notifyErrorOnCallingThread(mozIStorageError *aError);
+ nsresult notifyResultsOnCallingThread(ResultSet *aResultSet);
+
private:
AsyncExecuteStatements(StatementDataArray &aStatements,
Connection *aConnection,
@@ -186,7 +194,10 @@ private:
RefPtr<Connection> mConnection;
sqlite3 *mNativeConnection;
bool mHasTransaction;
- mozIStorageStatementCallback *mCallback;
+ // Note, this may not be a threadsafe object - never addref/release off
+ // the calling thread. We take a reference when this is created, and
+ // release it in the CompletionNotifier::Run() call back to this thread.
+ nsCOMPtr<mozIStorageStatementCallback> mCallback;
nsCOMPtr<nsIThread> mCallingThread;
RefPtr<ResultSet> mResultSet;
diff --git a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
index 5fed9212a..1d289c24d 100644
--- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
@@ -28,6 +28,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
"resource://gre/modules/AsyncShutdown.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
+ "resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
"resource://gre/modules/DeferredTask.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
@@ -675,20 +677,6 @@ this.DownloadIntegration = {
launchDownload: Task.async(function* (aDownload) {
let file = new FileUtils.File(aDownload.target.path);
-#ifndef XP_WIN
- // Ask for confirmation if the file is executable, except on Windows where
- // the operating system will show the prompt based on the security zone.
- // We do this here, instead of letting the caller handle the prompt
- // separately in the user interface layer, for two reasons. The first is
- // because of its security nature, so that add-ons cannot forget to do
- // this check. The second is that the system-level security prompt would
- // be displayed at launch time in any case.
- if (file.isExecutable() &&
- !(yield this.confirmLaunchExecutable(file.path))) {
- return;
- }
-#endif
-
// In case of a double extension, like ".tar.gz", we only
// consider the last one, because the MIME service cannot
// handle multiple extensions.
@@ -698,6 +686,21 @@ this.DownloadIntegration = {
fileExtension = match[1];
}
+ let isWindowsExe = AppConstants.platform == "win" &&
+ fileExtension.toLowerCase() == "exe";
+
+ // Ask for confirmation if the file is executable, except for .exe on
+ // Windows where the operating system will show the prompt based on the
+ // security zone. We do this here, instead of letting the caller handle
+ // the prompt separately in the user interface layer, for two reasons. The
+ // first is because of its security nature, so that add-ons cannot forget
+ // to do this check. The second is that the system-level security prompt
+ // would be displayed at launch time in any case.
+ if (file.isExecutable() && !isWindowsExe &&
+ !(await this.confirmLaunchExecutable(file.path))) {
+ return;
+ }
+
try {
// The MIME service might throw if contentType == "" and it can't find
// a MIME type for the given extension, so we'll treat this case as