diff --git a/build/unix/run-mozilla.sh b/build/unix/run-mozilla.sh index fbd9f7a8..2e407334 100644 --- a/build/unix/run-mozilla.sh +++ b/build/unix/run-mozilla.sh @@ -328,34 +328,34 @@ if [ -z "$MRE_HOME" ]; then fi ## ## Set LD_LIBRARY_PATH -LD_LIBRARY_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH+":$LD_LIBRARY_PATH"} +LD_LIBRARY_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"} if [ -n "$LD_LIBRARYN32_PATH" ] then - LD_LIBRARYN32_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARYN32_PATH+":$LD_LIBRARYN32_PATH"} + LD_LIBRARYN32_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARYN32_PATH:+":$LD_LIBRARYN32_PATH"} fi if [ -n "$LD_LIBRARYN64_PATH" ] then - LD_LIBRARYN64_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARYN64_PATH+":$LD_LIBRARYN64_PATH"} + LD_LIBRARYN64_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARYN64_PATH:+":$LD_LIBRARYN64_PATH"} fi if [ -n "$LD_LIBRARY_PATH_64" ]; then - LD_LIBRARY_PATH_64=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH_64+":$LD_LIBRARY_PATH_64"} + LD_LIBRARY_PATH_64=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH_64:+":$LD_LIBRARY_PATH_64"} fi # # ## Set SHLIB_PATH for HPUX -SHLIB_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${SHLIB_PATH+":$SHLIB_PATH"} +SHLIB_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${SHLIB_PATH:+":$SHLIB_PATH"} # ## Set LIBPATH for AIX -LIBPATH=${MOZ_DIST_BIN}:${MRE_HOME}${LIBPATH+":$LIBPATH"} +LIBPATH=${MOZ_DIST_BIN}:${MRE_HOME}${LIBPATH:+":$LIBPATH"} # ## Set DYLD_LIBRARY_PATH for Mac OS X (Darwin) -DYLD_LIBRARY_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${DYLD_LIBRARY_PATH+":$DYLD_LIBRARY_PATH"} +DYLD_LIBRARY_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${DYLD_LIBRARY_PATH:+":$DYLD_LIBRARY_PATH"} # ## Set LIBRARY_PATH for BeOS -LIBRARY_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/components:${MRE_HOME}${LIBRARY_PATH+":$LIBRARY_PATH"} +LIBRARY_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/components:${MRE_HOME}${LIBRARY_PATH:+":$LIBRARY_PATH"} # ## Set ADDON_PATH for BeOS -ADDON_PATH=${MOZ_DIST_BIN}${ADDON_PATH+":$ADDON_PATH"} +ADDON_PATH=${MOZ_DIST_BIN}${ADDON_PATH:+":$ADDON_PATH"} # ## Solaris Xserver(Xsun) tuning - use shared memory transport if available if [ "$XSUNTRANSPORT" = "" ] diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 7bdbb8d7..f4290bf2 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -81,6 +81,7 @@ class nsIJSRuntimeService; class nsIScriptGlobalObject; struct JSRuntime; class nsPIDOMWindow; +class nsPIDOMEventTarget; #ifdef MOZ_XTF class nsIXTFService; #endif @@ -706,6 +707,9 @@ public: ~nsCxPusher() { Pop(); } // Returns PR_FALSE if something erroneous happened. PRBool Push(nsISupports *aCurrentTarget); + // If nothing has been pushed to stack, this works like Push. + // Otherwise if context will change, Pop and Push will be called. + PRBool RePush(nsISupports *aCurrentTarget); void Pop(); private: diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 69688013..5e1bbad1 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -997,7 +997,7 @@ nsContentUtils::ReparentContentWrappersInScope(nsIScriptGlobalObject *aOldScope, NS_ERROR("Weird things are happening in XPConnect"); return NS_ERROR_FAILURE; } - return xpconnect18->ReparentScopeAwareWrappers(cx, oldScopeObj, newScopeObj); + return xpconnect18->MoveWrappers(cx, oldScopeObj, newScopeObj); } nsIDocShell * @@ -2395,6 +2395,47 @@ nsCxPusher::Push(nsISupports *aCurrentTarget) return PR_TRUE; } +PRBool +nsCxPusher::RePush(nsISupports *aCurrentTarget) +{ + if (!mScx) { + return Push(aCurrentTarget); + } + + if (aCurrentTarget) { + nsIScriptContext* scx = nsnull; + nsCOMPtr sgo; + nsCOMPtr content(do_QueryInterface(aCurrentTarget)); + + if (content) { + nsCOMPtr ownerDoc = content->GetOwnerDoc(); + if (ownerDoc) { + nsCOMPtr branch3doc = + do_QueryInterface(ownerDoc); + NS_ASSERTION(branch3doc, + "Document must implement nsIDocument_MOZILLA_1_8_BRANCH3!!!"); + PRBool hasHadScriptObject = PR_TRUE; + sgo = branch3doc->GetScriptHandlingObject(hasHadScriptObject); + } + } else { + sgo = do_QueryInterface(aCurrentTarget); + } + + if (sgo) { + scx = sgo->GetContext(); + // If we have the same script context and native context is still + // alive, no need to Pop/Push. + if (scx && scx == mScx && + scx->GetNativeContext()) { + return PR_TRUE; + } + } + } + + Pop(); + return Push(aCurrentTarget); +} + void nsCxPusher::Pop() { diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 191726e3..3c622400 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -3710,13 +3710,9 @@ nsDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) NS_IMETHODIMP nsDocument::Normalize() { - PRInt32 count = mChildren.ChildCount(); - for (PRInt32 i = 0; i < count; ++i) { + for (PRInt32 i = 0; i < mChildren.ChildCount(); ++i) { nsCOMPtr node(do_QueryInterface(mChildren.ChildAt(i))); - - if (node) { - node->Normalize(); - } + node->Normalize(); } return NS_OK; diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index 530197a6..7461a6fb 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -235,7 +235,9 @@ nsFrameLoader::Destroy() // Let our window know that we are gone nsCOMPtr win_private(do_GetInterface(mDocShell)); if (win_private) { + nsIDOMElement* frameElement = win_private->GetFrameElementInternal(); win_private->SetFrameElementInternal(nsnull); + NS_IF_RELEASE(frameElement); } nsCOMPtr base_win(do_QueryInterface(mDocShell)); @@ -402,7 +404,11 @@ nsFrameLoader::EnsureDocShell() nsCOMPtr win_private(do_GetInterface(mDocShell)); NS_ENSURE_TRUE(win_private, NS_ERROR_UNEXPECTED); + nsIDOMElement* oldFrame = win_private->GetFrameElementInternal(); win_private->SetFrameElementInternal(frame_element); + nsIDOMElement* fe = frame_element.get(); + NS_ADDREF(fe); + NS_IF_RELEASE(oldFrame); nsCOMPtr base_win(do_QueryInterface(mDocShell)); NS_ENSURE_TRUE(base_win, NS_ERROR_UNEXPECTED); diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 4562fd0f..c44420e3 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -2797,15 +2797,16 @@ doInsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify, NS_PRECONDITION(!aParent || aParent->GetCurrentDoc() == aDocument, "Incorrect aDocument"); + nsMutationGuard::DidMutate(); + + // Do this before checking the child-count since this could cause mutations + mozAutoDocUpdate updateBatch(aDocument, UPDATE_CONTENT_MODEL, aNotify); + PRUint32 childCount = aChildArray.ChildCount(); NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE); - nsMutationGuard::DidMutate(); - PRBool isAppend = (aIndex == childCount); - mozAutoDocUpdate updateBatch(aDocument, UPDATE_CONTENT_MODEL, aNotify); - // Note that SetRootContent already deals with binding, so if we plan to call // it we shouldn't bind ourselves. // XXXbz this doesn't put aKid in the right spot, really... We really need a diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index 2a4bd545..a9c86230 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -1645,11 +1645,7 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct, } } - // nsCxPusher will push and pop (automatically) the current cx onto the - // context stack - nsCxPusher pusher; - - if (NS_SUCCEEDED(result) && pusher.Push(aCurrentTarget)) { + if (NS_SUCCEEDED(result)) { nsCOMPtr aPrivDOMEvent(do_QueryInterface(aDOMEvent)); aPrivDOMEvent->SetCurrentTarget(aCurrentTarget); result = aListener->HandleEvent(aDOMEvent); @@ -1727,6 +1723,7 @@ nsEventListenerManager::HandleEvent(nsPresContext* aPresContext, } if (NS_SUCCEEDED(ret)) { + nsCxPusher pusher; PRInt32 count = listeners->Count(); nsVoidArray originalListeners(count); originalListeners = *listeners; @@ -1746,14 +1743,17 @@ nsEventListenerManager::HandleEvent(nsPresContext* aPresContext, if (eventListener) { // Try the type-specific listener interface PRBool hasInterface = PR_FALSE; - if (typeData) + if (typeData) { + pusher.Pop(); DispatchToInterface(*aDOMEvent, eventListener, dispData->method, *typeData->iid, &hasInterface); + } // If it doesn't implement that, call the generic HandleEvent() - if (!hasInterface && (ls->mSubType == NS_EVENT_BITS_NONE || - ls->mSubType & dispData->bits)) { + if (!hasInterface && + (ls->mSubType == NS_EVENT_BITS_NONE || ls->mSubType & dispData->bits) && + pusher.RePush(aCurrentTarget)) { HandleEventSubType(ls, eventListener, *aDOMEvent, aCurrentTarget, dispData ? dispData->bits : NS_EVENT_BITS_NONE, aFlags); diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 70e082a8..853b78ea 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -2100,7 +2100,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext, } nsIFrame* currFrame = mCurrentTarget; - nsIContent* activeContent = nsnull; + nsCOMPtr activeContent; if (mCurrentTarget) activeContent = mCurrentTarget->GetContent(); diff --git a/content/html/content/public/nsIFrameSetElement.h b/content/html/content/public/nsIFrameSetElement.h index 9cf3632e..0ddce3f1 100644 --- a/content/html/content/public/nsIFrameSetElement.h +++ b/content/html/content/public/nsIFrameSetElement.h @@ -65,6 +65,12 @@ struct nsFramesetSpec { nscoord mValue; }; +/** + * The maximum number of entries allowed in the frame set element row + * or column spec. + */ +#define NS_MAX_FRAMESET_SPEC_COUNT 16000 + /** * This interface is used by the nsFramesetFrame to access the parsed * values of the "rows" and "cols" attributes diff --git a/content/html/content/src/nsHTMLFrameSetElement.cpp b/content/html/content/src/nsHTMLFrameSetElement.cpp index 5ba3b876..7353c78a 100644 --- a/content/html/content/src/nsHTMLFrameSetElement.cpp +++ b/content/html/content/src/nsHTMLFrameSetElement.cpp @@ -43,6 +43,7 @@ #include "nsIFrameSetElement.h" #include "nsIHTMLDocument.h" #include "nsIDocument.h" +#include "nspr.h" class nsHTMLFrameSetElement : public nsGenericHTMLElement, public nsIDOMHTMLFrameSetElement, @@ -312,10 +313,11 @@ nsHTMLFrameSetElement::ParseRowCol(const nsAString & aValue, spec.StripChars(" \n\r\t\"\'"); spec.Trim(","); - // Count the commas + // Count the commas. Don't count more than X commas (bug 576447). + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT * sizeof(nsFramesetSpec) < (1 << 30)); PRInt32 commaX = spec.FindChar(sComma); PRInt32 count = 1; - while (commaX != kNotFound) { + while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) { count++; commaX = spec.FindChar(sComma, commaX + 1); } diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index cec77869..c590f2a9 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -2944,8 +2944,13 @@ nsHTMLDocument::GetSelection(nsAString& aReturn) consoleService->LogStringMessage(NS_LITERAL_STRING("Deprecated method document.getSelection() called. Please use window.getSelection() instead.").get()); } - nsIDOMWindow *window = GetWindow(); - NS_ENSURE_TRUE(window, NS_OK); + nsCOMPtr window = do_QueryInterface(GetScopeObject()); + nsCOMPtr pwin = do_QueryInterface(window); + NS_ENSURE_TRUE(pwin, NS_OK); + NS_ASSERTION(pwin->IsInnerWindow(), "Should have inner window here!"); + NS_ENSURE_TRUE(pwin->GetOuterWindow() && + pwin->GetOuterWindow()->GetCurrentInnerWindow() == pwin, + NS_OK); nsCOMPtr selection; nsresult rv = window->GetSelection(getter_AddRefs(selection)); diff --git a/content/xbl/src/nsBindingManager.cpp b/content/xbl/src/nsBindingManager.cpp index 8cbcf555..555db8fd 100644 --- a/content/xbl/src/nsBindingManager.cpp +++ b/content/xbl/src/nsBindingManager.cpp @@ -383,6 +383,9 @@ nsBindingManager::SetBinding(nsIContent* aContent, nsXBLBinding* aBinding) SetWrappedJS(aContent, nsnull); SetContentListFor(aContent, nsnull); SetAnonymousNodesFor(aContent, nsnull); + if (oldBinding) { + oldBinding->SetBoundElement(nsnull); + } } return result ? NS_OK : NS_ERROR_FAILURE; diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index 01e3158d..ccbcaebe 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -1217,7 +1217,7 @@ nsXBLBinding::AllowScripts() return PR_FALSE; } - nsIDocument* doc = mBoundElement->GetOwnerDoc(); + nsIDocument* doc = mBoundElement ? mBoundElement->GetOwnerDoc() : nsnull; if (!doc) { return PR_FALSE; } diff --git a/content/xul/document/src/nsXULCommandDispatcher.cpp b/content/xul/document/src/nsXULCommandDispatcher.cpp index 50c93173..fc63ecbd 100644 --- a/content/xul/document/src/nsXULCommandDispatcher.cpp +++ b/content/xul/document/src/nsXULCommandDispatcher.cpp @@ -383,6 +383,8 @@ nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName) free(actionString); } #endif + + nsCOMArray updaters; for (Updater* updater = mUpdaters; updater != nsnull; updater = updater->mNext) { nsCOMPtr element; @@ -401,6 +403,12 @@ nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName) NS_ASSERTION(content != nsnull, "not an nsIContent"); if (! content) return NS_ERROR_UNEXPECTED; + + updaters.AppendObject(content); + } + + for (PRUint32 u = 0; u < updaters.Count(); u++) { + nsIContent* content = updaters[u]; nsCOMPtr document = content->GetDocument(); @@ -414,7 +422,7 @@ nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName) CopyUTF16toUTF8(aEventName, aeventnameC); PR_LOG(gLog, PR_LOG_NOTICE, ("xulcmd[%p] update %p event=%s", - this, element.get(), + this, content, aeventnameC.get())); } #endif @@ -500,4 +508,3 @@ nsXULCommandDispatcher::SetSuppressFocusScroll(PRBool aSuppressFocusScroll) return mFocusController->SetSuppressFocusScroll(aSuppressFocusScroll); } - diff --git a/content/xul/templates/src/Makefile.in b/content/xul/templates/src/Makefile.in index fd635862..c8c04ca3 100644 --- a/content/xul/templates/src/Makefile.in +++ b/content/xul/templates/src/Makefile.in @@ -96,7 +96,8 @@ FORCE_STATIC_LIB = 1 include $(topsrcdir)/config/rules.mk LOCAL_INCLUDES = -I$(srcdir)/../../../base/src \ - -I$(srcdir)/../../content/src \ - $(NULL) + -I$(srcdir)/../../content/src \ + -I$(srcdir)/../../../../layout/xul/base/src/tree/src \ + $(NULL) DEFINES += -D_IMPL_NS_LAYOUT diff --git a/content/xul/templates/src/nsXULTreeBuilder.cpp b/content/xul/templates/src/nsXULTreeBuilder.cpp index 1ef43384..455f3b29 100644 --- a/content/xul/templates/src/nsXULTreeBuilder.cpp +++ b/content/xul/templates/src/nsXULTreeBuilder.cpp @@ -72,6 +72,8 @@ #include "nsUnicharUtils.h" #include "nsINameSpaceManager.h" #include "nsIDOMClassInfo.h" +#include "nsTreeContentView.h" +#include "nsDOMError.h" // For security check #include "nsIDocument.h" @@ -482,6 +484,9 @@ nsXULTreeBuilder::GetSelection(nsITreeSelection** aSelection) NS_IMETHODIMP nsXULTreeBuilder::SetSelection(nsITreeSelection* aSelection) { + NS_ENSURE_TRUE(!aSelection || + nsTreeContentView::CanTrustTreeSelection(aSelection), + NS_ERROR_DOM_SECURITY_ERR); mSelection = aSelection; return NS_OK; } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 54474d16..438da45e 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -56,6 +56,7 @@ #include "nsPIDOMStorage.h" #include "nsIDocumentViewer.h" #include "nsIDocumentLoaderFactory.h" +#include "nsIJARURI.h" #include "nsCURILoader.h" #include "nsDocShellCID.h" #include "nsLayoutCID.h" @@ -639,6 +640,7 @@ nsDocShell::LoadURI(nsIURI * aURI, nsCOMPtr headersStream; nsCOMPtr owner; PRBool inheritOwner = PR_FALSE; + PRBool ownerIsExplicit = PR_FALSE; PRBool sendReferrer = PR_TRUE; nsCOMPtr shEntry; nsXPIDLString target; @@ -662,6 +664,12 @@ nsDocShell::LoadURI(nsIURI * aURI, aLoadInfo->GetPostDataStream(getter_AddRefs(postStream)); aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream)); aLoadInfo->GetSendReferrer(&sendReferrer); + + nsCOMPtr info19 = + do_QueryInterface(aLoadInfo); + if (info19) { + info19->GetOwnerIsExplicit(&ownerIsExplicit); + } } #if defined(PR_LOGGING) && defined(DEBUG) @@ -774,81 +782,98 @@ nsDocShell::LoadURI(nsIURI * aURI, ("nsDocShell[%p]: loading from session history", this)); #endif - rv = LoadHistoryEntry(shEntry, loadType); + return LoadHistoryEntry(shEntry, loadType); } - // Perform the load... - else { - // We need an owner (a referring principal). 4 possibilities: - // (1) If the system principal was passed in and we're a typeContent - // docshell, inherit the principal from the current document - // instead. - // (2) In all other cases when the principal passed in is not null, - // use that principal. - // (3) If the caller has allowed inheriting from the current - // document, or if we're being called from chrome (if there's - // system JS on the stack), then inheritOwner should be true and - // InternalLoad will get an owner from the current document. If - // none of these things are true, then - // (4) we pass a null owner into the channel, and an owner will be - // created later from the channel's internal data. - nsCOMPtr secMan = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - // Just to compare, not to use! - nsCOMPtr sysPrin; - rv = secMan->GetSystemPrincipal(getter_AddRefs(sysPrin)); - NS_ENSURE_SUCCESS(rv, rv); - - if (owner == sysPrin && mItemType != typeChrome) { + // Perform the load... + + // We need an owner (a referring principal). + // + // If ownerIsExplicit is not set there are 4 possibilities: + // (1) If the system principal was passed in and we're a typeContent + // docshell, inherit the principal from the current document + // instead. + // (2) In all other cases when the principal passed in is not null, + // use that principal. + // (3) If the caller has allowed inheriting from the current document, + // or if we're being called from system code (eg chrome JS or pure + // C++) then inheritOwner should be true and InternalLoad will get + // an owner from the current document. If none of these things are + // true, then + // (4) we pass a null owner into the channel, and an owner will be + // created later from the channel's internal data. + // + // If ownerIsExplicit *is* set, there are 4 possibilities + // (1) If the system principal was passed in and we're a typeContent + // docshell, return an error. + // (2) In all other cases when the principal passed in is not null, + // use that principal. + // (3) If the caller has allowed inheriting from the current document, + // then inheritOwner should be true and InternalLoad will get an owner + // from the current document. If none of these things are true, then + // (4) we pass a null owner into the channel, and an owner will be + // created later from the channel's internal data. + // + // NOTE: This all only works because the only thing the owner is used + // for in InternalLoad is data:, javascript:, and about:blank + // URIs. For other URIs this would all be dead wrong! + + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr sysPrin; + rv = secMan->GetSystemPrincipal(getter_AddRefs(sysPrin)); + NS_ENSURE_SUCCESS(rv, rv); + + if (owner && mItemType != typeChrome) { + nsCOMPtr ownerPrincipal = do_QueryInterface(owner); + PRBool isSystem = ownerPrincipal == sysPrin; + + if (isSystem) { + if (ownerIsExplicit) { + return NS_ERROR_DOM_SECURITY_ERR; + } owner = nsnull; inheritOwner = PR_TRUE; } - else if (!owner && !inheritOwner) { - // See if there's system or chrome JS code running - if (NS_SUCCEEDED(rv)) { - nsCOMPtr subjectPrin; - - rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrin)); - // If there's no subject principal, there's no JS running, so - // we're in system code. - if (NS_SUCCEEDED(rv) && - (!subjectPrin || sysPrin == subjectPrin)) { - inheritOwner = PR_TRUE; - } - } + } + if (!owner && !inheritOwner && !ownerIsExplicit) { + // See if there's system or chrome JS code running + rv = secMan->SubjectPrincipalIsSystem(&inheritOwner); + if (NS_FAILED(rv)) { + // Set it back to false + inheritOwner = PR_FALSE; } - - PRUint32 flags = 0; - - if (inheritOwner) - flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER; - - if (!sendReferrer) - flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; - - if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) - flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; - - if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) - flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; - - rv = InternalLoad(aURI, - referrer, - owner, - flags, - target.get(), - nsnull, // No type hint - postStream, - headersStream, - loadType, - nsnull, // No SHEntry - aFirstParty, - nsnull, // No nsIDocShell - nsnull); // No nsIRequest } - return rv; + PRUint32 flags = 0; + + if (inheritOwner) + flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER; + + if (!sendReferrer) + flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; + + if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) + flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; + + if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) + flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; + + return InternalLoad(aURI, + referrer, + owner, + flags, + target.get(), + nsnull, // No type hint + postStream, + headersStream, + loadType, + nsnull, // No SHEntry + aFirstParty, + nsnull, // No nsIDocShell + nsnull); // No nsIRequest } NS_IMETHODIMP @@ -3314,6 +3339,12 @@ nsDocShell::Reload(PRUint32 aReloadFlags) NS_IMETHODIMP nsDocShell::Stop(PRUint32 aStopFlags) { + if (mLoadType == LOAD_ERROR_PAGE && mLSHE) { + // Since error page loads never unset mLSHE, do so now + SetHistoryEntry(&mOSHE, mLSHE); + SetHistoryEntry(&mLSHE, nsnull); + } + if (nsIWebNavigation::STOP_CONTENT & aStopFlags) { // Revoke any pending plevents related to content viewer restoration nsCOMPtr uiThreadQueue; @@ -4495,6 +4526,25 @@ nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI, rv = securityManager->CheckLoadURI(aBaseURI, uri, nsIScriptSecurityManager:: DISALLOW_FROM_MAIL); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr innerURI = uri; + nsCOMPtr jarURI(do_QueryInterface(innerURI)); + while (jarURI) { + jarURI->GetJARFile(getter_AddRefs(innerURI)); + jarURI = do_QueryInterface(innerURI); + } + NS_ENSURE_TRUE(innerURI, NS_ERROR_FAILURE); + + PRBool isjs = PR_TRUE; + rv = innerURI->SchemeIs("javascript", &isjs); + NS_ENSURE_SUCCESS(rv, rv); + + if (isjs) { + return NS_ERROR_FAILURE; + } + } + if (NS_SUCCEEDED(rv)) { // Since we can't travel back in time yet, just pretend // negative numbers do nothing at all. @@ -4831,6 +4881,12 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel, return; // nothing to tell anybody about AddToGlobalHistory(oldURI, PR_TRUE, aOldChannel); } + + if (!(aStateFlags & nsIChannelEventSink::REDIRECT_INTERNAL) && + mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) { + mLoadType = LOAD_NORMAL_REPLACE; + SetHistoryEntry(&mLSHE, nsnull); + } } NS_IMETHODIMP @@ -8781,6 +8837,7 @@ NS_INTERFACE_MAP_BEGIN(nsRefreshTimer) NS_INTERFACE_MAP_ENTRY(nsITimerCallback) NS_INTERFACE_MAP_END_THREADSAFE + ///***************************************************************************** // nsRefreshTimer::nsITimerCallback //***************************************************************************** @@ -8820,46 +8877,46 @@ nsRefreshTimer::Notify(nsITimer * aTimer) */ loadInfo->SetReferrer(currURI); + /* Don't ever "guess" on which owner to use to avoid picking + * the current owner. + */ + nsCOMPtr info19 = + do_QueryInterface(loadInfo); + NS_ENSURE_TRUE(info19, NS_ERROR_NO_INTERFACE); + info19->SetOwnerIsExplicit(PR_TRUE); + /* Check if this META refresh causes a redirection - * to another site. + * to another site. */ PRBool equalUri = PR_FALSE; nsresult rv = mURI->Equals(currURI, &equalUri); - if (NS_SUCCEEDED(rv) && (!equalUri) && mMetaRefresh) { + if (NS_SUCCEEDED(rv) && (!equalUri) && mMetaRefresh && + mDelay <= REFRESH_REDIRECT_TIMER) { - /* It is a META refresh based redirection. Now check if it happened within - * the threshold time we have in mind(15000 ms as defined by REFRESH_REDIRECT_TIMER). - * If so, pass a REPLACE flag to LoadURI(). + /* It is a META refresh based redirection within the threshold time + * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER). + * Pass a REPLACE flag to LoadURI(). */ - if (delay <= REFRESH_REDIRECT_TIMER) { - loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace); - - /* for redirects we mimic HTTP, which passes the - * original referrer - */ - nsCOMPtr internalReferrer; - nsCOMPtr webNav = - do_QueryInterface(mDocShell); - if (webNav) { - webNav->GetReferringURI(getter_AddRefs(internalReferrer)); - if (internalReferrer) { - loadInfo->SetReferrer(internalReferrer); - } - } + loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace); + + /* for redirects we mimic HTTP, which passes the + * original referrer + */ + nsCOMPtr internalReferrer; + + webNav->GetReferringURI(getter_AddRefs(internalReferrer)); + if (internalReferrer) { + loadInfo->SetReferrer(internalReferrer); } - else - loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh); - /* - * LoadURL(...) will cancel all refresh timers... This causes the Timer and - * its refreshData instance to be released... - */ - mDocShell->LoadURI(mURI, loadInfo, - nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE); - return NS_OK; - } - else + else { loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh); + } + + /* + * LoadURI(...) will cancel all refresh timers... This causes the + * Timer and its refreshData instance to be released... + */ mDocShell->LoadURI(mURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE); } return NS_OK; diff --git a/docshell/base/nsDocShellEnumerator.cpp b/docshell/base/nsDocShellEnumerator.cpp index 2eb60d3d..31afabab 100644 --- a/docshell/base/nsDocShellEnumerator.cpp +++ b/docshell/base/nsDocShellEnumerator.cpp @@ -43,16 +43,15 @@ nsDocShellEnumerator::nsDocShellEnumerator(PRInt32 inEnumerationDirection) : mRootItem(nsnull) -, mItemArray(nsnull) , mCurIndex(0) , mDocShellType(nsIDocShellTreeItem::typeAll) +, mArrayValid(PR_FALSE) , mEnumerationDirection(inEnumerationDirection) { } nsDocShellEnumerator::~nsDocShellEnumerator() { - delete mItemArray; } NS_IMPL_ISUPPORTS1(nsDocShellEnumerator, nsISimpleEnumerator) @@ -66,19 +65,15 @@ NS_IMETHODIMP nsDocShellEnumerator::GetNext(nsISupports **outCurItem) nsresult rv = EnsureDocShellArray(); if (NS_FAILED(rv)) return rv; - - if (mCurIndex >= 0 && mCurIndex < mItemArray->Count()) - { - nsIDocShellTreeItem* thisItem = NS_REINTERPRET_CAST(nsIDocShellTreeItem*, mItemArray->ElementAt(mCurIndex)); - rv = thisItem->QueryInterface(NS_GET_IID(nsISupports), (void **)outCurItem); - if (NS_FAILED(rv)) return rv; - } - else + + if (mCurIndex >= mItemArray.Length()) { return NS_ERROR_FAILURE; - - mCurIndex ++; - - return NS_OK; + } + + // post-increment is important here + nsCOMPtr item = do_QueryReferent(mItemArray[mCurIndex++], &rv); + item.forget(outCurItem); + return rv; } /* boolean hasMoreElements (); */ @@ -90,21 +85,21 @@ NS_IMETHODIMP nsDocShellEnumerator::HasMoreElements(PRBool *outHasMore) nsresult rv = EnsureDocShellArray(); if (NS_FAILED(rv)) return rv; - *outHasMore = (mCurIndex < mItemArray->Count()); + *outHasMore = (mCurIndex < mItemArray.Length()); return NS_OK; } nsresult nsDocShellEnumerator::GetEnumerationRootItem(nsIDocShellTreeItem * *aEnumerationRootItem) { NS_ENSURE_ARG_POINTER(aEnumerationRootItem); - *aEnumerationRootItem = mRootItem; - NS_IF_ADDREF(*aEnumerationRootItem); + nsCOMPtr item = do_QueryReferent(mRootItem); + item.forget(aEnumerationRootItem); return NS_OK; } nsresult nsDocShellEnumerator::SetEnumerationRootItem(nsIDocShellTreeItem * aEnumerationRootItem) { - mRootItem = aEnumerationRootItem; + mRootItem = do_GetWeakReference(aEnumerationRootItem); ClearState(); return NS_OK; } @@ -131,12 +126,10 @@ nsresult nsDocShellEnumerator::First() nsresult nsDocShellEnumerator::EnsureDocShellArray() { - if (!mItemArray) + if (!mArrayValid) { - mItemArray = new nsVoidArray; - if (!mItemArray) return NS_ERROR_OUT_OF_MEMORY; - - return BuildDocShellArray(*mItemArray); + mArrayValid = PR_TRUE; + return BuildDocShellArray(mItemArray); } return NS_OK; @@ -144,21 +137,21 @@ nsresult nsDocShellEnumerator::EnsureDocShellArray() nsresult nsDocShellEnumerator::ClearState() { - delete mItemArray; - mItemArray = nsnull; - + mItemArray.Clear(); + mArrayValid = PR_FALSE; mCurIndex = 0; return NS_OK; } -nsresult nsDocShellEnumerator::BuildDocShellArray(nsVoidArray& inItemArray) +nsresult nsDocShellEnumerator::BuildDocShellArray(nsTArray& inItemArray) { NS_ENSURE_TRUE(mRootItem, NS_ERROR_NOT_INITIALIZED); inItemArray.Clear(); - return BuildArrayRecursive(mRootItem, inItemArray); + nsCOMPtr item = do_QueryReferent(mRootItem); + return BuildArrayRecursive(item, inItemArray); } -nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray) +nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray) { nsresult rv; nsCOMPtr itemAsNode = do_QueryInterface(inItem, &rv); @@ -169,8 +162,8 @@ nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* if ((mDocShellType == nsIDocShellTreeItem::typeAll) || (NS_SUCCEEDED(inItem->GetItemType(&itemType)) && (itemType == mDocShellType))) { - rv = inItemArray.AppendElement((void *)inItem); - if (NS_FAILED(rv)) return rv; + if (!inItemArray.AppendElement(do_GetWeakReference(inItem))) + return NS_ERROR_OUT_OF_MEMORY; } PRInt32 numChildren; @@ -191,7 +184,7 @@ nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* } -nsresult nsDocShellBackwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray) +nsresult nsDocShellBackwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray) { nsresult rv; nsCOMPtr itemAsNode = do_QueryInterface(inItem, &rv); @@ -216,12 +209,10 @@ nsresult nsDocShellBackwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* if ((mDocShellType == nsIDocShellTreeItem::typeAll) || (NS_SUCCEEDED(inItem->GetItemType(&itemType)) && (itemType == mDocShellType))) { - rv = inItemArray.AppendElement((void *)inItem); - if (NS_FAILED(rv)) return rv; + if (!inItemArray.AppendElement(do_GetWeakReference(inItem))) + return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; } - - diff --git a/docshell/base/nsDocShellEnumerator.h b/docshell/base/nsDocShellEnumerator.h index aa4758a0..eba22137 100644 --- a/docshell/base/nsDocShellEnumerator.h +++ b/docshell/base/nsDocShellEnumerator.h @@ -42,7 +42,9 @@ #include "nsIEnumerator.h" #include "nsCOMPtr.h" -#include "nsVoidArray.h" +#include "nsTArray.h" +#include "nsIWeakReference.h" +#include "nsIWeakReferenceUtils.h" class nsIDocShellTreeItem; @@ -98,17 +100,18 @@ protected: nsresult EnsureDocShellArray(); nsresult ClearState(); - nsresult BuildDocShellArray(nsVoidArray& inItemArray); - virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray) = 0; + nsresult BuildDocShellArray(nsTArray& inItemArray); + virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray) = 0; protected: - nsIDocShellTreeItem* mRootItem; // weak ref! + nsWeakPtr mRootItem; // weak ref! - nsVoidArray* mItemArray; // flattened list of items with matching type - PRInt32 mCurIndex; + nsTArray mItemArray; // flattened list of items with matching type + PRUint32 mCurIndex; PRInt32 mDocShellType; // only want shells of this type + PRPackedBool mArrayValid; // is mItemArray up to date? const PRInt8 mEnumerationDirection; }; @@ -125,7 +128,7 @@ public: protected: - virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray); + virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray); }; @@ -139,6 +142,6 @@ public: } protected: - virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray); + virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray); }; diff --git a/docshell/base/nsDocShellLoadInfo.cpp b/docshell/base/nsDocShellLoadInfo.cpp index e1d634f2..c919e60a 100644 --- a/docshell/base/nsDocShellLoadInfo.cpp +++ b/docshell/base/nsDocShellLoadInfo.cpp @@ -49,6 +49,7 @@ nsDocShellLoadInfo::nsDocShellLoadInfo() : mInheritOwner(PR_FALSE), + mOwnerIsExplicit(PR_FALSE), mSendReferrer(PR_TRUE), mLoadType(nsIDocShellLoadInfo::loadNormal) { @@ -68,6 +69,7 @@ NS_IMPL_RELEASE(nsDocShellLoadInfo) NS_INTERFACE_MAP_BEGIN(nsDocShellLoadInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellLoadInfo) NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo) + NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo_1_9_0_BRANCH) NS_INTERFACE_MAP_END //***************************************************************************** @@ -118,6 +120,18 @@ NS_IMETHODIMP nsDocShellLoadInfo::SetInheritOwner(PRBool aInheritOwner) return NS_OK; } +NS_IMETHODIMP nsDocShellLoadInfo::GetOwnerIsExplicit(PRBool* aOwnerIsExplicit) +{ + *aOwnerIsExplicit = mOwnerIsExplicit; + return NS_OK; +} + +NS_IMETHODIMP nsDocShellLoadInfo::SetOwnerIsExplicit(PRBool aOwnerIsExplicit) +{ + mOwnerIsExplicit = aOwnerIsExplicit; + return NS_OK; +} + NS_IMETHODIMP nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType * aLoadType) { NS_ENSURE_ARG_POINTER(aLoadType); diff --git a/docshell/base/nsDocShellLoadInfo.h b/docshell/base/nsDocShellLoadInfo.h index c3701a68..e7d2cb54 100644 --- a/docshell/base/nsDocShellLoadInfo.h +++ b/docshell/base/nsDocShellLoadInfo.h @@ -51,13 +51,14 @@ #include "nsIInputStream.h" #include "nsISHEntry.h" -class nsDocShellLoadInfo : public nsIDocShellLoadInfo +class nsDocShellLoadInfo : public nsIDocShellLoadInfo_1_9_0_BRANCH { public: nsDocShellLoadInfo(); NS_DECL_ISUPPORTS NS_DECL_NSIDOCSHELLLOADINFO + NS_DECL_NSIDOCSHELLLOADINFO_1_9_0_BRANCH protected: virtual ~nsDocShellLoadInfo(); @@ -66,6 +67,7 @@ protected: nsCOMPtr mReferrer; nsCOMPtr mOwner; PRPackedBool mInheritOwner; + PRPackedBool mOwnerIsExplicit; PRPackedBool mSendReferrer; nsDocShellInfoLoadType mLoadType; nsCOMPtr mSHEntry; diff --git a/docshell/base/nsIDocShellLoadInfo.idl b/docshell/base/nsIDocShellLoadInfo.idl index dcbf325d..92dbc2ed 100644 --- a/docshell/base/nsIDocShellLoadInfo.idl +++ b/docshell/base/nsIDocShellLoadInfo.idl @@ -103,3 +103,15 @@ interface nsIDocShellLoadInfo : nsISupports */ attribute boolean sendReferrer; }; + +[scriptable, uuid(b66d94ba-4457-41b1-9507-79c1cd873da0)] +interface nsIDocShellLoadInfo_1_9_0_BRANCH : nsIDocShellLoadInfo +{ + /** If this attribute is true only ever use the owner specify by + * the owner and inheritOwner attributes. + * If there are security reasons for why this is unsafe, such + * as trying to use a systemprincipal owner for a content docshell + * the load fails. + */ + attribute boolean ownerIsExplicit; +}; diff --git a/docshell/base/nsWebShell.cpp b/docshell/base/nsWebShell.cpp index d49e2a4e..f2610b83 100644 --- a/docshell/base/nsWebShell.cpp +++ b/docshell/base/nsWebShell.cpp @@ -532,6 +532,10 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent, nsCOMPtr anchor(do_QueryInterface(aContent)); if (anchor) { anchor->GetType(typeHint); + NS_ConvertUTF16toUTF8 utf8Hint(typeHint); + nsCAutoString type, dummy; + NS_ParseContentType(utf8Hint, type, dummy); + CopyUTF8toUTF16(type, typeHint); } switch(aVerb) { diff --git a/dom/public/base/nsPIDOMWindow.h b/dom/public/base/nsPIDOMWindow.h index 60104edf..473d9e6d 100644 --- a/dom/public/base/nsPIDOMWindow.h +++ b/dom/public/base/nsPIDOMWindow.h @@ -173,6 +173,7 @@ public: return mFrameElement; } + // Caller must release the old frame element and addref the new one. void SetFrameElementInternal(nsIDOMElement *aFrameElement) { if (IsOuterWindow()) { diff --git a/dom/public/nsIDOMClassInfo.h b/dom/public/nsIDOMClassInfo.h index cfb9b6e2..eed55e0a 100644 --- a/dom/public/nsIDOMClassInfo.h +++ b/dom/public/nsIDOMClassInfo.h @@ -191,7 +191,6 @@ enum nsDOMClassInfoID { // Crypto classes eDOMClassInfo_Crypto_id, eDOMClassInfo_CRMFObject_id, - eDOMClassInfo_Pkcs11_id, // DOM Traversal classes eDOMClassInfo_TreeWalker_id, diff --git a/dom/src/base/nsBarProps.cpp b/dom/src/base/nsBarProps.cpp index 157b657a..645671fc 100644 --- a/dom/src/base/nsBarProps.cpp +++ b/dom/src/base/nsBarProps.cpp @@ -51,8 +51,11 @@ // // Basic (virtual) BarProp class implementation // -nsBarProp::nsBarProp() : mBrowserChrome(nsnull) +nsBarProp::nsBarProp(nsGlobalWindow *aWindow) { + mDOMWindow = aWindow; + nsISupports *supwin = static_cast(aWindow); + mDOMWindowWeakref = do_GetWeakReference(supwin); } nsBarProp::~nsBarProp() @@ -71,25 +74,19 @@ NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsBarProp) NS_IMPL_RELEASE(nsBarProp) - -NS_IMETHODIMP -nsBarProp::SetWebBrowserChrome(nsIWebBrowserChrome* aBrowserChrome) -{ - mBrowserChrome = aBrowserChrome; - return NS_OK; -} - NS_IMETHODIMP nsBarProp::GetVisibleByFlag(PRBool *aVisible, PRUint32 aChromeFlag) { - NS_ENSURE_TRUE(mBrowserChrome, NS_ERROR_FAILURE); - - PRUint32 chromeFlags; *aVisible = PR_FALSE; - NS_ENSURE_SUCCESS(mBrowserChrome->GetChromeFlags(&chromeFlags), + nsCOMPtr browserChrome = GetBrowserChrome(); + NS_ENSURE_TRUE(browserChrome, NS_OK); + + PRUint32 chromeFlags; + + NS_ENSURE_SUCCESS(browserChrome->GetChromeFlags(&chromeFlags), NS_ERROR_FAILURE); - if(chromeFlags & aChromeFlag) + if (chromeFlags & aChromeFlag) *aVisible = PR_TRUE; return NS_OK; @@ -98,9 +95,10 @@ nsBarProp::GetVisibleByFlag(PRBool *aVisible, PRUint32 aChromeFlag) NS_IMETHODIMP nsBarProp::SetVisibleByFlag(PRBool aVisible, PRUint32 aChromeFlag) { - NS_ENSURE_TRUE(mBrowserChrome, NS_ERROR_FAILURE); + nsCOMPtr browserChrome = GetBrowserChrome(); + NS_ENSURE_TRUE(browserChrome, NS_OK); - PRBool enabled = PR_FALSE; + PRBool enabled = PR_FALSE; nsCOMPtr securityManager(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); @@ -111,23 +109,37 @@ nsBarProp::SetVisibleByFlag(PRBool aVisible, PRUint32 aChromeFlag) PRUint32 chromeFlags; - NS_ENSURE_SUCCESS(mBrowserChrome->GetChromeFlags(&chromeFlags), + NS_ENSURE_SUCCESS(browserChrome->GetChromeFlags(&chromeFlags), NS_ERROR_FAILURE); - if(aVisible) + if (aVisible) chromeFlags |= aChromeFlag; else chromeFlags &= ~aChromeFlag; - NS_ENSURE_SUCCESS(mBrowserChrome->SetChromeFlags(chromeFlags), + NS_ENSURE_SUCCESS(browserChrome->SetChromeFlags(chromeFlags), NS_ERROR_FAILURE); return NS_OK; } +already_AddRefed +nsBarProp::GetBrowserChrome() +{ + // Check that the window is still alive. + nsCOMPtr domwin(do_QueryReferent(mDOMWindowWeakref)); + if (!domwin) + return nsnull; + + nsIWebBrowserChrome *browserChrome = nsnull; + mDOMWindow->GetWebBrowserChrome(&browserChrome); + return browserChrome; +} + // // MenubarProp class implementation // -nsMenubarProp::nsMenubarProp() +nsMenubarProp::nsMenubarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -153,7 +165,8 @@ nsMenubarProp::SetVisible(PRBool aVisible) // ToolbarProp class implementation // -nsToolbarProp::nsToolbarProp() +nsToolbarProp::nsToolbarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -179,7 +192,8 @@ nsToolbarProp::SetVisible(PRBool aVisible) // LocationbarProp class implementation // -nsLocationbarProp::nsLocationbarProp() +nsLocationbarProp::nsLocationbarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -207,7 +221,8 @@ nsLocationbarProp::SetVisible(PRBool aVisible) // PersonalbarProp class implementation // -nsPersonalbarProp::nsPersonalbarProp() +nsPersonalbarProp::nsPersonalbarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -235,7 +250,8 @@ nsPersonalbarProp::SetVisible(PRBool aVisible) // StatusbarProp class implementation // -nsStatusbarProp::nsStatusbarProp() +nsStatusbarProp::nsStatusbarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -262,10 +278,8 @@ nsStatusbarProp::SetVisible(PRBool aVisible) // nsScrollbarsProp::nsScrollbarsProp(nsGlobalWindow *aWindow) +: nsBarProp(aWindow) { - mDOMWindow = aWindow; - nsISupports *supwin = NS_STATIC_CAST(nsIScriptGlobalObject *, aWindow); - mDOMWindowWeakref = do_GetWeakReference(supwin); } nsScrollbarsProp::~nsScrollbarsProp() @@ -339,7 +353,7 @@ nsScrollbarsProp::SetVisible(PRBool aVisible) } /* Notably absent is the part where we notify the chrome window using - mBrowserChrome->SetChromeFlags(). Given the possibility of multiple + GetBrowserChrome()->SetChromeFlags(). Given the possibility of multiple DOM windows (multiple top-level windows, even) within a single chrome window, the historical concept of a single "has scrollbars" flag in the chrome is inapplicable, and we can't tell at this level @@ -354,4 +368,3 @@ nsScrollbarsProp::SetVisible(PRBool aVisible) return NS_OK; } - diff --git a/dom/src/base/nsBarProps.h b/dom/src/base/nsBarProps.h index 80cc6838..f032c10e 100644 --- a/dom/src/base/nsBarProps.h +++ b/dom/src/base/nsBarProps.h @@ -56,26 +56,34 @@ class nsIWebBrowserChrome; class nsBarProp : public nsIDOMBarProp { public: - nsBarProp(); + explicit nsBarProp(nsGlobalWindow *aWindow); virtual ~nsBarProp(); NS_DECL_ISUPPORTS - NS_IMETHOD SetWebBrowserChrome(nsIWebBrowserChrome* aBrowserChrome); - NS_IMETHOD GetVisibleByFlag(PRBool *aVisible, PRUint32 aChromeFlag); NS_IMETHOD SetVisibleByFlag(PRBool aVisible, PRUint32 aChromeFlag); protected: - // Weak Reference - nsIWebBrowserChrome* mBrowserChrome; + already_AddRefed GetBrowserChrome(); + + nsGlobalWindow *mDOMWindow; + nsCOMPtr mDOMWindowWeakref; + /* Note the odd double reference to the owning global window. + Since the corresponding DOM window nominally owns this object, + but refcounted ownership of this object can be handed off to + owners unknown, we need a weak ref back to the DOM window. + However we also need access to properties of the DOM Window + that aren't available through interfaces. Then it's either + a weak ref and some skanky casting, or this funky double ref. + Funky beats skanky, so here we are. */ }; // Script "menubar" object class nsMenubarProp : public nsBarProp { public: - nsMenubarProp(); + explicit nsMenubarProp(nsGlobalWindow *aWindow); virtual ~nsMenubarProp(); NS_DECL_NSIDOMBARPROP @@ -85,7 +93,7 @@ public: class nsToolbarProp : public nsBarProp { public: - nsToolbarProp(); + explicit nsToolbarProp(nsGlobalWindow *aWindow); virtual ~nsToolbarProp(); NS_DECL_NSIDOMBARPROP @@ -95,7 +103,7 @@ public: class nsLocationbarProp : public nsBarProp { public: - nsLocationbarProp(); + explicit nsLocationbarProp(nsGlobalWindow *aWindow); virtual ~nsLocationbarProp(); NS_DECL_NSIDOMBARPROP @@ -105,7 +113,7 @@ public: class nsPersonalbarProp : public nsBarProp { public: - nsPersonalbarProp(); + explicit nsPersonalbarProp(nsGlobalWindow *aWindow); virtual ~nsPersonalbarProp(); NS_DECL_NSIDOMBARPROP @@ -115,31 +123,20 @@ public: class nsStatusbarProp : public nsBarProp { public: - nsStatusbarProp(); + explicit nsStatusbarProp(nsGlobalWindow *aWindow); virtual ~nsStatusbarProp(); NS_DECL_NSIDOMBARPROP }; // Script "scrollbars" object -class nsScrollbarsProp : public nsBarProp { +class nsScrollbarsProp : public nsBarProp +{ public: - nsScrollbarsProp(nsGlobalWindow *aWindow); + explicit nsScrollbarsProp(nsGlobalWindow *aWindow); virtual ~nsScrollbarsProp(); NS_DECL_NSIDOMBARPROP - -private: - nsGlobalWindow *mDOMWindow; - nsCOMPtr mDOMWindowWeakref; - /* Note the odd double reference to the owning global window. - Since the corresponding DOM window nominally owns this object, - yet refcounted ownership of this object can be handed off to - owners unknown, we need a weak ref to back to the DOM window. - However we also need access to properties of the DOM Window - that aren't available through interfaces. Then it's either - a weak ref and some skanky casting, or this funky double ref. - Funky beats skanky, so here we are. */ }; #endif /* nsBarProps_h___ */ diff --git a/dom/src/base/nsDOMClassInfo.cpp b/dom/src/base/nsDOMClassInfo.cpp index 5b3e0937..6399d6d7 100644 --- a/dom/src/base/nsDOMClassInfo.cpp +++ b/dom/src/base/nsDOMClassInfo.cpp @@ -309,7 +309,6 @@ #include "nsIDOMXULCommandDispatcher.h" #include "nsIDOMCrypto.h" #include "nsIDOMCRMFObject.h" -#include "nsIDOMPkcs11.h" #include "nsIControllers.h" #include "nsISelection.h" #include "nsIBoxObject.h" @@ -557,8 +556,7 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(DOMException, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(DocumentFragment, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(DocumentFragment, nsNodeSH, NODE_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(Element, nsElementSH, ELEMENT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(Attr, nsDOMGenericSH, @@ -806,8 +804,6 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(CRMFObject, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(Pkcs11, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) // DOM Traversal classes NS_DEFINE_CLASSINFO_DATA(TreeWalker, nsDOMGCParticipantSH, @@ -2418,10 +2414,6 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMCRMFObject) DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(Pkcs11, nsIDOMPkcs11) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMPkcs11) - DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XMLStylesheetProcessingInstruction, nsIDOMProcessingInstruction) DOM_CLASSINFO_MAP_ENTRY(nsIDOMProcessingInstruction) DOM_CLASSINFO_MAP_ENTRY(nsIDOMLinkStyle) @@ -6020,13 +6012,61 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_OK; } + JSString *str = JSVAL_TO_STRING(id); + + if (id == sLocation_id) { + // This must be done even if we're just getting the value of + // window.location (i.e. no checking flags & JSRESOLVE_ASSIGNING + // here) since we must define window.location to prevent the + // getter from being overriden (for security reasons). + + nsCOMPtr location; + rv = win->GetLocation(getter_AddRefs(location)); + NS_ENSURE_SUCCESS(rv, rv); + + // Make sure we wrap the location object in the inner window's + // scope if we've got an inner window. + JSObject *scope = nsnull; + if (win->IsOuterWindow()) { + nsGlobalWindow *innerWin = win->GetCurrentInnerWindowInternal(); + + if (innerWin) { + scope = innerWin->GetGlobalJSObject(); + } + } + + if (!scope) { + wrapper->GetJSObject(&scope); + } + + jsval v; + nsCOMPtr holder; + rv = WrapNative(cx, scope, location, NS_GET_IID(nsIDOMLocation), &v, + getter_AddRefs(holder)); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool doSecurityCheckInAddProperty = sDoSecurityCheckInAddProperty; + sDoSecurityCheckInAddProperty = PR_FALSE; + + JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), + ::JS_GetStringLength(str), v, nsnull, + nsnull, JSPROP_ENUMERATE); + + sDoSecurityCheckInAddProperty = doSecurityCheckInAddProperty; + + if (!ok) { + return NS_ERROR_FAILURE; + } + + *objp = obj; + + return NS_OK; + } // Hmm, we do an awful lot of QIs here; maybe we should add a // method on an interface that would let us just call into the // window code directly... - JSString *str = JSVAL_TO_STRING(id); - // Don't resolve named iframes on native wrappers if (!ObjectIsNativeWrapper(cx, obj)) { nsCOMPtr dsn(do_QueryInterface(win->GetDocShell())); @@ -6145,55 +6185,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_OK; } - if (id == sLocation_id) { - // This must be done even if we're just getting the value of - // window.location (i.e. no checking flags & JSRESOLVE_ASSIGNING - // here) since we must define window.location to prevent the - // getter from being overriden (for security reasons). - - nsCOMPtr location; - rv = win->GetLocation(getter_AddRefs(location)); - NS_ENSURE_SUCCESS(rv, rv); - - // Make sure we wrap the location object in the inner window's - // scope if we've got an inner window. - JSObject *scope = nsnull; - if (win->IsOuterWindow()) { - nsGlobalWindow *innerWin = win->GetCurrentInnerWindowInternal(); - - if (innerWin) { - scope = innerWin->GetGlobalJSObject(); - } - } - - if (!scope) { - wrapper->GetJSObject(&scope); - } - - jsval v; - nsCOMPtr holder; - rv = WrapNative(cx, scope, location, NS_GET_IID(nsIDOMLocation), &v, - getter_AddRefs(holder)); - NS_ENSURE_SUCCESS(rv, rv); - - PRBool doSecurityCheckInAddProperty = sDoSecurityCheckInAddProperty; - sDoSecurityCheckInAddProperty = PR_FALSE; - - JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), v, nsnull, - nsnull, JSPROP_ENUMERATE); - - sDoSecurityCheckInAddProperty = doSecurityCheckInAddProperty; - - if (!ok) { - return NS_ERROR_FAILURE; - } - - *objp = obj; - - return NS_OK; - } - if (flags & JSRESOLVE_ASSIGNING) { if (IsReadonlyReplaceable(id) || (!(flags & JSRESOLVE_QUALIFIED) && IsWritableReplaceable(id))) { @@ -6760,17 +6751,6 @@ nsEventReceiverSH::AddEventListenerHelper(JSContext *cx, JSObject *obj, return JS_FALSE; } - // Can't use the macro OBJ_TO_INNER_OBJECT here due to it using the - // non-exported function js_GetSlotThreadSafe(). - { - JSClass *clasp = JS_GET_CLASS(cx, obj); - if (clasp->flags & JSCLASS_IS_EXTENDED) { - JSExtendedClass *xclasp = (JSExtendedClass*)clasp; - if (xclasp->innerObject) - obj = xclasp->innerObject(cx, obj); - } - } - nsCOMPtr wrapper; nsresult rv = sXPConnect->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper)); @@ -6784,6 +6764,26 @@ nsEventReceiverSH::AddEventListenerHelper(JSContext *cx, JSObject *obj, // event listener. wrapper->GetJSObject(&obj); + // Can't use the macro OBJ_TO_INNER_OBJECT here due to it using the + // non-exported function js_GetSlotThreadSafe(). + { + JSClass *clasp = JS_GET_CLASS(cx, obj); + if (clasp->flags & JSCLASS_IS_EXTENDED) { + JSExtendedClass *xclasp = (JSExtendedClass*)clasp; + if (xclasp->innerObject) + obj = xclasp->innerObject(cx, obj); + } + } + if (!obj) { + return JS_FALSE; + } + rv = sXPConnect->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper)); + + if (NS_FAILED(rv)) { + nsDOMClassInfo::ThrowJSException(cx, rv); + return JS_FALSE; + } + // Check that the caller has permission to call obj's addEventListener. if (NS_FAILED(sSecMan->CheckPropertyAccess(cx, obj, JS_GET_CLASS(cx, obj)->name, diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index 89ef1ea2..3be51293 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -97,7 +97,6 @@ #include "nsIDOMEvent.h" #include "nsIDOMKeyEvent.h" #include "nsIDOMPopupBlockedEvent.h" -#include "nsIDOMPkcs11.h" #include "nsDOMString.h" #include "nsIEmbeddingSiteWindow2.h" #include "nsIEventQueueService.h" @@ -444,6 +443,7 @@ nsGlobalWindow::~nsGlobalWindow() } } + NS_IF_RELEASE(mFrameElement); mDocument = nsnull; // Forces Release NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!"); @@ -1539,12 +1539,6 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell) mScreen->SetDocShell(aDocShell); if (mDocShell) { - // tell our member elements about the new browserwindow - if (mMenubar) { - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - mMenubar->SetWebBrowserChrome(browserChrome); - } // Get our enclosing chrome shell and retrieve its global window impl, so // that we can do some forwarding to the chrome document. @@ -2168,15 +2162,10 @@ nsGlobalWindow::GetMenubar(nsIDOMBarProp** aMenubar) *aMenubar = nsnull; if (!mMenubar) { - mMenubar = new nsMenubarProp(); + mMenubar = new nsMenubarProp(this); if (!mMenubar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mMenubar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aMenubar = mMenubar); @@ -2192,15 +2181,10 @@ nsGlobalWindow::GetToolbar(nsIDOMBarProp** aToolbar) *aToolbar = nsnull; if (!mToolbar) { - mToolbar = new nsToolbarProp(); + mToolbar = new nsToolbarProp(this); if (!mToolbar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mToolbar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aToolbar = mToolbar); @@ -2216,15 +2200,10 @@ nsGlobalWindow::GetLocationbar(nsIDOMBarProp** aLocationbar) *aLocationbar = nsnull; if (!mLocationbar) { - mLocationbar = new nsLocationbarProp(); + mLocationbar = new nsLocationbarProp(this); if (!mLocationbar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mLocationbar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aLocationbar = mLocationbar); @@ -2240,15 +2219,10 @@ nsGlobalWindow::GetPersonalbar(nsIDOMBarProp** aPersonalbar) *aPersonalbar = nsnull; if (!mPersonalbar) { - mPersonalbar = new nsPersonalbarProp(); + mPersonalbar = new nsPersonalbarProp(this); if (!mPersonalbar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mPersonalbar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aPersonalbar = mPersonalbar); @@ -2264,15 +2238,10 @@ nsGlobalWindow::GetStatusbar(nsIDOMBarProp** aStatusbar) *aStatusbar = nsnull; if (!mStatusbar) { - mStatusbar = new nsStatusbarProp(); + mStatusbar = new nsStatusbarProp(this); if (!mStatusbar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mStatusbar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aStatusbar = mStatusbar); @@ -2292,11 +2261,6 @@ nsGlobalWindow::GetScrollbars(nsIDOMBarProp** aScrollbars) if (!mScrollbars) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mScrollbars->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aScrollbars = mScrollbars); @@ -2358,14 +2322,7 @@ nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto) NS_IMETHODIMP nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11) { - FORWARD_TO_OUTER(GetPkcs11, (aPkcs11), NS_ERROR_NOT_INITIALIZED); - - if (!mPkcs11) { - mPkcs11 = do_CreateInstance(kPkcs11ContractID); - } - - NS_IF_ADDREF(*aPkcs11 = mPkcs11); - + *aPkcs11 = nsnull; return NS_OK; } @@ -3301,6 +3258,9 @@ nsGlobalWindow::EnsureReflowFlushAndPaint() NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no " "docshell!"); + if (!mDocShell) + return; + nsCOMPtr presShell; mDocShell->GetPresShell(getter_AddRefs(presShell)); @@ -5153,6 +5113,7 @@ nsGlobalWindow::FindInternal(const nsAString& aStr, PRBool caseSensitive, *aDidFind = PR_FALSE; nsCOMPtr finder(do_GetInterface(mDocShell)); + NS_ENSURE_TRUE(finder, NS_ERROR_FAILURE); // Set the options of the search rv = finder->SetSearchString(PromiseFlatString(aStr).get()); @@ -7920,6 +7881,10 @@ nsNavigator::nsNavigator(nsIDocShell *aDocShell) nsNavigator::~nsNavigator() { sPrefInternal_id = JSVAL_VOID; + if (mMimeTypes) + mMimeTypes->Invalidate(); + if (mPlugins) + mPlugins->Invalidate(); } //***************************************************************************** @@ -8464,8 +8429,15 @@ nsNavigator::LoadingNewDocument() // Release these so that they will be recreated for the // new document (if requested). The plugins or mime types // arrays may have changed. See bug 150087. - mMimeTypes = nsnull; - mPlugins = nsnull; + if (mMimeTypes) { + mMimeTypes->Invalidate(); + mMimeTypes = nsnull; + } + + if (mPlugins) { + mPlugins->Invalidate(); + mPlugins = nsnull; + } } nsresult diff --git a/dom/src/base/nsGlobalWindow.h b/dom/src/base/nsGlobalWindow.h index b7647088..f5c3d3b5 100644 --- a/dom/src/base/nsGlobalWindow.h +++ b/dom/src/base/nsGlobalWindow.h @@ -82,7 +82,6 @@ #include "nsIEventListenerManager.h" #include "nsIDOMDocument.h" #include "nsIDOMCrypto.h" -#include "nsIDOMPkcs11.h" #include "nsIPrincipal.h" #include "nsPluginArray.h" #include "nsMimeTypeArray.h" @@ -319,6 +318,8 @@ public: friend class WindowStateHolder; protected: + friend class nsBarProp; + // Object Management virtual ~nsGlobalWindow(); void CleanUp(); @@ -537,7 +538,6 @@ protected: nsIScriptGlobalObjectOwner* mGlobalObjectOwner; // Weak Reference nsIDocShell* mDocShell; // Weak Reference nsCOMPtr mCrypto; - nsCOMPtr mPkcs11; nsCOMPtr gGlobalStorageList; diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index 5215ea13..ce6012b5 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -248,6 +248,13 @@ NS_ScriptErrorReporter(JSContext *cx, } else { errorevent.errorMsg = xoriginMsg.get(); errorevent.lineNr = 0; + // FIXME: once the principal of the script is not tied to + // the filename, we can stop using the post-redirect + // filename if we want and remove this line. Note that + // apparently we can't handle null filenames in the error + // event dispatching code. + static PRUnichar nullFilename[] = { PRUnichar(0) }; + errorevent.fileName = nullFilename; } // HandleDOMEvent() must be synchronous for the recursion block diff --git a/dom/src/base/nsMimeTypeArray.cpp b/dom/src/base/nsMimeTypeArray.cpp index cacb5bae..26389fc5 100644 --- a/dom/src/base/nsMimeTypeArray.cpp +++ b/dom/src/base/nsMimeTypeArray.cpp @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=79: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -197,6 +198,9 @@ nsresult nsMimeTypeArray::GetMimeTypes() { NS_PRECONDITION(!mMimeTypeArray && mMimeTypeCount==0, "already initialized"); + if (!mNavigator) { + return NS_ERROR_NOT_AVAILABLE; + } nsIDOMPluginArray* pluginArray = nsnull; nsresult rv = mNavigator->GetPlugins(&pluginArray); @@ -225,14 +229,14 @@ nsresult nsMimeTypeArray::GetMimeTypes() PRUint32 mimeTypeIndex = 0; PRUint32 k; for (k = 0; k < pluginCount; k++) { - nsIDOMPlugin* plugin = nsnull; - if (pluginArray->Item(k, &plugin) == NS_OK) { + nsCOMPtr plugin; + if (NS_SUCCEEDED(pluginArray->Item(k, getter_AddRefs(plugin))) && + plugin) { PRUint32 mimeTypeCount = 0; if (plugin->GetLength(&mimeTypeCount) == NS_OK) { for (PRUint32 j = 0; j < mimeTypeCount; j++) plugin->Item(j, &mMimeTypeArray[mimeTypeIndex++]); } - NS_RELEASE(plugin); } } } diff --git a/dom/src/base/nsMimeTypeArray.h b/dom/src/base/nsMimeTypeArray.h index 10604138..b64cf618 100644 --- a/dom/src/base/nsMimeTypeArray.h +++ b/dom/src/base/nsMimeTypeArray.h @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=79: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -45,6 +46,8 @@ class nsIDOMNavigator; +// NB: Due to weak references, nsNavigator has intimate knowledge of our +// members. class nsMimeTypeArray : public nsIDOMMimeTypeArray { public: @@ -58,6 +61,13 @@ public: NS_IMETHOD NamedItem(const nsAString& aName, nsIDOMMimeType** aReturn); nsresult Refresh(); + void Invalidate() + { + // NB: This will cause GetMimeTypes to fail from now on. + mNavigator = nsnull; + Clear(); + } + private: nsresult GetMimeTypes(); void Clear(); diff --git a/dom/src/base/nsPluginArray.cpp b/dom/src/base/nsPluginArray.cpp index 9670a105..dd133851 100644 --- a/dom/src/base/nsPluginArray.cpp +++ b/dom/src/base/nsPluginArray.cpp @@ -181,11 +181,18 @@ nsPluginArray::GetPluginHost(nsIPluginHost** aPluginHost) } void -nsPluginArray::SetDocShell(nsIDocShell* aDocShell) +nsPluginArray::SetDocShell(nsIDocShell *aDocShell) { mDocShell = aDocShell; } +void +nsPluginArray::Invalidate() +{ + mDocShell = nsnull; + mNavigator = nsnull; +} + NS_IMETHODIMP nsPluginArray::Refresh(PRBool aReloadDocuments) { diff --git a/dom/src/base/nsPluginArray.h b/dom/src/base/nsPluginArray.h index df1ed61c..a0f87591 100644 --- a/dom/src/base/nsPluginArray.h +++ b/dom/src/base/nsPluginArray.h @@ -47,6 +47,8 @@ class nsNavigator; class nsIDocShell; class nsIPluginHost; +// NB: Due to weak references, nsNavigator has intimate knowledge of our +// internals. class nsPluginArray : public nsIDOMPluginArray, public nsIDOMJSPluginArray { @@ -69,7 +71,8 @@ private: PRBool AllowPlugins(); public: - void SetDocShell(nsIDocShell* aDocShell); + void SetDocShell(nsIDocShell *aDocShell); + void Invalidate(); protected: nsNavigator* mNavigator; diff --git a/editor/composer/src/nsEditingSession.cpp b/editor/composer/src/nsEditingSession.cpp index 51651046..3f0f373e 100644 --- a/editor/composer/src/nsEditingSession.cpp +++ b/editor/composer/src/nsEditingSession.cpp @@ -1125,9 +1125,10 @@ nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress, if (NS_FAILED(rv)) return rv; mEditorStatus = eEditorCreationInProgress; + mDocShell = do_GetWeakReference(docShell); mLoadBlankDocTimer->InitWithFuncCallback( nsEditingSession::TimerCallback, - (void*)docShell, + static_cast (mDocShell.get()), 10, nsITimer::TYPE_ONE_SHOT); } } @@ -1139,7 +1140,7 @@ nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress, void nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure) { - nsCOMPtr docShell = (nsIDocShell*)aClosure; + nsCOMPtr docShell = do_QueryReferent(static_cast (aClosure)); if (docShell) { nsCOMPtr webNav(do_QueryInterface(docShell)); diff --git a/editor/composer/src/nsEditingSession.h b/editor/composer/src/nsEditingSession.h index 7d40db33..33db4264 100644 --- a/editor/composer/src/nsEditingSession.h +++ b/editor/composer/src/nsEditingSession.h @@ -163,6 +163,9 @@ protected: PRUint32 mBaseCommandControllerId; PRUint32 mDocStateControllerId; PRUint32 mHTMLCommandControllerId; + + // Make sure the docshell we use is safe + nsWeakPtr mDocShell; }; diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 81e8314c..2676d428 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -982,12 +982,12 @@ nsEditor::BeginPlaceHolderTransaction(nsIAtom *aName) mPlaceHolderName = aName; nsCOMPtr selection; nsresult res = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(res)) return res; - mSelState = new nsSelectionState(); - if (!mSelState) - return NS_ERROR_OUT_OF_MEMORY; - - mSelState->SaveSelection(selection); + if (NS_SUCCEEDED(res)) { + mSelState = new nsSelectionState(); + if (mSelState) { + mSelState->SaveSelection(selection); + } + } } mPlaceHolderBatch++; diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/text/nsTextEditRules.cpp index 88d32635..2a3931a6 100644 --- a/editor/libeditor/text/nsTextEditRules.cpp +++ b/editor/libeditor/text/nsTextEditRules.cpp @@ -201,6 +201,12 @@ nsTextEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection) nsAutoLockRulesSniffing lockIt(this); mDidExplicitlySetInterline = PR_FALSE; + if (!mActionNesting) + { + // let rules remember the top level action + mTheAction = action; + } + mActionNesting++; // get the selection and cache the position before editing nsCOMPtr selection; @@ -211,12 +217,6 @@ nsTextEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection) selection->GetAnchorNode(getter_AddRefs(mCachedSelectionNode)); selection->GetAnchorOffset(&mCachedSelectionOffset); - if (!mActionNesting) - { - // let rules remember the top level action - mTheAction = action; - } - mActionNesting++; return NS_OK; } diff --git a/embedding/components/windowwatcher/src/nsPromptService.cpp b/embedding/components/windowwatcher/src/nsPromptService.cpp index 4ce7f19d..0346e561 100644 --- a/embedding/components/windowwatcher/src/nsPromptService.cpp +++ b/embedding/components/windowwatcher/src/nsPromptService.cpp @@ -652,6 +652,8 @@ nsPromptService::DoDialog(nsIDOMWindow *aParent, aParent = activeParent; } + aParamBlock->SetInt(eButtonPressed, 1); + nsCOMPtr arguments(do_QueryInterface(aParamBlock)); nsCOMPtr dialog; rv = mWatcher->OpenWindow(aParent, aChromeURL, "_blank", diff --git a/extensions/transformiix/source/xpath/Expr.h b/extensions/transformiix/source/xpath/Expr.h index 7aea1524..608d80d5 100644 --- a/extensions/transformiix/source/xpath/Expr.h +++ b/extensions/transformiix/source/xpath/Expr.h @@ -169,7 +169,8 @@ protected: /* * Evaluates the given Expression and converts its result to a number. */ - double evaluateToNumber(Expr* aExpr, txIEvalContext* aContext); + static nsresult evaluateToNumber(Expr* aExpr, txIEvalContext* aContext, + double* aResult); /* * Evaluates the given Expression and converts its result to a boolean. diff --git a/extensions/transformiix/source/xpath/FunctionCall.cpp b/extensions/transformiix/source/xpath/FunctionCall.cpp index bf0cb92d..93b6243d 100644 --- a/extensions/transformiix/source/xpath/FunctionCall.cpp +++ b/extensions/transformiix/source/xpath/FunctionCall.cpp @@ -99,15 +99,19 @@ void FunctionCall::evaluateToString(Expr* aExpr, txIEvalContext* aContext, /* * Evaluates the given Expression and converts its result to a number. */ -double FunctionCall::evaluateToNumber(Expr* aExpr, txIEvalContext* aContext) +// static +nsresult +FunctionCall::evaluateToNumber(Expr* aExpr, txIEvalContext* aContext, + double* aResult) { NS_ASSERTION(aExpr, "missing expression"); nsRefPtr exprResult; nsresult rv = aExpr->evaluate(aContext, getter_AddRefs(exprResult)); - if (NS_FAILED(rv)) - return Double::NaN; + NS_ENSURE_SUCCESS(rv, rv); - return exprResult->numberValue(); + *aResult = exprResult->numberValue(); + + return NS_OK; } /* diff --git a/extensions/transformiix/source/xpath/NumberFunctionCall.cpp b/extensions/transformiix/source/xpath/NumberFunctionCall.cpp index 2fdd011e..04e710ae 100644 --- a/extensions/transformiix/source/xpath/NumberFunctionCall.cpp +++ b/extensions/transformiix/source/xpath/NumberFunctionCall.cpp @@ -79,7 +79,10 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) switch (mType) { case CEILING: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext); + double dbl; + nsresult rv = evaluateToNumber((Expr*)iter.next(), aContext, &dbl); + NS_ENSURE_SUCCESS(rv, rv); + if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) { if (Double::isNeg(dbl) && dbl > -1) { dbl *= 0; @@ -93,7 +96,10 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) } case FLOOR: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext); + double dbl; + nsresult rv = evaluateToNumber((Expr*)iter.next(), aContext, &dbl); + NS_ENSURE_SUCCESS(rv, rv); + if (!Double::isNaN(dbl) && !Double::isInfinite(dbl) && !(dbl == 0 && Double::isNeg(dbl))) { @@ -104,7 +110,10 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) } case ROUND: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext); + double dbl; + nsresult rv = evaluateToNumber((Expr*)iter.next(), aContext, &dbl); + NS_ENSURE_SUCCESS(rv, rv); + if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) { if (Double::isNeg(dbl) && dbl >= -0.5) { dbl *= 0; @@ -136,7 +145,8 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) { double res; if (iter.hasNext()) { - res = evaluateToNumber((Expr*)iter.next(), aContext); + nsresult rv = evaluateToNumber((Expr*)iter.next(), aContext, &res); + NS_ENSURE_SUCCESS(rv, rv); } else { nsAutoString resultStr; diff --git a/extensions/transformiix/source/xpath/StringFunctionCall.cpp b/extensions/transformiix/source/xpath/StringFunctionCall.cpp index f9b66d2b..a78a3dda 100644 --- a/extensions/transformiix/source/xpath/StringFunctionCall.cpp +++ b/extensions/transformiix/source/xpath/StringFunctionCall.cpp @@ -193,7 +193,8 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) nsAutoString src; double start, end; evaluateToString((Expr*)iter.next(), aContext, src); - start = evaluateToNumber((Expr*)iter.next(), aContext); + rv = evaluateToNumber((Expr*)iter.next(), aContext, &start); + NS_ENSURE_SUCCESS(rv, rv); // check for NaN or +/-Inf if (Double::isNaN(start) || @@ -206,8 +207,10 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) start = floor(start + 0.5) - 1; if (iter.hasNext()) { - end = start + evaluateToNumber((Expr*)iter.next(), - aContext); + rv = evaluateToNumber((Expr*)iter.next(), aContext, &end); + NS_ENSURE_SUCCESS(rv, rv); + + end += start; if (Double::isNaN(end) || end < 0) { aContext->recycler()->getEmptyStringResult(aResult); diff --git a/extensions/transformiix/source/xpath/XFormsFunctionCall.cpp b/extensions/transformiix/source/xpath/XFormsFunctionCall.cpp index bcf7af57..eb0c5524 100644 --- a/extensions/transformiix/source/xpath/XFormsFunctionCall.cpp +++ b/extensions/transformiix/source/xpath/XFormsFunctionCall.cpp @@ -625,8 +625,8 @@ XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; double result = 0; - double base = evaluateToNumber((Expr*)iter.next(), aContext); - double exponent = evaluateToNumber((Expr*)iter.next(), aContext); + double base = evaluateToNumber((Expr*)iter.next(), aContext, &result); + double exponent = evaluateToNumber((Expr*)iter.next(), aContext, &result); // If base is negative and exponent is not an integral value, or if base // is zero and exponent is negative, a domain error occurs, setting the @@ -712,7 +712,8 @@ XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) if (!requireParams(1, 1, aContext)) return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - double days = evaluateToNumber((Expr*)iter.next(), aContext); + double res; + double days = evaluateToNumber((Expr*)iter.next(), aContext, &res); nsAutoString date; if (!Double::isNaN(days)) { @@ -745,7 +746,8 @@ XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) if (!requireParams(1, 1, aContext)) return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - double seconds = evaluateToNumber((Expr*)iter.next(), aContext); + double res; + double seconds = evaluateToNumber((Expr*)iter.next(), aContext, &res); nsAutoString dateTime; if (!Double::isNaN(seconds)) { diff --git a/extensions/transformiix/source/xslt/functions/txFormatNumberFunctionCall.cpp b/extensions/transformiix/source/xslt/functions/txFormatNumberFunctionCall.cpp index 83d12c65..89f9ce36 100644 --- a/extensions/transformiix/source/xslt/functions/txFormatNumberFunctionCall.cpp +++ b/extensions/transformiix/source/xslt/functions/txFormatNumberFunctionCall.cpp @@ -89,7 +89,9 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext, nsAutoString formatStr; txExpandedName formatName; - value = evaluateToNumber((Expr*)iter.next(), aContext); + rv = evaluateToNumber((Expr*)iter.next(), aContext, &value); + NS_ENSURE_SUCCESS(rv, rv); + evaluateToString((Expr*)iter.next(), aContext, formatStr); if (iter.hasNext()) { nsAutoString formatQName; diff --git a/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp b/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp index 3098aab3..00a1cfb0 100644 --- a/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp +++ b/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp @@ -416,10 +416,10 @@ nsresult txXSLKey::testNode(const txXPathNode& aNode, nsRefPtr exprResult; rv = key->useExpr->evaluate(evalContext, getter_AddRefs(exprResult)); - NS_ENSURE_SUCCESS(rv, rv); - delete aEs.popEvalContext(); + NS_ENSURE_SUCCESS(rv, rv); + if (exprResult->getResultType() == txAExprResult::NODESET) { txNodeSet* res = NS_STATIC_CAST(txNodeSet*, NS_STATIC_CAST(txAExprResult*, diff --git a/extensions/transformiix/source/xslt/txExecutionState.cpp b/extensions/transformiix/source/xslt/txExecutionState.cpp index 07aa633c..0deb225c 100644 --- a/extensions/transformiix/source/xslt/txExecutionState.cpp +++ b/extensions/transformiix/source/xslt/txExecutionState.cpp @@ -100,10 +100,13 @@ txExecutionState::txExecutionState(txStylesheet* aStylesheet, mKeyHash(aStylesheet->getKeyMap()), mDisableLoads(aDisableLoads) { + MOZ_COUNT_CTOR(txExecutionState); } txExecutionState::~txExecutionState() { + MOZ_COUNT_DTOR(txExecutionState); + delete mResultHandler; delete mLocalVariables; delete mEvalContext; @@ -203,7 +206,11 @@ txExecutionState::init(const txXPathNode& aNode, nsresult txExecutionState::end(nsresult aResult) { - popTemplateRule(); + NS_ASSERTION(NS_FAILED(aResult) || mTemplateRuleCount == 1, + "Didn't clean up template rules properly"); + if (NS_SUCCEEDED(aResult)) { + popTemplateRule(); + } mOutputHandler->endDocument(aResult); return NS_OK; @@ -276,9 +283,9 @@ txExecutionState::getVariable(PRInt32 aNamespace, nsIAtom* aLName, txVariableMap* oldVars = mLocalVariables; mLocalVariables = nsnull; rv = var->mExpr->evaluate(getEvalContext(), &aResult); - NS_ENSURE_SUCCESS(rv, rv); - mLocalVariables = oldVars; + + NS_ENSURE_SUCCESS(rv, rv); } else { nsAutoPtr rtfHandler(new txRtfHandler); @@ -448,9 +455,12 @@ txExecutionState::pushTemplateRule(txStylesheet::ImportFrame* aFrame, void txExecutionState::popTemplateRule() { + NS_PRECONDITION(mTemplateRuleCount > 0, "No rules to pop"); // decrement outside of RELEASE, that would decrement twice - --mTemplateRuleCount; - NS_IF_RELEASE(mTemplateRules[mTemplateRuleCount].mModeLocalName); + if(mTemplateRuleCount > 0) { + --mTemplateRuleCount; + NS_IF_RELEASE(mTemplateRules[mTemplateRuleCount].mModeLocalName); + } } txIEvalContext* @@ -514,7 +524,9 @@ txExecutionState::getKeyNodes(const txExpandedName& aKeyName, txExecutionState::TemplateRule* txExecutionState::getCurrentTemplateRule() { - return mTemplateRules + mTemplateRuleCount - 1; + NS_PRECONDITION(mTemplateRuleCount > 0, "No current rule!"); + // better to crash that underrun + return mTemplateRuleCount > 0 ? mTemplateRules + mTemplateRuleCount - 1 : NULL; } txInstruction* diff --git a/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp b/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp index b453c69c..879929fa 100644 --- a/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp +++ b/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp @@ -634,10 +634,12 @@ txMozillaXSLTProcessor::TransformToDoc(nsIDOMDocument *aOutputDoc, mObserver); es.mOutputHandlerFactory = &handlerFactory; - es.init(*sourceNode, &mVariables); + nsresult rv = es.init(*sourceNode, &mVariables); // Process root of XML source document - nsresult rv = txXSLTProcessor::execute(es); + if (NS_SUCCEEDED(rv)) { + rv = txXSLTProcessor::execute(es); + } es.end(rv); if (NS_SUCCEEDED(rv)) { if (aResult) { @@ -686,10 +688,12 @@ txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource, txToFragmentHandlerFactory handlerFactory(*aResult); es.mOutputHandlerFactory = &handlerFactory; - es.init(*sourceNode, &mVariables); + rv = es.init(*sourceNode, &mVariables); // Process root of XML source document - rv = txXSLTProcessor::execute(es); + if (NS_SUCCEEDED(rv)) { + rv = txXSLTProcessor::execute(es); + } // XXX setup exception context, bug 204658 es.end(rv); diff --git a/extensions/transformiix/source/xslt/txVariableMap.h b/extensions/transformiix/source/xslt/txVariableMap.h index 29964a80..7d8afe36 100644 --- a/extensions/transformiix/source/xslt/txVariableMap.h +++ b/extensions/transformiix/source/xslt/txVariableMap.h @@ -64,11 +64,14 @@ inline txVariableMap::txVariableMap() : mMap(MB_FALSE) { + MOZ_COUNT_CTOR(txVariableMap); } inline txVariableMap::~txVariableMap() { + MOZ_COUNT_DTOR(txVariableMap); + txExpandedNameMap::iterator iter(mMap); while (iter.next()) { txAExprResult* res = NS_STATIC_CAST(txAExprResult*, iter.value()); diff --git a/extensions/transformiix/source/xslt/util/txNodeSorter.cpp b/extensions/transformiix/source/xslt/util/txNodeSorter.cpp index be6b7388..a5371e07 100644 --- a/extensions/transformiix/source/xslt/util/txNodeSorter.cpp +++ b/extensions/transformiix/source/xslt/util/txNodeSorter.cpp @@ -190,7 +190,15 @@ txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs, // Create and set up memoryblock for sort-values and indexarray PRUint32 len = NS_STATIC_CAST(PRUint32, aNodes->size()); - void* mem = PR_Malloc(len * (sizeof(PRUint32) + mNKeys * sizeof(TxObject*))); + + // Don't overflow when calculating the length of the sort buffer. + PRUint32 itemSize = sizeof(PRUint32) + mNKeys * sizeof(TxObject*); + if (mNKeys > (PR_UINT32_MAX - sizeof(PRUint32)) / sizeof(TxObject*) || + len >= PR_UINT32_MAX / itemSize) { + return NS_ERROR_OUT_OF_MEMORY; + } + + void* mem = PR_Malloc(len * itemSize); NS_ENSURE_TRUE(mem, NS_ERROR_OUT_OF_MEMORY); PRUint32* indexes = NS_STATIC_CAST(PRUint32*, mem); diff --git a/intl/uconv/src/nsConverterInputStream.cpp b/intl/uconv/src/nsConverterInputStream.cpp index 362c087b..e059b0af 100644 --- a/intl/uconv/src/nsConverterInputStream.cpp +++ b/intl/uconv/src/nsConverterInputStream.cpp @@ -255,7 +255,8 @@ nsConverterInputStream::Fill(nsresult * aErrorCode) NS_ASSERTION(srcConsumed <= mByteData->GetLength(), "Whoa. The converter should have returned NS_OK_UDEC_MOREINPUT before this point!"); } while (mReplacementChar && - NS_FAILED(*aErrorCode)); + NS_FAILED(*aErrorCode) && + mUnicharData->GetBufferSize() > mUnicharDataLength); mLeftOverBytes = mByteData->GetLength() - srcConsumed; diff --git a/intl/uconv/src/nsUTF8ToUnicode.cpp b/intl/uconv/src/nsUTF8ToUnicode.cpp index 6563dbdc..9bcc6997 100644 --- a/intl/uconv/src/nsUTF8ToUnicode.cpp +++ b/intl/uconv/src/nsUTF8ToUnicode.cpp @@ -64,6 +64,15 @@ NS_IMETHODIMP NS_NewUTF8ToUnicode(nsISupports* aOuter, return res; } +static PRUnichar* EmitSurrogatePair(PRUint32 ucs4, PRUnichar* aDest) +{ + NS_ASSERTION(ucs4 > 0xFFFF, "Should be a supplementary character"); + ucs4 -= 0x00010000; + *aDest++ = 0xD800 | (0x000003FF & (ucs4 >> 10)); + *aDest++ = 0xDC00 | (0x000003FF & ucs4); + return aDest; +} + //---------------------------------------------------------------------- // Class nsUTF8ToUnicode [implementation] @@ -136,12 +145,28 @@ NS_IMETHODIMP nsUTF8ToUnicode::Convert(const char * aSrc, nsresult res = NS_OK; // conversion result + out = aDest; + if (mState == 0xFF) { + // Emit supplementary character left over from previous iteration. If the + // buffer size is insufficient, treat it as an illegal character. + if (aDestLen < 2) { + NS_ERROR("Output buffer insufficient to hold supplementary character"); + mState = 0; + return NS_ERROR_ILLEGAL_INPUT; + } + out = EmitSurrogatePair(mUcs4, out); + mUcs4 = 0; + mState = 0; + mBytes = 1; + mFirst = PR_FALSE; + } + // Set mFirst to PR_FALSE now so we don't have to every time through the ASCII // branch within the loop. if (mFirst && aSrcLen && (0 == (0x80 & (*aSrc)))) mFirst = PR_FALSE; - for (in = aSrc, out = aDest; ((in < inend) && (out < outend)); ++in) { + for (in = aSrc; ((in < inend) && (out < outend)); ++in) { if (0 == mState) { // When mState is zero we expect either a US-ASCII character or a // multi-octet sequence. @@ -227,9 +252,15 @@ NS_IMETHODIMP nsUTF8ToUnicode::Convert(const char * aSrc, } if (mUcs4 > 0xFFFF) { // mUcs4 is in the range 0x10000 - 0x10FFFF. Output a UTF-16 pair - mUcs4 -= 0x00010000; - *out++ = 0xD800 | (0x000003FF & (mUcs4 >> 10)); - *out++ = 0xDC00 | (0x000003FF & mUcs4); + if (out + 2 > outend) { + // insufficient space left in the buffer. Keep mUcs4 for the + // next iteration. + mState = 0xFF; + ++in; + res = NS_OK_UDEC_MOREOUTPUT; + break; + } + out = EmitSurrogatePair(mUcs4, out); } else if (UNICODE_BYTE_ORDER_MARK != mUcs4 || !mFirst) { // Don't output the BOM only if it is the first character *out++ = mUcs4; diff --git a/intl/uconv/ucvcn/nsGBKToUnicode.cpp b/intl/uconv/ucvcn/nsGBKToUnicode.cpp index b56f42f6..fb2925c2 100644 --- a/intl/uconv/ucvcn/nsGBKToUnicode.cpp +++ b/intl/uconv/ucvcn/nsGBKToUnicode.cpp @@ -206,8 +206,7 @@ NS_IMETHODIMP nsGBKToUnicode::ConvertNoBuff(const char* aSrc, *aDest = UCS2_NO_MAPPING; } else { // let's try supplement mapping - NS_ASSERTION(( (iDestlen+1) <= (*aDestLength) ), "no enouth output memory"); - if ( (iDestlen+1) <= (*aDestLength) ) + if ( (iDestlen+1) < (*aDestLength) ) { if(DecodeToSurrogate(aSrc, aDest)) { @@ -218,7 +217,13 @@ NS_IMETHODIMP nsGBKToUnicode::ConvertNoBuff(const char* aSrc, *aDest = UCS2_NO_MAPPING; } } else { - *aDest = UCS2_NO_MAPPING; + if (*aDestLength < 2) { + NS_ERROR("insufficient space in output buffer"); + *aDest = UCS2_NO_MAPPING; + } else { + rv = NS_OK_UDEC_MOREOUTPUT; + break; + } } } } else { diff --git a/intl/uconv/ucvja/nsJapaneseToUnicode.cpp b/intl/uconv/ucvja/nsJapaneseToUnicode.cpp index 629884f9..af9c87e8 100644 --- a/intl/uconv/ucvja/nsJapaneseToUnicode.cpp +++ b/intl/uconv/ucvja/nsJapaneseToUnicode.cpp @@ -50,6 +50,8 @@ static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CI #define SJIS_INDEX mMapIndex[0] #define JIS0208_INDEX mMapIndex[1] #define JIS0212_INDEX gJIS0212Index +#define SJIS_UNMAPPED 0x30FB +#define UNICODE_REPLACEMENT_CHARACTER 0xfffd void nsJapaneseToUnicode::setMapMode() { @@ -153,7 +155,7 @@ NS_IMETHODIMP nsShiftJISToUnicode::Convert( break; default: - *dest++ = 0x30FB; + *dest++ = SJIS_UNMAPPED; } if(dest >= destEnd) goto error1; @@ -176,13 +178,20 @@ NS_IMETHODIMP nsShiftJISToUnicode::Convert( case 1: // Index to table { + + // Error handling: in the case where the second octet is not in the + // valid ranges 0x40-0x7E 0x80-0xFC, unconsume the invalid octet and + // interpret it as the ASCII value. In the case where the second + // octet is in the valid range but there is no mapping for the + // 2-octet sequence, do not unconsume. PRUint8 off = sbIdx[*src]; if(0xFF == off) { - *dest++ = 0x30FB; + src--; + *dest++ = UNICODE_REPLACEMENT_CHARACTER; } else { PRUnichar ch = gJapaneseMap[mData+off]; if(ch == 0xfffd) - ch = 0x30fb; + ch = SJIS_UNMAPPED; *dest++ = ch; } mState = 0; @@ -194,8 +203,10 @@ NS_IMETHODIMP nsShiftJISToUnicode::Convert( case 2: // EUDC { PRUint8 off = sbIdx[*src]; + // Error handling as in case 1 if(0xFF == off) { - *dest++ = 0x30fb; + src--; + *dest++ = UNICODE_REPLACEMENT_CHARACTER; } else { *dest++ = mData + off; } @@ -322,10 +333,10 @@ NS_IMETHODIMP nsEUCJPToUnicodeV2::Convert( if(0xFF == off) { *dest++ = 0xFFFD; // if the first byte is valid for EUC-JP but the second - // is not while being a valid US-ASCII(i.e. < 0xc0), save it + // is not while being a valid US-ASCII, save it // instead of eating it up ! - if ( ! (*src & 0xc0) ) - *dest++ = (PRUnichar) *src;; + if ( (PRUint8)*src < (PRUint8)0x7f ) + --src; } else { *dest++ = gJapaneseMap[mData+off]; } @@ -344,7 +355,7 @@ NS_IMETHODIMP nsEUCJPToUnicodeV2::Convert( // if 0x8e is not followed by a valid JIS X 0201 byte // but by a valid US-ASCII, save it instead of eating it up. if ( (PRUint8)*src < (PRUint8)0x7f ) - *dest++ = (PRUnichar) *src; + --src; } mState = 0; if(dest >= destEnd) diff --git a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp index 9b39262b..a89dcdbf 100644 --- a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp +++ b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp @@ -42,14 +42,16 @@ #include #include "prtypes.h" -#define STATE_NORMAL 0 -#define STATE_HALF_CODE_POINT 1 -#define STATE_FIRST_CALL 2 -#define STATE_FOUND_BOM 3 +#define STATE_NORMAL 0 +#define STATE_HALF_CODE_POINT 1 +#define STATE_FIRST_CALL 2 +#define STATE_FOUND_BOM 3 +#define STATE_ODD_SURROGATE_PAIR 4 static nsresult UTF16ConvertToUnicode(PRUint8& aState, PRUint8& aOddByte, - PRUnichar& aOddHighSurrogate, const char * aSrc, + PRUnichar& aOddHighSurrogate, PRUnichar& aOddLowSurrogate, + const char * aSrc, PRInt32 * aSrcLength, PRUnichar * aDest, PRInt32 * aDestLength, PRBool aSwapBytes) @@ -59,32 +61,47 @@ UTF16ConvertToUnicode(PRUint8& aState, PRUint8& aOddByte, PRUnichar* dest = aDest; PRUnichar* destEnd = aDest + *aDestLength; - if(STATE_FOUND_BOM == aState) // caller found a BOM - { - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; - src+=2; - aState = STATE_NORMAL; - } else if(STATE_FIRST_CALL == aState) { // first time called - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; - - // Eliminate BOM (0xFEFF). Note that different endian case is taken care of - // in |Convert| of LE and BE converters. Here, we only have to - // deal with the same endian case. That is, 0xFFFE (byte-swapped BOM) is - // illegal. - if(0xFEFF == *((PRUnichar*)src)) { + switch(aState) { + case STATE_FOUND_BOM: + NS_ASSERTION(*aSrcLength > 1, "buffer too short"); src+=2; - } else if(0xFFFE == *((PRUnichar*)src)) { - *aSrcLength=0; - *aDestLength=0; - return NS_ERROR_ILLEGAL_INPUT; - } - aState = STATE_NORMAL; + aState = STATE_NORMAL; + break; + case STATE_FIRST_CALL: // first time called + NS_ASSERTION(*aSrcLength > 1, "buffer too short"); + // Eliminate BOM (0xFEFF). Note that different endian case is taken care + // of in |Convert| of LE and BE converters. Here, we only have to + // deal with the same endian case. That is, 0xFFFE (byte-swapped BOM) is + // illegal. + if(0xFEFF == *((PRUnichar*)src)) { + src+=2; + } else if(0xFFFE == *((PRUnichar*)src)) { + *aSrcLength=0; + *aDestLength=0; + return NS_ERROR_ILLEGAL_INPUT; + } + aState = STATE_NORMAL; + break; + + case STATE_ODD_SURROGATE_PAIR: + if (*aDestLength < 2) + *dest++ = UCS2_REPLACEMENT_CHAR; + else { + *dest++ = aOddHighSurrogate; + *dest++ = aOddLowSurrogate; + aOddHighSurrogate = aOddLowSurrogate = 0; + aState = STATE_NORMAL; + } + break; + + case STATE_NORMAL: + case STATE_HALF_CODE_POINT: + default: + break; } if (src == srcEnd) { - *aDestLength = 0; + *aDestLength = dest - aDest; return NS_OK; } @@ -136,17 +153,19 @@ have_codepoint: oddHighSurrogate = u; } else /* if (IS_LOW_SURROGATE(u)) */ { - if (oddHighSurrogate) { - if (dest == destEnd - 1) { - *dest++ = UCS2_REPLACEMENT_CHAR; + if (oddHighSurrogate && *aDestLength > 1) { + if (dest + 1 >= destEnd) { + aOddLowSurrogate = u; + aOddHighSurrogate = oddHighSurrogate; + aState = STATE_ODD_SURROGATE_PAIR; goto error; } *dest++ = oddHighSurrogate; *dest++ = u; - oddHighSurrogate = 0; } else { *dest++ = UCS2_REPLACEMENT_CHAR; } + oddHighSurrogate = 0; } } if (src != srcEnd) { @@ -173,6 +192,7 @@ nsUTF16ToUnicodeBase::Reset() mState = STATE_FIRST_CALL; mOddByte = 0; mOddHighSurrogate = 0; + mOddLowSurrogate = 0; return NS_OK; } @@ -181,9 +201,11 @@ nsUTF16ToUnicodeBase::GetMaxLength(const char * aSrc, PRInt32 aSrcLength, PRInt32 * aDestLength) { // the left-over data of the previous run have to be taken into account. - *aDestLength = (aSrcLength + - ((STATE_HALF_CODE_POINT == mState) ? 1 : 0)) / 2 + - ((mOddHighSurrogate != 0) ? 1 : 0); + *aDestLength = (aSrcLength + ((STATE_HALF_CODE_POINT == mState) ? 1 : 0)) / 2; + if (mOddHighSurrogate) + (*aDestLength)++; + if (mOddLowSurrogate) + (*aDestLength)++; return NS_OK; } @@ -192,14 +214,19 @@ NS_IMETHODIMP nsUTF16BEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, PRUnichar * aDest, PRInt32 * aDestLength) { + if(STATE_FIRST_CALL == mState && *aSrcLength < 2) + { + nsresult res = (*aSrcLength == 0) ? NS_OK : NS_ERROR_ILLEGAL_INPUT; + *aSrcLength=0; + *aDestLength=0; + return res; + } #ifdef IS_LITTLE_ENDIAN // Remove the BOM if we're little-endian. The 'same endian' case with the // leading BOM will be taken care of by |UTF16ConvertToUnicode|. if(STATE_FIRST_CALL == mState) // Called for the first time. { mState = STATE_NORMAL; - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; if(0xFFFE == *((PRUnichar*)aSrc)) { // eliminate BOM (on LE machines, BE BOM is 0xFFFE) mState = STATE_FOUND_BOM; @@ -212,6 +239,7 @@ nsUTF16BEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, #endif nsresult rv = UTF16ConvertToUnicode(mState, mOddByte, mOddHighSurrogate, + mOddLowSurrogate, aSrc, aSrcLength, aDest, aDestLength, #ifdef IS_LITTLE_ENDIAN PR_TRUE @@ -226,14 +254,19 @@ NS_IMETHODIMP nsUTF16LEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, PRUnichar * aDest, PRInt32 * aDestLength) { + if(STATE_FIRST_CALL == mState && *aSrcLength < 2) + { + nsresult res = (*aSrcLength == 0) ? NS_OK : NS_ERROR_ILLEGAL_INPUT; + *aSrcLength=0; + *aDestLength=0; + return res; + } #ifdef IS_BIG_ENDIAN // Remove the BOM if we're big-endian. The 'same endian' case with the // leading BOM will be taken care of by |UTF16ConvertToUnicode|. if(STATE_FIRST_CALL == mState) // first time called { mState = STATE_NORMAL; - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; if(0xFFFE == *((PRUnichar*)aSrc)) { // eliminate BOM (on BE machines, LE BOM is 0xFFFE) mState = STATE_FOUND_BOM; @@ -246,6 +279,7 @@ nsUTF16LEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, #endif nsresult rv = UTF16ConvertToUnicode(mState, mOddByte, mOddHighSurrogate, + mOddLowSurrogate, aSrc, aSrcLength, aDest, aDestLength, #ifdef IS_BIG_ENDIAN PR_TRUE @@ -268,12 +302,16 @@ NS_IMETHODIMP nsUTF16ToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, PRUnichar * aDest, PRInt32 * aDestLength) { + if(STATE_FIRST_CALL == mState && *aSrcLength < 2) + { + nsresult res = (*aSrcLength == 0) ? NS_OK : NS_ERROR_ILLEGAL_INPUT; + *aSrcLength=0; + *aDestLength=0; + return res; + } if(STATE_FIRST_CALL == mState) // first time called { mState = STATE_NORMAL; - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; - // check if BOM (0xFEFF) is at the beginning, remove it if found, and // set mEndian accordingly. if(0xFF == PRUint8(aSrc[0]) && 0xFE == PRUint8(aSrc[1])) { @@ -304,6 +342,7 @@ nsUTF16ToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, } nsresult rv = UTF16ConvertToUnicode(mState, mOddByte, mOddHighSurrogate, + mOddLowSurrogate, aSrc, aSrcLength, aDest, aDestLength, #ifdef IS_BIG_ENDIAN (mEndian == kLittleEndian) diff --git a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.h b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.h index 0cf5bfea..7c3d2943 100644 --- a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.h +++ b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.h @@ -62,6 +62,8 @@ protected: PRUint8 mOddByte; // to store an odd high surrogate left over between runs PRUnichar mOddHighSurrogate; + // to store an odd low surrogate left over between runs + PRUnichar mOddLowSurrogate; }; // UTF-16 big endian diff --git a/js/src/jsapi.c b/js/src/jsapi.c index b2e27898..7a4e60fd 100644 --- a/js/src/jsapi.c +++ b/js/src/jsapi.c @@ -4829,7 +4829,7 @@ JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline) CHECK_REQUEST(cx); /* No locking required, cx is thread-private and input must be live. */ res = &cx->regExpStatics; - res->input = input; + res->pendingInput = input; res->multiline = multiline; cx->runtime->gcPoke = JS_TRUE; } @@ -4841,11 +4841,7 @@ JS_ClearRegExpStatics(JSContext *cx) /* No locking required, cx is thread-private and input must be live. */ res = &cx->regExpStatics; - res->input = NULL; - res->multiline = JS_FALSE; - res->parenCount = 0; - res->lastMatch = res->lastParen = js_EmptySubString; - res->leftContext = res->rightContext = js_EmptySubString; + js_RegExpStatics_clear(cx, res); cx->runtime->gcPoke = JS_TRUE; } @@ -4857,6 +4853,7 @@ JS_ClearRegExpRoots(JSContext *cx) /* No locking required, cx is thread-private and input must be live. */ res = &cx->regExpStatics; res->input = NULL; + res->pendingInput = NULL; cx->runtime->gcPoke = JS_TRUE; } diff --git a/js/src/jsbit.h b/js/src/jsbit.h index 87bb0476..e612eb68 100644 --- a/js/src/jsbit.h +++ b/js/src/jsbit.h @@ -190,6 +190,25 @@ js_FloorLog2wImpl(JSUword n); #endif +/* + * Macros for rotate left. There is no rotate operation in the C Language so + * the construct (a << 4) | (a >> 28) is used instead. Most compilers convert + * this to a rotate instruction but some versions of MSVC don't without a + * little help. To get MSVC to generate a rotate instruction, we have to use + * the _rotl intrinsic and use a pragma to make _rotl inline. + * + * MSVC in VS2005 will do an inline rotate instruction on the above construct. + */ + +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \ + defined(_M_X64)) +#include +#pragma intrinsic(_rotl) +#define JS_ROTATE_LEFT32(a, bits) _rotl(a, bits) +#else +#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) +#endif + JS_END_EXTERN_C #endif /* jsbit_h___ */ diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index ee10d377..8f46eb14 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -912,7 +912,7 @@ typedef enum JSErrNum { JSErr_Limit } JSErrNum; -extern const JSErrorFormatString * +extern JS_PUBLIC_API(const JSErrorFormatString *) js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber); #ifdef va_start diff --git a/js/src/jsdbgapi.c b/js/src/jsdbgapi.c index 7bcec506..93ff1146 100644 --- a/js/src/jsdbgapi.c +++ b/js/src/jsdbgapi.c @@ -587,21 +587,23 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id, attrs = sprop->attrs; flags = sprop->flags; shortid = sprop->shortid; + JS_UNLOCK_OBJ(cx, pobj); } else { - if (!OBJ_GET_PROPERTY(cx, pobj, id, &value) || - !OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs)) { - OBJ_DROP_PROPERTY(cx, pobj, prop); + OBJ_DROP_PROPERTY(cx, pobj, prop); + + if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) || + !OBJ_GET_ATTRIBUTES(cx, pobj, propid, NULL, &attrs)) { return JS_FALSE; } getter = setter = NULL; flags = 0; shortid = 0; } - OBJ_DROP_PROPERTY(cx, pobj, prop); /* Recall that obj is native, whether or not pobj is native. */ - if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter, - attrs, flags, shortid, &prop)) { + if (!js_DefineNativeProperty(cx, obj, propid, value, + getter, setter, attrs, flags, + shortid, &prop)) { return JS_FALSE; } sprop = (JSScopeProperty *) prop; diff --git a/js/src/jsobj.c b/js/src/jsobj.c index deecc603..232bb652 100644 --- a/js/src/jsobj.c +++ b/js/src/jsobj.c @@ -431,9 +431,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) #if JS_HAS_GETTER_SETTER JSObject *obj2; JSProperty *prop; - uintN attrs; #endif - jsval val; int stackDummy; if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { @@ -469,44 +467,60 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) ok = JS_TRUE; for (i = 0, length = ida->length; i < length; i++) { + JSTempValueRooter v; + JSTempValueRooter setter; + PRBool hasGetter, hasSetter; + id = ida->vector[i]; + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_VOID, &v); #if JS_HAS_GETTER_SETTER ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop); if (!ok) - break; + goto brk; if (!prop) - continue; - ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs); - if (ok) { - if (OBJ_IS_NATIVE(obj2) && - (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { - val = JSVAL_NULL; - if (attrs & JSPROP_GETTER) - val = (jsval) ((JSScopeProperty*)prop)->getter; - if (attrs & JSPROP_SETTER) { - if (val != JSVAL_NULL) { - /* Mark the getter, then set val to setter. */ - ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), - NULL) - != NULL); - } - val = (jsval) ((JSScopeProperty*)prop)->setter; - } - } else { - ok = OBJ_GET_PROPERTY(cx, obj, id, &val); - } + goto cont; + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_VOID, &setter); + if (!OBJ_IS_NATIVE(obj2)) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + hasGetter = hasSetter = PR_FALSE; + } else { + JSScopeProperty *sprop = (JSScopeProperty *) prop; + uintN attrs = sprop->attrs; + hasGetter = (attrs & JSPROP_GETTER); + hasSetter = (attrs & JSPROP_SETTER); + if (hasGetter) + v.u.value = (jsval) ((JSScopeProperty*)sprop)->getter; + if (hasSetter) + setter.u.value = (jsval) ((JSScopeProperty*)sprop)->setter; + JS_UNLOCK_OBJ(cx, obj2); } - OBJ_DROP_PROPERTY(cx, obj2, prop); + if (hasSetter) { + /* Mark the getter, then set value to setter. */ + if (hasGetter && !JSVAL_IS_PRIMITIVE(v.u.value)) { + ok = !!MarkSharpObjects(cx, JSVAL_TO_OBJECT(v.u.value), NULL); + } + if (ok) + v.u.value = setter.u.value; + } else if (!hasGetter) { + ok = OBJ_GET_PROPERTY(cx, obj, id, &(v.u.value)); + } + JS_POP_TEMP_ROOT(cx, &setter); #else - ok = OBJ_GET_PROPERTY(cx, obj, id, &val); + ok = OBJ_GET_PROPERTY(cx, obj, id, &(v.u.value)); #endif if (!ok) - break; - if (!JSVAL_IS_PRIMITIVE(val) && - !MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) { + goto brk; + if (!JSVAL_IS_PRIMITIVE(v.u.value) && + !MarkSharpObjects(cx, JSVAL_TO_OBJECT(v.u.value), NULL)) { ok = JS_FALSE; - break; + goto brk; } + cont: + JS_POP_TEMP_ROOT(cx, &v); + continue; + brk: + JS_POP_TEMP_ROOT(cx, &v); + break; } if (!ok || !idap) JS_DestroyIdArray(cx, ida); @@ -866,13 +880,9 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, valcnt = 0; if (prop) { - ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs); - if (!ok) { - OBJ_DROP_PROPERTY(cx, obj2, prop); - goto error; - } - if (OBJ_IS_NATIVE(obj2) && - (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { + if (OBJ_IS_NATIVE(obj2)) { + JSScopeProperty *sprop = (JSScopeProperty *) prop; + attrs = sprop->attrs; if (attrs & JSPROP_GETTER) { val[valcnt] = (jsval) ((JSScopeProperty *)prop)->getter; gsopold[valcnt] = @@ -889,13 +899,18 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, ATOM_TO_STRING(cx->runtime->atomState.setAtom); valcnt++; } + JS_UNLOCK_OBJ(cx, obj2); } else { + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + if (!valcnt) { valcnt = 1; gsop[0] = NULL; gsopold[0] = NULL; ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]); + if (!ok) + goto error; } - OBJ_DROP_PROPERTY(cx, obj2, prop); } #else /* !JS_HAS_GETTER_SETTER */ @@ -911,11 +926,11 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, gsopold[0] = NULL; ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]); -#endif /* !JS_HAS_GETTER_SETTER */ - if (!ok) goto error; +#endif /* !JS_HAS_GETTER_SETTER */ + /* * If id is a string that's not an identifier, then it needs to be * quoted. Also, negative integer ids must be quoted. @@ -3204,6 +3219,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, const JSCodeSpec *cs; uint32 format; JSBool ok; + JSTempValueRooter tvr, tvr2; /* * Handle old bug that took empty string as zero index. Also convert @@ -3296,7 +3312,9 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, if (!MAP_IS_NATIVE(&scope->map)) { /* Whoops, newresolve handed back a foreign obj2. */ JS_ASSERT(obj2 != obj); + JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(obj2), &tvr); ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp); + JS_POP_TEMP_ROOT(cx, &tvr); if (!ok || *propp) goto cleanup; JS_LOCK_OBJ(cx, obj2); @@ -3356,8 +3374,13 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, JS_UNLOCK_OBJ(cx, obj); if (!proto) break; - if (!OBJ_IS_NATIVE(proto)) - return OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp); + if (!OBJ_IS_NATIVE(proto)) { + JSBool ret; + JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(proto), &tvr2); + ret = OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp); + JS_POP_TEMP_ROOT(cx, &tvr2); + return ret; + } obj = proto; } @@ -4601,7 +4624,7 @@ js_ValueToObject(JSContext *cx, jsval v, JSObject **objp) obj = JSVAL_TO_OBJECT(v); if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_OBJECT, &v)) return JS_FALSE; - if (JSVAL_IS_OBJECT(v)) + if (!JSVAL_IS_PRIMITIVE(v)) obj = JSVAL_TO_OBJECT(v); } else { if (JSVAL_IS_STRING(v)) { @@ -4983,6 +5006,12 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v) return JS_TRUE; } +JS_FRIEND_API(void) +js_SetObjectWeakRoot(JSContext *cx, JSObject *obj) +{ + cx->weakRoots.newborn[GCX_OBJECT] = obj; +} + #ifdef DEBUG /* Routines to print out values during debugging. */ diff --git a/js/src/jsobj.h b/js/src/jsobj.h index a67e7327..74805670 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -597,6 +597,9 @@ extern const char * js_ComputeFilename(JSContext *cx, JSStackFrame *caller, JSPrincipals *principals, uintN *linenop); +JS_FRIEND_API(void) +js_SetObjectWeakRoot(JSContext *cx, JSObject *obj); + JS_END_EXTERN_C #endif /* jsobj_h___ */ diff --git a/js/src/jsregexp.c b/js/src/jsregexp.c index febc289b..d3c9f132 100644 --- a/js/src/jsregexp.c +++ b/js/src/jsregexp.c @@ -2684,7 +2684,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) jsbytecode *nextpc, *testpc; REOp nextop; RECapture *cap; - REProgState *curState; + REProgState *curState=NULL; const jschar *startcp; size_t parenIndex, k; size_t parenSoFar = 0; @@ -2809,7 +2809,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) * Occurs at (successful) end of REOP_ALT, */ case REOP_JUMP: - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; pc += GET_OFFSET(pc); op = (REOp) *pc++; continue; @@ -2818,7 +2819,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) * Occurs at last (successful) end of REOP_ALT, */ case REOP_ENDALT: - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; op = (REOp) *pc++; continue; @@ -2895,7 +2897,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) continue; case REOP_ASSERTTEST: - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; --curState; x->cp = gData->cpbegin + curState->index; gData->backTrackSP = @@ -2907,7 +2910,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) break; case REOP_ASSERTNOTTEST: - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; --curState; x->cp = gData->cpbegin + curState->index; gData->backTrackSP = @@ -2987,7 +2991,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) CHECK_BRANCH(); --curState; do { - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; if (!result) { /* Failed, see if we have enough children. */ if (curState->u.quantifier.min == 0) @@ -3075,7 +3080,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) pc, x, x->cp, 0, 0)) { return NULL; } - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; pc = pc + GET_OFFSET(pc); op = (REOp) *pc++; } @@ -3083,7 +3089,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) case REOP_MINIMALREPEAT: CHECK_BRANCH(); - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; --curState; if (!result) { @@ -3135,7 +3142,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) parenSoFar - curState->parenSoFar)) { return NULL; } - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; pc = pc + GET_OFFSET(pc); op = (REOp) *pc++; continue; @@ -3162,6 +3170,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) pc = backTrackData->backtrack_pc; op = backTrackData->backtrack_op; gData->stateStackTop = backTrackData->saveStateStackTop; + JS_ASSERT(gData->stateStackTop); memcpy(gData->stateStack, backTrackData + 1, @@ -3270,6 +3279,21 @@ bad: return NULL; } +void +js_RegExpStatics_clear(JSContext *cx, JSRegExpStatics *res) +{ + res->input = NULL; + res->pendingInput = NULL; + res->multiline = JS_FALSE; + res->parenCount = 0; + res->lastMatch = res->lastParen = js_EmptySubString; + res->leftContext = res->rightContext = js_EmptySubString; + if (res->moreParens) { + JS_free(cx, res->moreParens); + res->moreParens = NULL; + } +} + JSBool js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, JSBool test, jsval *rval) @@ -3375,7 +3399,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, } res = &cx->regExpStatics; - res->input = str; + res->pendingInput = res->input = str; res->parenCount = re->parenCount; if (re->parenCount == 0) { res->lastParen = js_EmptySubString; @@ -3478,6 +3502,8 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, res->rightContext.length = gData.cpend - ep; out: + if (!ok) + js_RegExpStatics_clear(cx,res); JS_FinishArenaPool(&gData.pool); return ok; } @@ -3580,8 +3606,11 @@ enum regexp_static_tinyid { JSBool js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res) { + JSBool in, pd; JS_ClearRegExpStatics(cx); - return js_AddRoot(cx, &res->input, "res->input"); + in = js_AddRoot(cx, &res->input, "res->input"); + pd = js_AddRoot(cx, &res->pendingInput, "res->input"); + return in && pd; } void @@ -3592,6 +3621,7 @@ js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res) res->moreParens = NULL; } js_RemoveRoot(cx->runtime, &res->input); + js_RemoveRoot(cx->runtime, &res->pendingInput); } static JSBool @@ -3608,8 +3638,8 @@ regexp_static_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) slot = JSVAL_TO_INT(id); switch (slot) { case REGEXP_STATIC_INPUT: - *vp = res->input ? STRING_TO_JSVAL(res->input) - : JS_GetEmptyStringValue(cx); + *vp = res->pendingInput ? STRING_TO_JSVAL(res->pendingInput) + : JS_GetEmptyStringValue(cx); return JS_TRUE; case REGEXP_STATIC_MULTILINE: *vp = BOOLEAN_TO_JSVAL(res->multiline); @@ -3651,7 +3681,7 @@ regexp_static_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) { return JS_FALSE; } - res->input = JSVAL_TO_STRING(*vp); + res->pendingInput = JSVAL_TO_STRING(*vp); } else if (JSVAL_TO_INT(id) == REGEXP_STATIC_MULTILINE) { if (!JSVAL_IS_BOOLEAN(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp)) { @@ -4018,7 +4048,7 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* Now that obj is unlocked, it's safe to (potentially) grab the GC lock. */ if (argc == 0) { - str = cx->regExpStatics.input; + str = cx->regExpStatics.pendingInput; if (!str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_INPUT, diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index 50789832..2996fbbe 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -52,6 +52,7 @@ struct JSRegExpStatics { JSString *input; /* input string to match (perl $_, GC root) */ + JSString *pendingInput; /* pending input string to match */ JSBool multiline; /* whether input contains newlines (perl $*) */ uint16 parenCount; /* number of valid elements in parens[] */ uint16 moreLength; /* number of allocated elements in moreParens */ @@ -63,6 +64,9 @@ struct JSRegExpStatics { JSSubString rightContext; /* input to right of last match (perl $') */ }; +void +js_RegExpStatics_clear(JSContext *cx, JSRegExpStatics *res); + /* * This struct holds a bitmap representation of a class from a regexp. * There's a list of these referenced by the classList field in the JSRegExp diff --git a/js/src/jsxml.c b/js/src/jsxml.c index a07cc69d..c7f53c9b 100644 --- a/js/src/jsxml.c +++ b/js/src/jsxml.c @@ -6028,7 +6028,8 @@ xml_elements(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, nameqn = ToXMLName(cx, name, &funid); if (!nameqn) return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nameqn->object); + if (argc) + argv[0] = OBJECT_TO_JSVAL(nameqn->object); list = xml_list_helper(cx, xml, rval); if (!list) diff --git a/js/src/liveconnect/jsj_JavaArray.c b/js/src/liveconnect/jsj_JavaArray.c index 38e80631..a327d768 100644 --- a/js/src/liveconnect/jsj_JavaArray.c +++ b/js/src/liveconnect/jsj_JavaArray.c @@ -254,6 +254,7 @@ JavaArray_lookupProperty(JSContext *cx, JSObject *obj, jsid id, if (access_java_array_element(cx, jEnv, obj, id, NULL, JS_FALSE)) { *objp = obj; *propp = (JSProperty*)1; + js_SetObjectWeakRoot(cx, obj); } else { *objp = NULL; *propp = NULL; diff --git a/js/src/liveconnect/jsj_JavaClass.c b/js/src/liveconnect/jsj_JavaClass.c index ebf7104b..27b981e7 100644 --- a/js/src/liveconnect/jsj_JavaClass.c +++ b/js/src/liveconnect/jsj_JavaClass.c @@ -321,6 +321,7 @@ JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id, if (lookup_static_member_by_id(cx, jEnv, obj, NULL, id, NULL)) { *objp = obj; *propp = (JSProperty*)1; + js_SetObjectWeakRoot(cx, obj); } else { *objp = NULL; *propp = NULL; diff --git a/js/src/liveconnect/jsj_JavaObject.c b/js/src/liveconnect/jsj_JavaObject.c index 91209213..59e8b83a 100644 --- a/js/src/liveconnect/jsj_JavaObject.c +++ b/js/src/liveconnect/jsj_JavaObject.c @@ -832,6 +832,7 @@ JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id, *objp = obj; *propp = (JSProperty*)1; } + js_SetObjectWeakRoot(cx, *objp); } else { *objp = NULL; *propp = NULL; diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index eaf5eb91..5352760a 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -688,9 +688,9 @@ interface nsIXPConnect : nsISupports interface nsIXPConnect_MOZILLA_1_8_BRANCH : nsIXPConnect { void - reparentScopeAwareWrappers(in JSContextPtr aJSContext, - in JSObjectPtr aOldScope, - in JSObjectPtr aNewScope); + moveWrappers(in JSContextPtr aJSContext, + in JSObjectPtr aOldScope, + in JSObjectPtr aNewScope); /** * Create a sandbox for evaluating code in isolation using diff --git a/js/src/xpconnect/src/Makefile.in b/js/src/xpconnect/src/Makefile.in index abfe5402..36602ebc 100644 --- a/js/src/xpconnect/src/Makefile.in +++ b/js/src/xpconnect/src/Makefile.in @@ -65,6 +65,7 @@ REQUIRES = xpcom \ caps \ necko \ dom \ + widget \ $(NULL) CPPSRCS = \ diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index 6bcf2694..47632d03 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -1127,9 +1127,16 @@ MirrorWrappedNativeParent(JSContext *cx, XPCWrappedNative *wrapper, XPCWrappedNative *parent_wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wn_parent); - *result = XPCNativeWrapper::GetNewOrUsed(cx, parent_wrapper, nsnull, nsnull); - if (!*result) - return JS_FALSE; + // parent_wrapper can be null if we're in a Components.utils.evalInSandbox + // scope. In that case, the best we can do is just use the + // non-native-wrapped sandbox global object for our parent. + if (parent_wrapper) { + *result = XPCNativeWrapper::GetNewOrUsed(cx, parent_wrapper, nsnull, nsnull); + if (!*result) + return JS_FALSE; + } else { + *result = nsnull; + } } return JS_TRUE; } diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 00013239..4631356f 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -779,11 +779,11 @@ MoveableWrapperFinder(JSDHashTable *table, JSDHashEntryHdr *hdr, return JS_DHASH_NEXT; } -/* void reparentScopeAwareWrappers(in JSContextPtr aJSContext, in JSObjectPtr aOldScope, in JSObjectPtr aNewScope); */ +/* void moveWrappers(in JSContextPtr aJSContext, in JSObjectPtr aOldScope, in JSObjectPtr aNewScope); */ NS_IMETHODIMP -nsXPConnect::ReparentScopeAwareWrappers(JSContext *aJSContext, - JSObject *aOldScope, - JSObject *aNewScope) +nsXPConnect::MoveWrappers(JSContext *aJSContext, + JSObject *aOldScope, + JSObject *aNewScope) { XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) @@ -840,35 +840,41 @@ nsXPConnect::ReparentScopeAwareWrappers(JSContext *aJSContext, if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + JSObject *newParent = aOldScope; + // If the wrapper doesn't want precreate, then we don't need to // worry about reparenting it. if(!sciWrapper.GetFlags().WantPreCreate()) continue; - JSObject *newParent = aOldScope; rv = sciWrapper.GetCallback()->PreCreate(identity, ccx, aOldScope, &newParent); if(NS_FAILED(rv)) return rv; - if(newParent != aOldScope) + if(newParent == aOldScope) { - // The wrapper returned a new parent. If the new parent is in - // a different scope, then we need to reparent it, otherwise, - // the old scope is fine. + // The old scope still works for this wrapper. We have to assume + // that the wrapper will continue to return the old scope from + // PreCreate, so don't move it. + continue; + } - XPCWrappedNativeScope *betterScope = - XPCWrappedNativeScope::FindInJSObjectScope(ccx, newParent); - if(betterScope == oldScope) - continue; - - NS_ASSERTION(betterScope == newScope, "Weird scope returned"); - } - else - { - // The old scope still works for this wrapper. - continue; - } + // The wrapper returned a new parent. If the new parent is in + // a different scope, then we need to reparent it, otherwise, + // the old scope is fine. + + XPCWrappedNativeScope *betterScope = + XPCWrappedNativeScope::FindInJSObjectScope(ccx, newParent); + if(betterScope == oldScope) + { + // The wrapper asked for a different object, but that object + // was in the same scope. We assume here that the new parent + // simply hasn't been reparented yet. + newParent = nsnull; + } + else + NS_ASSERTION(betterScope == newScope, "Weird scope returned"); // Now, reparent the wrapper, since we know that it wants to be // reparented. diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 0407c27e..f8006652 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -1910,7 +1910,14 @@ nsXPCComponents_Utils::LookupMethod() return NS_ERROR_XPC_BAD_CONVERT_JS; JSObject* obj = JSVAL_TO_OBJECT(argv[0]); + { + XPCWrappedNative *wn = + XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); + if(!wn) + return NS_ERROR_XPC_BAD_CONVERT_JS; + obj = wn->GetFlatJSObject(); + } // Can't use the macro OBJ_TO_INNER_OBJECT here due to it using // the non-exported function js_GetSlotThreadSafe(). { @@ -1921,6 +1928,8 @@ nsXPCComponents_Utils::LookupMethod() obj = xclasp->innerObject(cx, obj); } } + if(!obj) + return NS_ERROR_XPC_BAD_CONVERT_JS; // second param must be a string if(!JSVAL_IS_STRING(argv[1])) diff --git a/js/src/xpconnect/src/xpcthreadcontext.cpp b/js/src/xpconnect/src/xpcthreadcontext.cpp index bf3c5c3b..8c38de30 100644 --- a/js/src/xpconnect/src/xpcthreadcontext.cpp +++ b/js/src/xpconnect/src/xpcthreadcontext.cpp @@ -42,6 +42,8 @@ /* Implement global service to track stack of JSContext per thread. */ #include "xpcprivate.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptContext.h" /***************************************************************************/ @@ -117,6 +119,20 @@ XPCJSContextStack::Pop(JSContext * *_retval) return NS_OK; } +static nsIPrincipal* +GetPrincipalFromCx(JSContext *cx) +{ + nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) + { + nsCOMPtr globalData = + do_QueryInterface(scriptContext->GetGlobalObject()); + if (globalData) + return globalData->GetPrincipal(); + } + return nsnull; +} + /* void push (in JSContext cx); */ NS_IMETHODIMP XPCJSContextStack::Push(JSContext * cx) @@ -126,8 +142,33 @@ XPCJSContextStack::Push(JSContext * cx) if(mStack.Length() > 1) { JSContextAndFrame & e = mStack[mStack.Length() - 2]; - if(e.cx && e.cx != cx) - e.frame = JS_SaveFrameChain(e.cx); + if(e.cx) + { + if (e.cx == cx) + { nsresult rv; + nsCOMPtr ssm = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv) && ssm) + { + nsIPrincipal* globalObjectPrincipal = + GetPrincipalFromCx(cx); + if (globalObjectPrincipal) + { + nsCOMPtr subjectPrincipal; + ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)); + + PRBool equals = PR_FALSE; + globalObjectPrincipal->Equals(subjectPrincipal, &equals); + if (equals) + { + return NS_OK; + } + } + } + } + + e.frame = JS_SaveFrameChain(e.cx); + } } return NS_OK; } diff --git a/js/src/xpconnect/src/xpcvariant.cpp b/js/src/xpconnect/src/xpcvariant.cpp index f3054c9a..1de0a842 100644 --- a/js/src/xpconnect/src/xpcvariant.cpp +++ b/js/src/xpconnect/src/xpcvariant.cpp @@ -239,6 +239,13 @@ XPCArrayHomogenizer::GetTypeForArray(XPCCallContext& ccx, JSObject* array, JSBool XPCVariant::InitializeData(XPCCallContext& ccx) { + int stackDummy; + + if (!JS_CHECK_STACK_SIZE(ccx.GetJSContext(), stackDummy)) { + JS_ReportErrorNumber(ccx.GetJSContext(), js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); + return JS_FALSE; + } + if(JSVAL_IS_INT(mJSVal)) return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, JSVAL_TO_INT(mJSVal))); @@ -763,5 +770,3 @@ NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(PRUint32 *size, PRUnichar **str) { return nsVariant::ConvertToWStringWithSize(mData, size, str); } - - diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index 344d7a5c..d10b8221 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -238,6 +238,29 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx, jsid funid; jsval fun; + // Don't call the actual function on a content object. We'll determine + // whether or not a content object is capable of implementing the + // interface (i.e. whether the interface is scriptable) and most content + // objects don't have QI implementations anyway. Also see bug 503926. + if(!JS_IsSystemObject(ccx, jsobj)) + { + nsCOMPtr objPrin; + + nsXPConnect *xpc = nsXPConnect::GetXPConnect(); + nsCOMPtr ssm = + do_QueryInterface(xpc->GetDefaultSecurityManager()); + if(ssm) + { + nsresult rv = ssm->GetObjectPrincipal(ccx, jsobj, getter_AddRefs(objPrin)); + NS_ENSURE_SUCCESS(rv, nsnull); + + nsCOMPtr systemPrin; + rv = ssm->GetSystemPrincipal(getter_AddRefs(systemPrin)); + if(systemPrin != objPrin) + return nsnull; + } + } + // check upfront for the existence of the function property funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE); if(!OBJ_GET_PROPERTY(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun)) diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index 524db3eb..2907e5fd 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -1143,7 +1143,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx, // Now we can just fix up the parent and return the wrapper - if(!JS_SetParent(ccx, wrapper->GetFlatJSObject(), aNewParent)) + if(aNewParent && !JS_SetParent(ccx, wrapper->GetFlatJSObject(), aNewParent)) { NS_RELEASE(wrapper); return NS_ERROR_FAILURE; diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index e8f771b6..f09a9b72 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -8572,6 +8572,32 @@ nsCSSFrameConstructor::FindNextSibling(nsIContent* aContainer, return nsnull; } +#ifdef MOZ_XUL + +static +nsIListBoxObject* +MaybeGetListBoxBodyFrame(nsIContent* aContainer, nsIContent* aChild) +{ + NS_PRECONDITION(aContainer, "Must have container here"); + + if (aContainer->IsContentOfType(nsIContent::eXUL) && + aChild->IsContentOfType(nsIContent::eXUL) && + aContainer->Tag() == nsXULAtoms::listbox && + aChild->Tag() == nsXULAtoms::listitem) { + nsCOMPtr xulElement = do_QueryInterface(aContainer); + nsCOMPtr boxObject; + xulElement->GetBoxObject(getter_AddRefs(boxObject)); + nsCOMPtr listBoxObject = do_QueryInterface(boxObject); + if (listBoxObject) { + return listBoxObject->GetListBoxBody(PR_FALSE); + } + } + + return nsnull; +} + +#endif + inline PRBool ShouldIgnoreSelectChild(nsIContent* aContainer) { @@ -8727,6 +8753,20 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, PRUint32 containerCount = aContainer->GetChildCount(); for (PRUint32 i = aNewIndexInContainer; i < containerCount; i++) { nsIContent *child = aContainer->GetChildAt(i); + nsIFrame* primaryFrame = nsnull; + mPresShell->GetPrimaryFrameFor(child,&primaryFrame); + if (primaryFrame +#ifdef MOZ_XUL + // Except listboxes suck, so do NOT skip anything here if + // we plan to notify a listbox. + && !MaybeGetListBoxBodyFrame(aContainer, child) +#endif + ) { + // Already have a frame for this content; a previous ContentInserted + // in this loop must have reconstructed its insertion parent. Skip + // it. + continue; + } if (multiple) { // Filters are in effect, so the insertion point needs to be refetched for // each child. @@ -9203,37 +9243,28 @@ PRBool NotifyListBoxBody(nsPresContext* aPresContext, PRBool aUseXBLForms, content_operation aOperation) { - if (!aContainer) + if (!aContainer) { return PR_FALSE; + } - if (aContainer->IsContentOfType(nsIContent::eXUL) && - aChild->IsContentOfType(nsIContent::eXUL) && - aContainer->Tag() == nsXULAtoms::listbox && - aChild->Tag() == nsXULAtoms::listitem) { - nsCOMPtr xulElement = do_QueryInterface(aContainer); - nsCOMPtr boxObject; - xulElement->GetBoxObject(getter_AddRefs(boxObject)); - nsCOMPtr listBoxObject = do_QueryInterface(boxObject); - if (listBoxObject) { - nsIListBoxObject* listboxBody = listBoxObject->GetListBoxBody(PR_FALSE); - if (listboxBody) { - nsListBoxBodyFrame *listBoxBodyFrame = NS_STATIC_CAST(nsListBoxBodyFrame*, listboxBody); - if (aOperation == CONTENT_REMOVED) { - // Except if we have an aChildFrame and its parent is not the right - // thing, then we don't do this. Pseudo frames are so much fun.... - if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) { - listBoxBodyFrame->OnContentRemoved(aPresContext, aChildFrame, - aIndexInContainer); - return PR_TRUE; - } - } else { - listBoxBodyFrame->OnContentInserted(aPresContext, aChild); - return PR_TRUE; - } + nsIListBoxObject* listboxBody = MaybeGetListBoxBodyFrame(aContainer, aChild); + if (listboxBody) { + nsListBoxBodyFrame *listBoxBodyFrame = static_cast(listboxBody); + if (aOperation == CONTENT_REMOVED) { + // Except if we have an aChildFrame and its parent is not the right + // thing, then we don't do this. Pseudo frames are so much fun.... + if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) { + listBoxBodyFrame->OnContentRemoved(aPresContext, aChildFrame, + aIndexInContainer); + return PR_TRUE; } + } else { + listBoxBodyFrame->OnContentInserted(aPresContext, aChild); + return PR_TRUE; } } + nsCOMPtr tag; PRInt32 namespaceID; aDocument->BindingManager()->ResolveTag(aContainer, &namespaceID, diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 9c958f49..443376f4 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -220,8 +220,6 @@ nsPresContext::nsPresContext(nsPresContextType aType) nsPresContext::~nsPresContext() { - mImageLoaders.Enumerate(destroy_loads); - NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer"); SetShell(nsnull); @@ -775,6 +773,13 @@ nsPresContext::SetShell(nsIPresShell* aShell) UpdateCharSet(doc->GetDocumentCharacterSet()); } } + } else { + // Destroy image loaders now that the presshell is going away. + // This is important since imageloaders can have pointers to frames and + // we don't want those pointers to outlive the destruction of the frame + // arena. + mImageLoaders.Enumerate(destroy_loads, nsnull); + } } @@ -1037,6 +1042,8 @@ nsPresContext::SetTextZoomExternal(float aZoom) imgIRequest* nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame) { + NS_ASSERTION(mShell, "Shouldn't load image after the shell is gone"); + // look and see if we have a loader for the target frame. nsVoidKey key(aTargetFrame); diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 3cfe13dd..b6f1b891 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -3236,6 +3236,8 @@ NS_IMETHODIMP PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) { if (!mIgnoreFrameDestruction) { + mPresContext->StopImagesFor(aFrame); + mFrameConstructor->NotifyDestroyingFrame(aFrame); // Cancel any pending reflow commands targeted at this frame diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 3074727e..12040d85 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -752,17 +752,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, // and we may even delete the line with the line cursor. ClearLineCursor(); - if (IsFrameTreeTooDeep(aReflowState, aMetrics)) { -#ifdef DEBUG_kipp - { - extern char* nsPresShell_ReflowStackPointerTop; - char marker; - char* newsp = (char*) ▮ - printf("XXX: frame tree is too deep; approx stack size = %d\n", - nsPresShell_ReflowStackPointerTop - newsp); - } -#endif - aStatus = NS_FRAME_COMPLETE; + if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) { return NS_OK; } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index ac067b30..afb60872 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -645,10 +645,6 @@ nsFrame::Destroy(nsPresContext* aPresContext) } } - //XXX Why is this done in nsFrame instead of some frame class - // that actually loads images? - aPresContext->StopImagesFor(this); - if (view) { // Break association between view and frame view->SetClientData(nsnull); @@ -2703,9 +2699,11 @@ nsFrame::CheckInvalidateSizeChange(nsPresContext* aPresContext, PRBool nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aMetrics) + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus) { if (aReflowState.mReflowDepth > MAX_FRAME_DEPTH) { + NS_WARNING("frame tree too deep; setting zero size and returning"); mState |= NS_FRAME_IS_UNFLOWABLE; mState &= ~NS_FRAME_OUTSIDE_CHILDREN; aMetrics.width = 0; @@ -2720,6 +2718,16 @@ nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState, if (aMetrics.mComputeMEW) { aMetrics.mMaxElementWidth = 0; } + + if (GetNextInFlow()) { + // Reflow depth might vary between reflows, so we might have + // successfully reflowed and split this frame before. If so, we + // shouldn't delete its continuations. + aStatus = NS_FRAME_NOT_COMPLETE; + } else { + aStatus = NS_FRAME_COMPLETE; + } + return PR_TRUE; } mState &= ~NS_FRAME_IS_UNFLOWABLE; diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index 42605f41..cc5e9ee8 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -350,13 +350,14 @@ public: nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState); - // Helper function that tests if the frame tree is too deep; if it - // is it marks the frame as "unflowable" and zeros out the metrics - // and returns PR_TRUE. Otherwise, the frame is unmarked - // "unflowable" and the metrics are not touched and PR_FALSE is - // returned. + // Helper function that tests if the frame tree is too deep; if it is + // it marks the frame as "unflowable", zeroes out the metrics, sets + // the reflow status, and returns PR_TRUE. Otherwise, the frame is + // unmarked "unflowable" and the metrics and reflow status are not + // touched and PR_FALSE is returned. PRBool IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aMetrics); + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus); // Do the work for getting the parent style context frame so that // other frame's |GetParentStyleContextFrame| methods can call this diff --git a/layout/generic/nsFrameFrame.cpp b/layout/generic/nsFrameFrame.cpp index 4c4ea11f..a339503c 100644 --- a/layout/generic/nsFrameFrame.cpp +++ b/layout/generic/nsFrameFrame.cpp @@ -767,26 +767,6 @@ nsSubDocumentFrame::ShowDocShell() baseWindow->SetVisibility(PR_TRUE); } - // Trigger editor re-initialization if midas is turned on in the - // sub-document. This shouldn't be necessary, but given the way our - // editor works, it is. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=284245 - docShell->GetPresShell(getter_AddRefs(presShell)); - if (presShell) { - nsCOMPtr doc = - do_QueryInterface(presShell->GetDocument()); - - if (doc) { - nsAutoString designMode; - doc->GetDesignMode(designMode); - - if (designMode.EqualsLiteral("on")) { - doc->SetDesignMode(NS_LITERAL_STRING("off")); - doc->SetDesignMode(NS_LITERAL_STRING("on")); - } - } - } - return NS_OK; } diff --git a/layout/generic/nsFrameSetFrame.cpp b/layout/generic/nsFrameSetFrame.cpp index 0c3e7ad0..c142c885 100644 --- a/layout/generic/nsFrameSetFrame.cpp +++ b/layout/generic/nsFrameSetFrame.cpp @@ -355,13 +355,19 @@ nsHTMLFramesetFrame::Init(nsPresContext* aPresContext, NS_ENSURE_SUCCESS(result, result); result = ourContent->GetColSpec(&mNumCols, &colSpecs); NS_ENSURE_SUCCESS(result, result); + + // Maximum value of mNumRows and mNumCols is NS_MAX_FRAMESET_SPEC_COUNT + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nscoord)); mRowSizes = new nscoord[mNumRows]; mColSizes = new nscoord[mNumCols]; if (!mRowSizes || !mColSizes) return NS_ERROR_OUT_OF_MEMORY; + // Ensure we can't overflow numCells + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < PR_INT32_MAX / NS_MAX_FRAMESET_SPEC_COUNT); PRInt32 numCells = mNumRows*mNumCols; + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nsHTMLFramesetBorderFrame*)); mVerBorders = new nsHTMLFramesetBorderFrame*[mNumCols]; // 1 more than number of ver borders if (!mVerBorders) return NS_ERROR_OUT_OF_MEMORY; @@ -375,7 +381,13 @@ nsHTMLFramesetFrame::Init(nsPresContext* aPresContext, for (int horX = 0; horX < mNumRows; horX++) mHorBorders[horX] = nsnull; - + + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT + < UINT_MAX / sizeof(PRInt32) / NS_MAX_FRAMESET_SPEC_COUNT); + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT + < UINT_MAX / sizeof(nsFrameborder) / NS_MAX_FRAMESET_SPEC_COUNT); + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT + < UINT_MAX / sizeof(nsBorderColor) / NS_MAX_FRAMESET_SPEC_COUNT); mChildTypes = new PRInt32[numCells]; mChildFrameborder = new nsFrameborder[numCells]; mChildBorderColors = new nsBorderColor[numCells]; @@ -550,6 +562,9 @@ void nsHTMLFramesetFrame::CalculateRowCol(nsPresContext* aPresContext, const nsFramesetSpec* aSpecs, nscoord* aValues) { + // aNumSpecs maximum value is NS_MAX_FRAMESET_SPEC_COUNT + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(PRInt32)); + PRInt32 fixedTotal = 0; PRInt32 numFixed = 0; PRInt32* fixed = new PRInt32[aNumSpecs]; @@ -1045,6 +1060,11 @@ nsHTMLFramesetFrame::Reflow(nsPresContext* aPresContext, nsFrameborder frameborder = GetFrameBorder(); if (firstTime) { + // Check for overflow in memory allocations using mNumCols and mNumRows + // which have a maxium value of NS_MAX_FRAMESET_SPEC_COUNT. + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(PRBool)); + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nscolor)); + verBordersVis = new PRBool[mNumCols]; verBorderColors = new nscolor[mNumCols]; for (int verX = 0; verX < mNumCols; verX++) { @@ -1360,7 +1380,10 @@ nsHTMLFramesetFrame::RecalculateBorderResize() return; } + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < PR_INT32_MAX / NS_MAX_FRAMESET_SPEC_COUNT); PRInt32 numCells = mNumRows * mNumCols; // max number of cells + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT + < UINT_MAX / sizeof(PRInt32) / NS_MAX_FRAMESET_SPEC_COUNT); PRInt32* childTypes = new PRInt32[numCells]; PRUint32 childIndex, frameOrFramesetChildIndex = 0; diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 59a8304e..9aeee318 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -457,17 +457,7 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, } } - if (IsFrameTreeTooDeep(aReflowState, aMetrics)) { -#ifdef DEBUG_kipp - { - extern char* nsPresShell_ReflowStackPointerTop; - char marker; - char* newsp = (char*) ▮ - printf("XXX: frame tree is too deep; approx stack size = %d\n", - nsPresShell_ReflowStackPointerTop - newsp); - } -#endif - aStatus = NS_FRAME_COMPLETE; + if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) { return NS_OK; } diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index 16d2ba49..94293f19 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -3293,12 +3293,13 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly // look for "data", lets instead copy the "data" attribute and add another entry // to the bottom of the array if there isn't already a "src" specified. - PRInt16 numRealAttrs = mNumCachedAttrs; + PRUint16 numRealAttrs = mNumCachedAttrs; nsAutoString data; nsIAtom *tag = content->Tag(); if (nsHTMLAtoms::object == tag && !content->HasAttr(kNameSpaceID_None, nsHTMLAtoms::src) - && NS_CONTENT_ATTR_NOT_THERE != content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::data, data)) { + && NS_CONTENT_ATTR_NOT_THERE != content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::data, data) + && !data.IsEmpty()) { mNumCachedAttrs++; } @@ -3309,7 +3310,7 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY); // let's fill in our attributes - PRInt16 c = 0; + PRUint32 nextAttrParamIndex = 0; // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the // attribute order. So we want to make sure we give the plugin the @@ -3317,7 +3318,7 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() // other browsers. Now in HTML, the storage order is the reverse of the // source order, while in XML and XHTML it's the same as the source order // (see the AddAttributes functions in the HTML and XML content sinks). - PRInt16 start, end, increment; + PRInt32 start, end, increment; if (content->IsContentOfType(nsIContent::eHTML) && content->GetNodeInfo()->NamespaceEquals(kNameSpaceID_None)) { // HTML. Walk attributes in reverse order. @@ -3330,7 +3331,7 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() end = numRealAttrs; increment = 1; } - for (PRInt16 index = start; index != end; index += increment) { + for (PRInt32 index = start; index != end; index += increment) { PRInt32 nameSpaceID; nsCOMPtr atom; nsCOMPtr prefix; @@ -3344,25 +3345,26 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() mOwner->FixUpURLS(name, value); - mCachedAttrParamNames [c] = ToNewUTF8String(name); - mCachedAttrParamValues[c] = ToNewUTF8String(value); - c++; + mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name); + mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value); + nextAttrParamIndex++; } } // if the conditions above were met, copy the "data" attribute to a "src" array entry - if (data.Length()) { - mCachedAttrParamNames [mNumCachedAttrs-1] = ToNewUTF8String(NS_LITERAL_STRING("SRC")); - mCachedAttrParamValues[mNumCachedAttrs-1] = ToNewUTF8String(data); + if (!data.IsEmpty()) { + mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("SRC")); + mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(data); + nextAttrParamIndex++; } // add our PARAM and null separator - mCachedAttrParamNames [mNumCachedAttrs] = ToNewUTF8String(NS_LITERAL_STRING("PARAM")); - mCachedAttrParamValues[mNumCachedAttrs] = nsnull; + mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("PARAM")); + mCachedAttrParamValues[nextAttrParamIndex] = nsnull; + nextAttrParamIndex++; // now fill in the PARAM name/value pairs from the cached DOM nodes - c = 0; - for (PRInt16 idx = 0; idx < mNumCachedParams; idx++) { + for (PRUint16 idx = 0; idx < mNumCachedParams; idx++) { nsCOMPtr param = do_QueryElementAt(ourParams, idx); if (param) { nsAutoString name; @@ -3384,9 +3386,9 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() */ name.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE); value.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE); - mCachedAttrParamNames [mNumCachedAttrs + 1 + c] = ToNewUTF8String(name); - mCachedAttrParamValues[mNumCachedAttrs + 1 + c] = ToNewUTF8String(value); - c++; // rules! + mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name); + mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value); + nextAttrParamIndex++; } } diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index 0242c863..5119c646 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -6312,6 +6312,9 @@ nsTypedSelection::Collapse(nsIDOMNode* aParentNode, PRInt32 aOffset) return NS_ERROR_INVALID_ARG; if (!mFrameSelection) return NS_ERROR_NOT_INITIALIZED; // Can't do selection + + nsCOMPtr kungfuDeathGrip = aParentNode; + mFrameSelection->InvalidateDesiredX(); if (!IsValidSelectionPoint(mFrameSelection, aParentNode)) return NS_ERROR_FAILURE; diff --git a/layout/style/nsCSSLoader.cpp b/layout/style/nsCSSLoader.cpp index f561bf0a..ac15769a 100644 --- a/layout/style/nsCSSLoader.cpp +++ b/layout/style/nsCSSLoader.cpp @@ -1495,10 +1495,11 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, PRBool aSucceeded) data = data->mNext; } - // Now that it's marked complete, put the sheet in our cache + // Now that it's marked complete, put the sheet in our cache, but + // only if we parsed it case-sensitively. if (aSucceeded && aLoadData->mURI) { #ifdef MOZ_XUL - if (IsChromeURI(aLoadData->mURI)) { + if (IsChromeURI(aLoadData->mURI) && mCaseSensitive) { nsCOMPtr cache(do_GetService("@mozilla.org/xul/xul-prototype-cache;1")); if (cache) { PRBool enabled; diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp index f811605d..56ab2623 100644 --- a/layout/tables/nsCellMap.cpp +++ b/layout/tables/nsCellMap.cpp @@ -324,7 +324,9 @@ nsTableCellMap::Synchronize(nsTableFrame* aTableFrame) if (map) { if (!maps.AppendElement(map)) { delete map; + map = nsnull; NS_WARNING("Could not AppendElement"); + break; } } } diff --git a/layout/xul/base/src/nsListBoxBodyFrame.cpp b/layout/xul/base/src/nsListBoxBodyFrame.cpp index 32992aa7..0b7b9354 100644 --- a/layout/xul/base/src/nsListBoxBodyFrame.cpp +++ b/layout/xul/base/src/nsListBoxBodyFrame.cpp @@ -1194,6 +1194,9 @@ nsListBoxBodyFrame::GetNextItemBox(nsIBox* aBox, PRInt32 aOffset, nsIFrame* existingFrame = nsnull; mPresContext->GetPresShell()->GetPrimaryFrameFor(nextContent, &existingFrame); + + if (existingFrame && existingFrame->GetParent() != this) + return GetNextItemBox(aBox, ++aOffset, aCreated); if (!existingFrame) { // Either append the new frame, or insert it after the current frame @@ -1450,14 +1453,14 @@ void nsListBoxBodyFrame::RemoveChildFrame(nsBoxLayoutState &aState, nsIFrame *aFrame) { + if (!mFrames.ContainsFrame(aFrame)) { + NS_ERROR("tried to remove a child frame which isn't our child"); + return; + } + mFrameConstructor->RemoveMappingsForFrameSubtree(aFrame, nsnull); -#ifdef DEBUG - PRBool removed = -#endif - mFrames.RemoveFrame(aFrame); - NS_ASSERTION(removed, - "Going to destroy a frame we didn't remove. Prepare to crash"); + mFrames.RemoveFrame(aFrame); if (mLayoutManager) mLayoutManager->ChildrenRemoved(this, aState, aFrame); aFrame->Destroy(mPresContext); diff --git a/layout/xul/base/src/tree/public/nsITreeSelection.idl b/layout/xul/base/src/tree/public/nsITreeSelection.idl index 32c58285..cc18c068 100644 --- a/layout/xul/base/src/tree/public/nsITreeSelection.idl +++ b/layout/xul/base/src/tree/public/nsITreeSelection.idl @@ -144,3 +144,14 @@ interface nsITreeSelection : nsISupports */ readonly attribute long shiftSelectPivot; }; + +/** + * The following interface is not scriptable and MUST NEVER BE MADE scriptable. + * Native treeselections implement it, and we use this to check whether a + * treeselection is native (and therefore suitable for use by untrusted content). + */ +[uuid(1bd59678-5cb3-4316-b246-31a91b19aabe)] +interface nsINativeTreeSelection : nsITreeSelection +{ + [noscript] void ensureNative(); +}; diff --git a/layout/xul/base/src/tree/src/nsTreeContentView.cpp b/layout/xul/base/src/tree/src/nsTreeContentView.cpp index 1932e40f..64e3d9ca 100644 --- a/layout/xul/base/src/tree/src/nsTreeContentView.cpp +++ b/layout/xul/base/src/tree/src/nsTreeContentView.cpp @@ -47,6 +47,8 @@ #include "nsIDOMClassInfo.h" #include "nsIEventStateManager.h" #include "nsINodeInfo.h" +#include "nsContentUtils.h" +#include "nsDOMError.h" // A content model view implementation for the tree. @@ -185,9 +187,22 @@ nsTreeContentView::GetSelection(nsITreeSelection** aSelection) return NS_OK; } +PRBool +nsTreeContentView::CanTrustTreeSelection(nsISupports* aValue) +{ + // Untrusted content is only allowed to specify known-good views + if (nsContentUtils::IsCallerTrustedForWrite()) + return PR_TRUE; + nsCOMPtr nativeTreeSel = do_QueryInterface(aValue); + return nativeTreeSel && NS_SUCCEEDED(nativeTreeSel->EnsureNative()); +} + NS_IMETHODIMP nsTreeContentView::SetSelection(nsITreeSelection* aSelection) { + NS_ENSURE_TRUE(!aSelection || CanTrustTreeSelection(aSelection), + NS_ERROR_DOM_SECURITY_ERR); + mSelection = aSelection; if (mUpdateSelection) { @@ -969,9 +984,14 @@ nsTreeContentView::ContentInserted(nsIDocument *aDocument, } else if (childTag == nsHTMLAtoms::option) { PRInt32 parentIndex = FindContent(aContainer); - PRInt32 count = InsertRow(parentIndex, aIndexInContainer, aChild); - if (mBoxObject) - mBoxObject->RowCountChanged(parentIndex + aIndexInContainer + 1, count); + + if (parentIndex >= 0) { + PRInt32 index = 0; + GetIndexInSubtree(aContainer, aChild, &index); + PRInt32 count = InsertRow(parentIndex, index, aChild); + if (mBoxObject) + mBoxObject->RowCountChanged(parentIndex + index + 1, count); + } } } diff --git a/layout/xul/base/src/tree/src/nsTreeContentView.h b/layout/xul/base/src/tree/src/nsTreeContentView.h index d9046f98..0b9d5e64 100644 --- a/layout/xul/base/src/tree/src/nsTreeContentView.h +++ b/layout/xul/base/src/tree/src/nsTreeContentView.h @@ -88,6 +88,8 @@ class nsTreeContentView : public nsINativeTreeView, nsIContent* aChild, PRInt32 aIndexInContainer); virtual void DocumentWillBeDestroyed(nsIDocument *aDocument); + static PRBool CanTrustTreeSelection(nsISupports* aValue); + protected: // Recursive methods which deal with serializing of nested content. void Serialize(nsIContent* aContent, PRInt32 aParentIndex, PRInt32* aIndex, nsVoidArray& aRows); diff --git a/layout/xul/base/src/tree/src/nsTreeSelection.cpp b/layout/xul/base/src/tree/src/nsTreeSelection.cpp index cf1cb232..3c6aeac1 100644 --- a/layout/xul/base/src/tree/src/nsTreeSelection.cpp +++ b/layout/xul/base/src/tree/src/nsTreeSelection.cpp @@ -54,6 +54,7 @@ #include "nsINameSpaceManager.h" #include "nsXULAtoms.h" #include "nsPLDOMEvent.h" +#include "nsTArray.h" // A helper class for managing our ranges of selection. struct nsTreeRange @@ -212,17 +213,39 @@ struct nsTreeRange return total; }; + static void CollectRanges(nsTreeRange* aRange, nsTArray& aRanges) + { + nsTreeRange* cur = aRange; + while (cur) { + aRanges.AppendElement(cur->mMin); + aRanges.AppendElement(cur->mMax); + cur = cur->mNext; + } + } + + static void InvalidateRanges(nsITreeBoxObject* aTree, + nsTArray& aRanges) + { + if (aTree) { + nsCOMPtr tree = aTree; + for (PRUint32 i = 0; i < aRanges.Length(); i += 2) { + aTree->InvalidateRange(aRanges[i], aRanges[i + 1]); + } + } + } + void Invalidate() { - mSelection->mTree->InvalidateRange(mMin, mMax); - if (mNext) - mNext->Invalidate(); + nsTArray ranges; + CollectRanges(this, ranges); + InvalidateRanges(mSelection->mTree, ranges); }; void RemoveAllBut(PRInt32 aIndex) { if (aIndex >= mMin && aIndex <= mMax) { // Invalidate everything in this list. - mSelection->mFirstRange->Invalidate(); + nsTArray ranges; + CollectRanges(mSelection->mFirstRange, ranges); mMin = aIndex; mMax = aIndex; @@ -238,6 +261,7 @@ struct nsTreeRange delete mSelection->mFirstRange; mSelection->mFirstRange = this; } + InvalidateRanges(mSelection->mTree, ranges); } else if (mNext) mNext->RemoveAllBut(aIndex); @@ -272,6 +296,7 @@ nsTreeSelection::~nsTreeSelection() // QueryInterface implementation for nsBoxObject NS_INTERFACE_MAP_BEGIN(nsTreeSelection) NS_INTERFACE_MAP_ENTRY(nsITreeSelection) + NS_INTERFACE_MAP_ENTRY(nsINativeTreeSelection) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(TreeSelection) NS_INTERFACE_MAP_END @@ -281,8 +306,7 @@ NS_IMPL_RELEASE(nsTreeSelection) NS_IMETHODIMP nsTreeSelection::GetTree(nsITreeBoxObject * *aTree) { - NS_IF_ADDREF(mTree); - *aTree = mTree; + NS_IF_ADDREF(*aTree = mTree); return NS_OK; } @@ -292,13 +316,20 @@ NS_IMETHODIMP nsTreeSelection::SetTree(nsITreeBoxObject * aTree) mSelectTimer->Cancel(); mSelectTimer = nsnull; } - mTree = aTree; // WEAK + + // Make sure aTree really implements nsITreeBoxObject! + mTree = do_QueryInterface(aTree); + NS_ENSURE_STATE(mTree || !aTree); return NS_OK; } NS_IMETHODIMP nsTreeSelection::GetSingle(PRBool* aSingle) { + if (!mTree) + return NS_ERROR_NULL_POINTER; + nsCOMPtr boxObject = do_QueryInterface(mTree); + NS_ENSURE_STATE(boxObject); nsCOMPtr element; boxObject->GetElement(getter_AddRefs(element)); nsCOMPtr content = do_QueryInterface(element); @@ -399,8 +430,8 @@ NS_IMETHODIMP nsTreeSelection::ToggleSelect(PRInt32 aIndex) else { if (!mFirstRange->Contains(aIndex)) { PRBool single; - GetSingle(&single); - if (!single) + rv = GetSingle(&single); + if (NS_SUCCEEDED(rv) && !single) rv = mFirstRange->Add(aIndex); } else @@ -418,7 +449,10 @@ NS_IMETHODIMP nsTreeSelection::ToggleSelect(PRInt32 aIndex) NS_IMETHODIMP nsTreeSelection::RangedSelect(PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aAugment) { PRBool single; - GetSingle(&single); + nsresult rv = GetSingle(&single); + if (NS_FAILED(rv)) + return rv; + if ((mFirstRange || (aStartIndex != aEndIndex)) && single) return NS_OK; @@ -427,6 +461,7 @@ NS_IMETHODIMP nsTreeSelection::RangedSelect(PRInt32 aStartIndex, PRInt32 aEndInd if (mFirstRange) { mFirstRange->Invalidate(); delete mFirstRange; + mFirstRange = nsnull; } } @@ -503,6 +538,10 @@ NS_IMETHODIMP nsTreeSelection::InvertSelection() NS_IMETHODIMP nsTreeSelection::SelectAll() { + if (!mTree) { + return NS_OK; + } + nsCOMPtr view; mTree->GetView(getter_AddRefs(view)); if (!view) @@ -511,7 +550,10 @@ NS_IMETHODIMP nsTreeSelection::SelectAll() PRInt32 rowCount; view->GetRowCount(&rowCount); PRBool single; - GetSingle(&single); + nsresult rv = GetSingle(&single); + if (NS_FAILED(rv)) + return rv; + if (rowCount == 0 || (rowCount > 1 && single)) return NS_OK; @@ -592,6 +634,9 @@ NS_IMETHODIMP nsTreeSelection::GetCurrentIndex(PRInt32 *aCurrentIndex) NS_IMETHODIMP nsTreeSelection::SetCurrentIndex(PRInt32 aIndex) { + if (!mTree) + return NS_ERROR_NULL_POINTER; + if (mCurrentIndex == aIndex) { return NS_OK; } @@ -633,7 +678,12 @@ NS_IMETHODIMP nsTreeSelection::SetCurrentIndex(PRInt32 aIndex) #define ADD_NEW_RANGE(macro_range, macro_selection, macro_start, macro_end) \ { \ - nsTreeRange* macro_new_range = new nsTreeRange(macro_selection, (macro_start), (macro_end)); \ + PRInt32 start = macro_start; \ + PRInt32 end = macro_end; \ + if (start > end) { \ + end = start; \ + } \ + nsTreeRange* macro_new_range = new nsTreeRange(macro_selection, start, end); \ if (macro_range) \ macro_range->Insert(macro_new_range); \ else \ @@ -671,27 +721,27 @@ nsTreeSelection::AdjustSelection(PRInt32 aIndex, PRInt32 aCount) // no selection, so nothing to do. if (!mFirstRange) return NS_OK; - nsTreeRange* newRange = nsnull; - PRBool selChanged = PR_FALSE; + nsTreeRange* oldFirstRange = mFirstRange; nsTreeRange* curr = mFirstRange; + mFirstRange = nsnull; while (curr) { if (aCount > 0) { // inserting if (aIndex > curr->mMax) { // adjustment happens after the range, so no change - ADD_NEW_RANGE(newRange, this, curr->mMin, curr->mMax); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax); } else if (aIndex <= curr->mMin) { // adjustment happens before the start of the range, so shift down - ADD_NEW_RANGE(newRange, this, curr->mMin + aCount, curr->mMax + aCount); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin + aCount, curr->mMax + aCount); selChanged = PR_TRUE; } else { // adjustment happen inside the range. // break apart the range and create two ranges - ADD_NEW_RANGE(newRange, this, curr->mMin, aIndex - 1); - ADD_NEW_RANGE(newRange, this, aIndex + aCount, curr->mMax + aCount); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, aIndex - 1); + ADD_NEW_RANGE(mFirstRange, this, aIndex + aCount, curr->mMax + aCount); selChanged = PR_TRUE; } } @@ -699,7 +749,7 @@ nsTreeSelection::AdjustSelection(PRInt32 aIndex, PRInt32 aCount) // deleting if (aIndex > curr->mMax) { // adjustment happens after the range, so no change - ADD_NEW_RANGE(newRange, this, curr->mMin, curr->mMax); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax); } else { // remember, aCount is negative @@ -708,31 +758,30 @@ nsTreeSelection::AdjustSelection(PRInt32 aIndex, PRInt32 aCount) if (aIndex <= curr->mMin) { if (lastIndexOfAdjustment < curr->mMin) { // adjustment happens before the start of the range, so shift up - ADD_NEW_RANGE(newRange, this, curr->mMin + aCount, curr->mMax + aCount); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin + aCount, curr->mMax + aCount); } else if (lastIndexOfAdjustment >= curr->mMax) { // adjustment contains the range. remove the range by not adding it to the newRange } else { // adjustment starts before the range, and ends in the middle of it, so trim the range - ADD_NEW_RANGE(newRange, this, aIndex, curr->mMax + aCount) + ADD_NEW_RANGE(mFirstRange, this, aIndex, curr->mMax + aCount) } } else if (lastIndexOfAdjustment >= curr->mMax) { // adjustment starts in the middle of the current range, and contains the end of the range, so trim the range - ADD_NEW_RANGE(newRange, this, curr->mMin, aIndex - 1) + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, aIndex - 1) } else { // range contains the adjustment, so shorten the range - ADD_NEW_RANGE(newRange, this, curr->mMin, curr->mMax + aCount) + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax + aCount) } } } curr = curr->mNext; } - delete mFirstRange; - mFirstRange = newRange; + delete oldFirstRange; // Fire the select event if (selChanged) @@ -760,7 +809,7 @@ nsTreeSelection::GetShiftSelectPivot(PRInt32* aIndex) nsresult nsTreeSelection::FireOnSelectHandler() { - if (mSuppressed) + if (mSuppressed || !mTree) return NS_OK; nsCOMPtr boxObject = do_QueryInterface(mTree); diff --git a/layout/xul/base/src/tree/src/nsTreeSelection.h b/layout/xul/base/src/tree/src/nsTreeSelection.h index 0130f9bd..fc62bff6 100644 --- a/layout/xul/base/src/tree/src/nsTreeSelection.h +++ b/layout/xul/base/src/tree/src/nsTreeSelection.h @@ -48,7 +48,7 @@ class nsITreeBoxObject; struct nsTreeRange; -class nsTreeSelection : public nsITreeSelection +class nsTreeSelection : public nsINativeTreeSelection { public: nsTreeSelection(nsITreeBoxObject* aTree); @@ -57,6 +57,9 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSITREESELECTION + // nsINativeTreeSelection: Untrusted code can use us + NS_IMETHOD EnsureNative() { return NS_OK; } + friend struct nsTreeRange; protected: @@ -65,7 +68,7 @@ protected: protected: // Members - nsITreeBoxObject* mTree; // [Weak]. The tree will hold on to us through the view and let go when it dies. + nsCOMPtr mTree; // The tree will hold on to us through the view and let go when it dies. PRBool mSuppressed; // Whether or not we should be firing onselect events. PRInt32 mCurrentIndex; // The item to draw the rect around. The last one clicked, etc. diff --git a/mailnews/addrbook/src/nsAddrDatabase.cpp b/mailnews/addrbook/src/nsAddrDatabase.cpp index 2e838159..4379493a 100644 --- a/mailnews/addrbook/src/nsAddrDatabase.cpp +++ b/mailnews/addrbook/src/nsAddrDatabase.cpp @@ -3153,19 +3153,19 @@ nsresult nsAddrDatabase::GetListFromDB(nsIAbDirectory *newList, nsIMdbRow* listR return err; } -class nsAddrDBEnumerator : public nsIEnumerator +class nsAddrDBEnumerator : public nsIEnumerator, public nsIAddrDBListener { public: NS_DECL_ISUPPORTS // nsIEnumerator methods: NS_DECL_NSIENUMERATOR - + NS_DECL_NSIADDRDBLISTENER // nsAddrDBEnumerator methods: nsAddrDBEnumerator(nsAddrDatabase* db); virtual ~nsAddrDBEnumerator(); - + void Clear(); protected: nsCOMPtr mDB; nsCOMPtr mResultList; @@ -3183,14 +3183,25 @@ nsAddrDBEnumerator::nsAddrDBEnumerator(nsAddrDatabase* db) { mDbTable = mDB->GetPabTable(); mCurrentRowIsList = PR_FALSE; + if (mDB) + mDB->AddListener(this); } nsAddrDBEnumerator::~nsAddrDBEnumerator() { - NS_IF_RELEASE(mRowCursor); + Clear(); } -NS_IMPL_ISUPPORTS1(nsAddrDBEnumerator, nsIEnumerator) +void nsAddrDBEnumerator::Clear() +{ + NS_IF_RELEASE(mRowCursor); + mCurrentRow = nsnull; + mDbTable = nsnull; + if (mDB) + mDB->RemoveListener(this); +} + +NS_IMPL_ISUPPORTS2(nsAddrDBEnumerator, nsIEnumerator, nsIAddrDBListener) NS_IMETHODIMP nsAddrDBEnumerator::First(void) { @@ -3277,6 +3288,30 @@ NS_IMETHODIMP nsAddrDBEnumerator::IsDone(void) return mDone ? NS_OK : NS_ERROR_FAILURE; } +NS_IMETHODIMP nsAddrDBEnumerator::OnCardAttribChange(PRUint32 abCode) +{ + return NS_OK; +} + +/* void onCardEntryChange (in unsigned long aAbCode, in nsIAbCard aCard, in nsIAbDirectory aParent); */ +NS_IMETHODIMP nsAddrDBEnumerator::OnCardEntryChange(PRUint32 aAbCode, nsIAbCard *aCard) +{ + return NS_OK; +} + +/* void onListEntryChange (in unsigned long abCode, in nsIAbDirectory list); */ +NS_IMETHODIMP nsAddrDBEnumerator::OnListEntryChange(PRUint32 abCode, nsIAbDirectory *list) +{ + return NS_OK; +} + +/* void onAnnouncerGoingAway (); */ +NS_IMETHODIMP nsAddrDBEnumerator::OnAnnouncerGoingAway() +{ + Clear(); + return NS_OK; +} + class nsListAddressEnumerator : public nsIEnumerator { public: diff --git a/mailnews/base/search/src/nsMsgFilter.cpp b/mailnews/base/search/src/nsMsgFilter.cpp index 9832f16b..d45be1d3 100644 --- a/mailnews/base/search/src/nsMsgFilter.cpp +++ b/mailnews/base/search/src/nsMsgFilter.cpp @@ -553,6 +553,7 @@ nsMsgFilter::MatchHdr(nsIMsgDBHdr *msgHdr, nsIMsgFolder *folder, PRUint32 headersSize, PRBool *pResult) { NS_ENSURE_ARG_POINTER(folder); + NS_ENSURE_ARG_POINTER(msgHdr); // use offlineMail because nsXPIDLCString folderCharset; folder->GetCharset(getter_Copies(folderCharset)); diff --git a/mailnews/base/src/nsMsgQuickSearchDBView.cpp b/mailnews/base/src/nsMsgQuickSearchDBView.cpp index 3913ba6c..f45abe52 100644 --- a/mailnews/base/src/nsMsgQuickSearchDBView.cpp +++ b/mailnews/base/src/nsMsgQuickSearchDBView.cpp @@ -427,6 +427,8 @@ nsresult nsMsgQuickSearchDBView::SortThreads(nsMsgViewSortTypeValue sortType, ns continue; // it would be nice if GetInsertIndexHelper always found the hdr, but it doesn't. threadHdr->GetChildHdrAt(0, getter_AddRefs(rootHdr)); + if (!rootHdr) + continue; threadRootIndex = GetInsertIndexHelper(rootHdr, &threadRootIds, nsMsgViewSortOrder::ascending, nsMsgViewSortType::byId); threadRootIds.InsertAt(threadRootIndex, rootKey); } diff --git a/mailnews/base/util/nsMsgDBFolder.cpp b/mailnews/base/util/nsMsgDBFolder.cpp index d5e2b6db..7f490987 100644 --- a/mailnews/base/util/nsMsgDBFolder.cpp +++ b/mailnews/base/util/nsMsgDBFolder.cpp @@ -1974,6 +1974,7 @@ nsMsgDBFolder::CallFilterPlugins(nsIMsgWindow *aMsgWindow, PRBool *aFiltersRun) { rv = GetDatabase(nsnull); // XXX is nsnull a reasonable arg here? NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(mDatabase, NS_ERROR_NOT_AVAILABLE); } // get the list of new messages @@ -2035,8 +2036,10 @@ nsMsgDBFolder::CallFilterPlugins(nsIMsgWindow *aMsgWindow, PRBool *aFiltersRun) nsXPIDLCString junkScore; nsCOMPtr msgHdr; nsMsgKey msgKey = newMessageKeys.GetAt(i); - rv = mDatabase->GetMsgHdrForKey(msgKey, getter_AddRefs(msgHdr)); - if (!NS_SUCCEEDED(rv)) + NS_ASSERTION(mDatabase, "null database"); + if (mDatabase) + rv = mDatabase->GetMsgHdrForKey(msgKey, getter_AddRefs(msgHdr)); + if (!mDatabase || !NS_SUCCEEDED(rv)) continue; nsXPIDLCString author; nsXPIDLCString authorEmailAddress; diff --git a/mailnews/base/util/nsMsgMailNewsUrl.cpp b/mailnews/base/util/nsMsgMailNewsUrl.cpp index e7e169fc..511f2e77 100644 --- a/mailnews/base/util/nsMsgMailNewsUrl.cpp +++ b/mailnews/base/util/nsMsgMailNewsUrl.cpp @@ -914,12 +914,13 @@ NS_IMETHODIMP nsMsgSaveAsListener::OnDataAvailable(nsIRequest* request, while (start && end) { - if (PL_strncasecmp(start, "X-Mozilla-Status:", 17) && + if (m_outputStream && + PL_strncasecmp(start, "X-Mozilla-Status:", 17) && PL_strncasecmp(start, "X-Mozilla-Status2:", 18) && PL_strncmp(start, "From - ", 7)) { rv = m_outputStream->Write(start, end-start, &writeCount); - rv = m_outputStream->Write(lineEnding, lineEndingLength, &writeCount); + rv |= m_outputStream->Write(lineEnding, lineEndingLength, &writeCount); } start = end+linebreak_len; if (start >= m_dataBuffer + m_leftOver) diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.cpp b/mailnews/compose/src/nsMsgAttachmentHandler.cpp index 23c01fb9..d7b1a814 100644 --- a/mailnews/compose/src/nsMsgAttachmentHandler.cpp +++ b/mailnews/compose/src/nsMsgAttachmentHandler.cpp @@ -1029,20 +1029,21 @@ nsMsgAttachmentHandler::LoadDataFromFile(nsFileSpec& fSpec, nsString &sigData, P nsresult nsMsgAttachmentHandler::Abort() { + nsCOMPtr saveRequest = mRequest; + mRequest = nsnull; NS_ASSERTION(m_mime_delivery_state != nsnull, "not-null m_mime_delivery_state"); if (m_done) return NS_OK; - if (mRequest) - return mRequest->Cancel(NS_ERROR_ABORT); + if (saveRequest) + return saveRequest->Cancel(NS_ERROR_ABORT); else if (m_mime_delivery_state) { m_mime_delivery_state->SetStatus(NS_ERROR_ABORT); m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, NS_ERROR_ABORT, 0, nsnull); } - return NS_OK; } diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.h b/mailnews/compose/src/nsMsgAttachmentHandler.h index 2b10eb1c..bcb675bc 100644 --- a/mailnews/compose/src/nsMsgAttachmentHandler.h +++ b/mailnews/compose/src/nsMsgAttachmentHandler.h @@ -102,7 +102,7 @@ public: nsCOMPtr mURL; nsFileSpec *mFileSpec; // The temp file to which we save it nsCOMPtr mOutFile; - nsIRequest *mRequest; // The live request used while fetching an attachment + nsCOMPtr mRequest; // The live request used while fetching an attachment nsMsgCompFields *mCompFields; // Message composition fields for the sender PRBool m_bogus_attachment; // This is to catch problem children... diff --git a/mailnews/imap/src/nsImapIncomingServer.cpp b/mailnews/imap/src/nsImapIncomingServer.cpp index ce7d204f..2023d597 100644 --- a/mailnews/imap/src/nsImapIncomingServer.cpp +++ b/mailnews/imap/src/nsImapIncomingServer.cpp @@ -1182,6 +1182,8 @@ NS_IMETHODIMP nsImapIncomingServer::PossibleImapMailbox(const char *folderPath, if (dupFolderPath.Last() == hierarchyDelimiter) { dupFolderPath.SetLength(dupFolderPath.Length()-1); + if (dupFolderPath.IsEmpty()) + return NS_ERROR_FAILURE; // *** this is what we did in 4.x in order to list uw folder only // mailbox in order to get the \NoSelect flag explicitlyVerify = !(boxFlags & kNameSpace); @@ -1305,7 +1307,8 @@ NS_IMETHODIMP nsImapIncomingServer::PossibleImapMailbox(const char *folderPath, } } - hostFolder->CreateClientSubfolderInfo(dupFolderPath.get(), hierarchyDelimiter,boxFlags, PR_FALSE); + rv = hostFolder->CreateClientSubfolderInfo(dupFolderPath.get(), hierarchyDelimiter,boxFlags, PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); caseInsensitive = (nsCRT::strcasecmp("INBOX", dupFolderPath.get())== 0); a_nsIFolder->GetChildWithURI(uri.get(), PR_TRUE, caseInsensitive , getter_AddRefs(child)); } diff --git a/mailnews/imap/src/nsImapMailFolder.cpp b/mailnews/imap/src/nsImapMailFolder.cpp index 347ffd52..c9a9d14c 100644 --- a/mailnews/imap/src/nsImapMailFolder.cpp +++ b/mailnews/imap/src/nsImapMailFolder.cpp @@ -7178,7 +7178,7 @@ nsImapFolderCopyState::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode) nsCOMPtr msgSupportsArray; NS_NewISupportsArray(getter_AddRefs(msgSupportsArray)); - PRBool hasMoreElements; + PRBool hasMoreElements = PR_FALSE; nsCOMPtr aSupport; if (messages) diff --git a/mailnews/imap/src/nsImapUtils.cpp b/mailnews/imap/src/nsImapUtils.cpp index de558516..56d8d663 100644 --- a/mailnews/imap/src/nsImapUtils.cpp +++ b/mailnews/imap/src/nsImapUtils.cpp @@ -389,7 +389,15 @@ void AllocateImapUidString(PRUint32 *msgUids, PRUint32 &msgCount, { PRBool foundIt; flagState->GetMessageFlagsFromUID(curSequenceEnd, &foundIt, &curFlagStateIndex); - NS_ASSERTION(foundIt, "flag state missing key"); + if (!foundIt) + { + NS_WARNING("flag state missing key"); + // The start of this sequence is missing from flag state, so move + // on to the next key. + curFlagStateIndex = -1; + curSequenceEnd = startSequence = nextKey; + continue; + } } curFlagStateIndex++; PRUint32 nextUidInFlagState; diff --git a/mailnews/mime/src/mimeenc.cpp b/mailnews/mime/src/mimeenc.cpp index 48c240d3..55d22a6a 100644 --- a/mailnews/mime/src/mimeenc.cpp +++ b/mailnews/mime/src/mimeenc.cpp @@ -1153,7 +1153,7 @@ mime_encode_qp_buffer (MimeEncoderData *data, const char *buffer, PRInt32 size) out = out_buffer; /* If it's CRLF, swallow two chars instead of one. */ - if (in[0] == nsCRT::CR && in[1] == nsCRT::LF) + if (in + 1 < end && in[0] == '\r' && in[1] == '\n') in++; out = out_buffer; diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 122a8cfe..d6a55254 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -49,6 +49,8 @@ #include "nsIFileURL.h" #include "nsIViewSourceChannel.h" #include "nsIJAR.h" +#include "nsChannelProperties.h" + static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID); @@ -190,6 +192,9 @@ nsJARInputThunk::IsNonBlocking(PRBool *nonBlocking) } //----------------------------------------------------------------------------- +// nsJARChannel +//----------------------------------------------------------------------------- + nsJARChannel::nsJARChannel() : mContentLength(-1) @@ -218,19 +223,24 @@ nsJARChannel::~nsJARChannel() NS_RELEASE(handler); // NULL parameter } -NS_IMPL_ISUPPORTS7(nsJARChannel, - nsIRequest, - nsIChannel, - nsIStreamListener, - nsIRequestObserver, - nsIDownloadObserver, - nsIJARChannel, - nsIJARChannel_MOZILLA_1_8_BRANCH) +NS_IMPL_ISUPPORTS_INHERITED7(nsJARChannel, + nsHashPropertyBag, + nsIRequest, + nsIChannel, + nsIStreamListener, + nsIRequestObserver, + nsIDownloadObserver, + nsIJARChannel, + nsIJARChannel_MOZILLA_1_8_BRANCH) nsresult nsJARChannel::Init(nsIURI *uri) { nsresult rv; + rv = nsHashPropertyBag::Init(); + if (NS_FAILED(rv)) + return rv; + mJarURI = do_QueryInterface(uri, &rv); if (NS_FAILED(rv)) return rv; @@ -736,6 +746,11 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader, mIsUnsafe = !(contentType.Equals(channelContentType) && (contentType.EqualsLiteral("application/java-archive") || contentType.EqualsLiteral("application/x-jar"))); + rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Disposition"), + header); + if (NS_SUCCEEDED(rv)) + SetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION, header); + } else { nsCOMPtr innerJARChannel(do_QueryInterface(channel)); if (innerJARChannel) { diff --git a/modules/libjar/nsJARChannel.h b/modules/libjar/nsJARChannel.h index 6f067d60..d8859c62 100644 --- a/modules/libjar/nsJARChannel.h +++ b/modules/libjar/nsJARChannel.h @@ -47,6 +47,7 @@ #include "nsIZipReader.h" #include "nsIDownloader.h" #include "nsILoadGroup.h" +#include "nsHashPropertyBag.h" #include "nsIFile.h" #include "nsIURI.h" #include "nsCOMPtr.h" @@ -61,6 +62,7 @@ class nsJARChannel : public nsIJARChannel , public nsIJARChannel_MOZILLA_1_8_BRANCH , public nsIDownloadObserver , public nsIStreamListener + , public nsHashPropertyBag { public: NS_DECL_ISUPPORTS diff --git a/modules/libjar/nsWildCard.cpp b/modules/libjar/nsWildCard.cpp index ca73d556..206871b9 100644 --- a/modules/libjar/nsWildCard.cpp +++ b/modules/libjar/nsWildCard.cpp @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -16,10 +15,13 @@ * * The Initial Developer of the Original Code is * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 + * Portions created by the Initial Developer are Copyright (C) 1998-2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Rob McCool (original author) + * Ken Key + * Nelson Bolyard * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,14 +38,13 @@ * ***** END LICENSE BLOCK ***** */ /* * - * * * shexp.c: shell-like wildcard match routines * * See shexp.h for public documentation. * * Rob McCool - * + * */ #include "nsWildCard.h" @@ -52,87 +53,87 @@ /* ----------------------------- shexp_valid ------------------------------ */ - -static int -_valid_subexp(char *expr, char stop) +static int +_valid_subexp(const char *expr, char stop1, char stop2) { - register int x,y,t; - int nsc,np,tld; + register int x; + int nsc = 0; /* Number of special characters */ + int np; /* Number of pipe characters in union */ + int tld = 0; /* Number of tilde characters */ - x=0;nsc=0;tld=0; - - while(expr[x] && (expr[x] != stop)) { + for (x = 0; expr[x] && (expr[x] != stop1) && (expr[x] != stop2); ++x) { switch(expr[x]) { - case '~': - if(tld) return INVALID_SXP; - else ++tld; - case '*': - case '?': - case '^': - case '$': + case '~': + if(tld) /* at most one exclusion */ + return INVALID_SXP; + if (stop1) /* no exclusions within unions */ + return INVALID_SXP; + if (!expr[x+1]) /* exclusion cannot be last character */ + return INVALID_SXP; + if (!x) /* exclusion cannot be first character */ + return INVALID_SXP; + ++tld; + /* fall through */ + case '*': + case '?': + case '$': ++nsc; break; - case '[': + case '[': ++nsc; if((!expr[++x]) || (expr[x] == ']')) return INVALID_SXP; - for(++x;expr[x] && (expr[x] != ']');++x) - if(expr[x] == '\\') - if(!expr[++x]) - return INVALID_SXP; + for(; expr[x] && (expr[x] != ']'); ++x) { + if(expr[x] == '\\' && !expr[++x]) + return INVALID_SXP; + } if(!expr[x]) return INVALID_SXP; break; - case '(': - ++nsc;np = 0; - while(1) { - if(expr[++x] == ')') - return INVALID_SXP; - for(y=x;(expr[y]) && (expr[y] != '|') && (expr[y] != ')');++y) - if(expr[y] == '\\') - if(!expr[++y]) - return INVALID_SXP; - if(!expr[y]) - return INVALID_SXP; - if(expr[y] == '|') - ++np; - t = _valid_subexp(&expr[x],expr[y]); - if(t == INVALID_SXP) + case '(': + ++nsc; + if (stop1) /* no nested unions */ + return INVALID_SXP; + np = -1; + do { + int t = _valid_subexp(&expr[++x], ')', '|'); + if(t == 0 || t == INVALID_SXP) return INVALID_SXP; x+=t; - if(expr[x] == ')') { - if(!np) - return INVALID_SXP; - break; - } - } + if(!expr[x]) + return INVALID_SXP; + ++np; + } while (expr[x] == '|' ); + if(np < 1) /* must be at least one pipe */ + return INVALID_SXP; break; - case ')': - case ']': + case ')': + case ']': + case '|': return INVALID_SXP; - case '\\': + case '\\': + ++nsc; if(!expr[++x]) return INVALID_SXP; - default: + break; + default: break; } - ++x; } - if((!stop) && (!nsc)) + if((!stop1) && (!nsc)) /* must be at least one special character */ return NON_SXP; - return ((expr[x] == stop) ? x : INVALID_SXP); + return ((expr[x] == stop1 || expr[x] == stop2) ? x : INVALID_SXP); } -int -NS_WildCardValid(char *expr) +int +NS_WildCardValid(const char *expr) { int x; - x = _valid_subexp(expr, '\0'); + x = _valid_subexp(expr, '\0', '\0'); return (x < 0 ? x : VALID_SXP); } - /* ----------------------------- shexp_match ----------------------------- */ @@ -140,152 +141,266 @@ NS_WildCardValid(char *expr) #define NOMATCH 1 #define ABORTED -1 -static int _shexp_match(char *str, char *expr, PRBool case_insensitive); +static int +_shexp_match(const char *str, const char *expr, PRBool case_insensitive, + unsigned int level); -static int -_handle_union(char *str, char *expr, PRBool case_insensitive) +/* Count characters until we reach a NUL character or either of the + * two delimiter characters, stop1 or stop2. If we encounter a bracketed + * expression, look only for NUL or ']' inside it. Do not look for stop1 + * or stop2 inside it. Return ABORTED if bracketed expression is unterminated. + * Handle all escaping. + * Return index in input string of first stop found, or ABORTED if not found. + * If "dest" is non-NULL, copy counted characters to it and NUL terminate. + */ +static int +_scan_and_copy(const char *expr, char stop1, char stop2, char *dest) { - char *e2 = (char *) PR_Malloc(sizeof(char)*strlen(expr)); - register int t,p2,p1 = 1; - int cp; + register int sx; /* source index */ + register char cc; - while(1) { - for(cp=1;expr[cp] != ')';cp++) - if(expr[cp] == '\\') - ++cp; - for(p2 = 0;(expr[p1] != '|') && (p1 != cp);p1++,p2++) { - if(expr[p1] == '\\') - e2[p2++] = expr[p1++]; - e2[p2] = expr[p1]; + for (sx = 0; (cc = expr[sx]) && cc != stop1 && cc != stop2; sx++) { + if (cc == '\\') { + if (!expr[++sx]) + return ABORTED; /* should be impossible */ } - for (t=cp+1; ((e2[p2] = expr[t]) != 0); ++t,++p2) {} - if(_shexp_match(str,e2, case_insensitive) == MATCH) { - PR_Free(e2); - return MATCH; + else if (cc == '[') { + while ((cc = expr[++sx]) && cc != ']') { + if(cc == '\\' && !expr[++sx]) + return ABORTED; + } + if (!cc) + return ABORTED; /* should be impossible */ } - if(p1 == cp) { - PR_Free(e2); - return NOMATCH; - } - else ++p1; } + if (dest && sx) { + /* Copy all but the closing delimiter. */ + memcpy(dest, expr, sx); + dest[sx] = 0; + } + return cc ? sx : ABORTED; /* index of closing delimiter */ } - -static int -_shexp_match(char *str, char *expr, PRBool case_insensitive) +/* On input, expr[0] is the opening parenthesis of a union. + * See if any of the alternatives in the union matches as a pattern. + * The strategy is to take each of the alternatives, in turn, and append + * the rest of the expression (after the closing ')' that marks the end of + * this union) to that alternative, and then see if the resultant expression + * matches the input string. Repeat this until some alternative matches, + * or we have an abort. + */ +static int +_handle_union(const char *str, const char *expr, PRBool case_insensitive, + unsigned int level) { - register int x,y; + register int sx; /* source index */ + int cp; /* source index of closing parenthesis */ + int count; + int ret = NOMATCH; + char *e2; + + /* Find the closing parenthesis that ends this union in the expression */ + cp = _scan_and_copy(expr, ')', '\0', NULL); + if (cp == ABORTED || cp < 4) /* must be at least "(a|b" before ')' */ + return ABORTED; + ++cp; /* now index of char after closing parenthesis */ + e2 = (char *) PR_Malloc(1 + strlen(expr)); + if (!e2) + return ABORTED; + for (sx = 1; ; ++sx) { + /* Here, expr[sx] is one character past the preceeding '(' or '|'. */ + /* Copy everything up to the next delimiter to e2 */ + count = _scan_and_copy(expr + sx, ')', '|', e2); + if (count == ABORTED || !count) { + ret = ABORTED; + break; + } + sx += count; + /* Append everything after closing parenthesis to e2. This is safe. */ + strcpy(e2+count, expr+cp); + ret = _shexp_match(str, e2, case_insensitive, level + 1); + if (ret != NOMATCH || !expr[sx] || expr[sx] == ')') + break; + } + PR_Free(e2); + if (sx < 2) + ret = ABORTED; + return ret; +} + +/* returns 1 if val is in range from start..end, case insensitive. */ +static int +_is_char_in_range(int start, int end, int val) +{ + char map[256]; + memset(map, 0, sizeof map); + while (start <= end) + map[tolower(start++)] = 1; + return map[tolower(val)]; +} + +static int +_shexp_match(const char *str, const char *expr, PRBool case_insensitive, + unsigned int level) +{ + register int x; /* input string index */ + register int y; /* expression index */ int ret,neg; - ret = 0; - for(x=0,y=0;expr[y];++y,++x) { - if((!str[x]) && (expr[y] != '(') && (expr[y] != '$') && (expr[y] != '*')) - ret = ABORTED; - else { - switch(expr[y]) { - case '$': - if( (str[x]) ) - ret = NOMATCH; - else - --x; /* we don't want loop to increment x */ - break; - case '*': - while(expr[++y] == '*'){} - if(!expr[y]) + if (level > 20) /* Don't let the stack get too deep. */ + return ABORTED; + for(x = 0, y = 0; expr[y]; ++y, ++x) { + if((!str[x]) && (expr[y] != '$') && (expr[y] != '*')) { + return NOMATCH; + } + switch(expr[y]) { + case '$': + if(str[x]) + return NOMATCH; + --x; /* we don't want loop to increment x */ + break; + case '*': + while(expr[++y] == '*'){} + if(!expr[y]) + return MATCH; + while(str[x]) { + ret = _shexp_match(&str[x++], &expr[y], case_insensitive, + level + 1); + switch(ret) { + case NOMATCH: + continue; + case ABORTED: + return ABORTED; + default: return MATCH; - while(str[x]) { - switch(_shexp_match(&str[x++],&expr[y], case_insensitive)) { - case NOMATCH: - continue; - case ABORTED: - ret = ABORTED; - break; - default: - return MATCH; - } - break; } - if((expr[y] == '$') && (expr[y+1] == '\0') && (!str[x])) - return MATCH; - else - ret = ABORTED; - break; - case '[': - neg = ((expr[++y] == '^') && (expr[y+1] != ']')); - if (neg) - ++y; - - if ((isalnum(expr[y])) && (expr[y+1] == '-') && - (isalnum(expr[y+2])) && (expr[y+3] == ']')) - { - int start = expr[y], end = expr[y+2]; - - /* Droolproofing for pinheads not included */ - if(neg ^ ((str[x] < start) || (str[x] > end))) { - ret = NOMATCH; - break; - } - y+=3; - } - else { - int matched; - - for (matched=0;expr[y] != ']';y++) - matched |= (str[x] == expr[y]); - if (neg ^ (!matched)) - ret = NOMATCH; - } - break; - case '(': - return _handle_union(&str[x],&expr[y], case_insensitive); - break; - case '?': - break; - case '\\': + } + if((expr[y] == '$') && (expr[y+1] == '\0') && (!str[x])) + return MATCH; + else + return NOMATCH; + case '[': { + int start, end = 0, i; + neg = ((expr[++y] == '^') && (expr[y+1] != ']')); + if (neg) ++y; - default: - if(case_insensitive) - { - if(toupper(str[x]) != toupper(expr[y])) - ret = NOMATCH; - } - else - { - if(str[x] != expr[y]) - ret = NOMATCH; - } - break; + i = y; + start = (unsigned char)(expr[i++]); + if (start == '\\') + start = (unsigned char)(expr[i++]); + if (isalnum(start) && expr[i++] == '-') { + end = (unsigned char)(expr[i++]); + if (end == '\\') + end = (unsigned char)(expr[i++]); + } + if (isalnum(end) && expr[i] == ']') { + /* This is a range form: a-b */ + int val = (unsigned char)(str[x]); + if (end < start) { /* swap them */ + start ^= end; + end ^= start; + start ^= end; + } + if (case_insensitive && isalpha(val)) { + val = _is_char_in_range(start, end, val); + if (neg == val) + return NOMATCH; + } + else if (neg != ((val < start) || (val > end))) { + return NOMATCH; + } + y = i; + } + else { + /* Not range form */ + int matched = 0; + for (; expr[y] != ']'; y++) { + if (expr[y] == '\\') + ++y; + if(case_insensitive) { + matched |= (toupper(str[x]) == toupper(expr[y])); + } + else { + matched |= (str[x] == expr[y]); + } + } + if (neg == matched) + return NOMATCH; } } - if(ret) + break; + case '(': + if (!expr[y+1]) + return ABORTED; + return _handle_union(&str[x], &expr[y], case_insensitive, level); + case '?': break; - } - return (ret ? ret : (str[x] ? NOMATCH : MATCH)); -} - -int -NS_WildCardMatch(char *str, char *xp, PRBool case_insensitive) { - register int x; - char *expr = PL_strdup(xp); - - if(!expr) - return 1; - - for(x=strlen(expr)-1;x;--x) { - if((expr[x] == '~') && (expr[x-1] != '\\')) { - expr[x] = '\0'; - if(_shexp_match(str,&expr[++x], case_insensitive) == MATCH) - goto punt; + case ')': + case ']': + case '|': + return ABORTED; + case '\\': + ++y; + /* fall through */ + default: + if(case_insensitive) { + if(toupper(str[x]) != toupper(expr[y])) + return NOMATCH; + } + else { + if(str[x] != expr[y]) + return NOMATCH; + } break; } } - if(_shexp_match(str,expr, case_insensitive) == MATCH) { - PR_Free(expr); - return 0; - } - - punt: - PR_Free(expr); - return 1; + return (str[x] ? NOMATCH : MATCH); } + +static int +ns_WildCardMatch(const char *str, const char *xp, PRBool case_insensitive) +{ + char *expr = 0; + int x, ret = MATCH; + + if (!strchr(xp, '~')) + return _shexp_match(str, xp, case_insensitive, 0); + + expr = PL_strdup(xp); + if(!expr) + return NOMATCH; + + x = _scan_and_copy(expr, '~', '\0', NULL); + if (x != ABORTED && expr[x] == '~') { + expr[x++] = '\0'; + ret = _shexp_match(str, &expr[x], case_insensitive, 0); + switch (ret) { + case NOMATCH: ret = MATCH; break; + case MATCH: ret = NOMATCH; break; + default: break; + } + } + if (ret == MATCH) + ret = _shexp_match(str, expr, case_insensitive, 0); + + PR_Free(expr); + return ret; +} + + +int +NS_WildCardMatch(const char *str, const char *expr, PRBool case_insensitive) +{ + int is_valid = NS_WildCardValid(expr); + switch(is_valid) { + case INVALID_SXP: + return -1; + case NON_SXP: + if (case_insensitive) + return (PL_strcasecmp(expr,str) ? NOMATCH : MATCH); + return (strcmp(expr,str) ? NOMATCH : MATCH); + default: + return ns_WildCardMatch(str, expr, case_insensitive); + } +} + diff --git a/modules/libjar/nsWildCard.h b/modules/libjar/nsWildCard.h index 9cefdd8c..ddbbcd75 100644 --- a/modules/libjar/nsWildCard.h +++ b/modules/libjar/nsWildCard.h @@ -16,10 +16,11 @@ * * The Initial Developer of the Original Code is * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 + * Portions created by the Initial Developer are Copyright (C) 1998-2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Nelson Bolyard * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -83,7 +84,7 @@ #define INVALID_SXP -2 #define VALID_SXP 1 -extern int NS_WildCardValid(char *expr); +extern int NS_WildCardValid(const char *expr); /* return values for the search routines */ @@ -99,7 +100,8 @@ extern int NS_WildCardValid(char *expr); * Returns 0 on match and 1 on non-match. */ -extern int NS_WildCardMatch(char *str, char *expr, PRBool case_insensitive); +extern int +NS_WildCardMatch(const char *str, const char *expr, PRBool case_insensitive); /* * Same as above, but validates the exp first. 0 on match, 1 on non-match, diff --git a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp index 22947c1c..77ff496c 100644 --- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp +++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp @@ -406,6 +406,11 @@ row_callback(png_structp png_ptr, png_bytep new_row, */ nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr)); + PRInt32 height; + decoder->mFrame->GetHeight(&height); + if (row_num >= height) + return; + PRUint32 bpr, abpr; decoder->mFrame->GetImageBytesPerRow(&bpr); decoder->mFrame->GetAlphaBytesPerRow(&abpr); diff --git a/modules/libpr0n/src/imgRequest.cpp b/modules/libpr0n/src/imgRequest.cpp index d0c95c8e..85429730 100644 --- a/modules/libpr0n/src/imgRequest.cpp +++ b/modules/libpr0n/src/imgRequest.cpp @@ -146,8 +146,11 @@ nsresult imgRequest::AddProxy(imgRequestProxy *proxy, PRBool aNotify) nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, PRBool aNotify) { LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::RemoveProxy", "proxy", proxy); - - mObservers.RemoveElement(NS_STATIC_CAST(void*, proxy)); + + if (!mObservers.RemoveElement(NS_STATIC_CAST(void*, proxy))) { + // Not one of our proxies; we're done + return NS_OK; + } /* Check mState below before we potentially call Cancel() below. Since Cancel() may result in OnStopRequest being called back before Cancel() diff --git a/modules/libpr0n/src/imgRequestProxy.cpp b/modules/libpr0n/src/imgRequestProxy.cpp index 32a4e144..34790945 100644 --- a/modules/libpr0n/src/imgRequestProxy.cpp +++ b/modules/libpr0n/src/imgRequestProxy.cpp @@ -218,7 +218,16 @@ NS_IMETHODIMP imgRequestProxy::GetStatus(nsresult *aStatus) /* void cancel (in nsresult status); */ NS_IMETHODIMP imgRequestProxy::Cancel(nsresult status) { - if (mCanceled || !mOwner) + if (!mOwner) + return NS_ERROR_FAILURE; + + // If mCanceled is true but mListener is non-null, that means + // someone called Cancel() on us but the imgCancelRunnable is still + // pending. We still need to null out mListener before returning + // from this function in this case. That means we want to do the + // RemoveProxy call right now, because we need to deliver the + // onStopRequest. + if (mCanceled && !mListener) return NS_ERROR_FAILURE; LOG_SCOPE(gImgLog, "imgRequestProxy::Cancel"); diff --git a/modules/oji/src/ProxyJNI.cpp b/modules/oji/src/ProxyJNI.cpp index 49a75e35..3da564aa 100644 --- a/modules/oji/src/ProxyJNI.cpp +++ b/modules/oji/src/ProxyJNI.cpp @@ -47,6 +47,7 @@ #include "nsVoidArray.h" #include "plstr.h" #include "ProxyClassLoader.h" +#include "nsCSecurityContext.h" #include "ProxyJNI.h" #include "nsDataHashtable.h" @@ -282,6 +283,7 @@ private: nsISecureEnv* mSecureEnv; nsISecurityContext* mContext; jbool mInProxyFindClass; + nsXPIDLCString mFakeOrigin; static ProxyJNIEnv& GetProxyEnv(JNIEnv* env) { return *(ProxyJNIEnv*)env; } @@ -294,6 +296,27 @@ private: } } + // Don't generate a new fake origin on every call to + // nsCSecurityContext::GetOrigin(). + nsresult getOrSetFakeOrigin(nsCSecurityContext *securityContext) + { + if (!securityContext) + return NS_OK; + if (!mFakeOrigin.IsVoid()) + securityContext->SetFakeOrigin(mFakeOrigin); + char origin[256]; + nsresult rv = securityContext->GetOrigin(origin, 256); + if (NS_FAILED(rv)) + return rv; + if (mFakeOrigin.IsVoid()) { + const nsCString& contextFakeOrigin = + securityContext->GetFakeOrigin(); + if (!contextFakeOrigin.IsVoid()) + mFakeOrigin.Assign(contextFakeOrigin); + } + return NS_OK; + } + static jint JNICALL GetVersion(JNIEnv* env) { jint version = 0; @@ -500,10 +523,10 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->NewObject(clazz, method->mMethodID, jargs, &outObject, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->NewObject(clazz, method->mMethodID, jargs, &outObject, securityContext); NS_IF_RELEASE(securityContext); - return outObject; } @@ -514,8 +537,9 @@ private: nsISecureEnv* secureEnv = GetSecureEnv(env); JNIMethod* method = (JNIMethod*)methodID; nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->NewObject(clazz, method->mMethodID, args, &outObject, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->NewObject(clazz, method->mMethodID, args, &outObject, securityContext); NS_IF_RELEASE(securityContext); return outObject; } @@ -569,7 +593,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->CallMethod(method->mReturnType, obj, method->mMethodID, args, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->CallMethod(method->mReturnType, obj, method->mMethodID, args, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -587,8 +613,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->CallMethod(jvoid_type, obj, method->mMethodID, args, &unusedValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->CallMethod(jvoid_type, obj, method->mMethodID, args, &unusedValue, securityContext); NS_IF_RELEASE(securityContext); } @@ -676,7 +703,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->CallNonvirtualMethod(method->mReturnType, obj, clazz, method->mMethodID, args, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->CallNonvirtualMethod(method->mReturnType, obj, clazz, method->mMethodID, args, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -694,8 +723,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->CallNonvirtualMethod(jvoid_type, obj, clazz, method->mMethodID, args, &unusedValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->CallNonvirtualMethod(jvoid_type, obj, clazz, method->mMethodID, args, &unusedValue, securityContext); NS_IF_RELEASE(securityContext); } @@ -781,7 +811,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->GetField(field->mFieldType, obj, field->mFieldID, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->GetField(field->mFieldType, obj, field->mFieldID, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -809,8 +841,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->SetField(field->mFieldType, obj, field->mFieldID, value, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->SetField(field->mFieldType, obj, field->mFieldID, value, securityContext); NS_IF_RELEASE(securityContext); } @@ -865,7 +898,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->CallStaticMethod(method->mReturnType, clazz, method->mMethodID, args, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->CallStaticMethod(method->mReturnType, clazz, method->mMethodID, args, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -883,8 +918,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->CallStaticMethod(jvoid_type, clazz, method->mMethodID, args, &unusedValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->CallStaticMethod(jvoid_type, clazz, method->mMethodID, args, &unusedValue, securityContext); NS_IF_RELEASE(securityContext); } @@ -970,7 +1006,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->GetStaticField(field->mFieldType, clazz, field->mFieldID, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->GetStaticField(field->mFieldType, clazz, field->mFieldID, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -998,8 +1036,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->SetStaticField(field->mFieldType, clazz, field->mFieldID, value, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->SetStaticField(field->mFieldType, clazz, field->mFieldID, value, securityContext); NS_IF_RELEASE(securityContext); } @@ -1735,9 +1774,8 @@ ProxyJNIEnv::ProxyJNIEnv(nsIJVMPlugin* jvmPlugin, nsISecureEnv* secureEnv) ProxyJNIEnv::~ProxyJNIEnv() { this->functions = NULL; - - if (mSecureEnv != NULL) - mSecureEnv->Release(); + + NS_IF_RELEASE(mSecureEnv); } JNIEnv* CreateProxyJNI(nsIJVMPlugin* jvmPlugin, nsISecureEnv* inSecureEnv) diff --git a/modules/oji/src/nsCSecurityContext.cpp b/modules/oji/src/nsCSecurityContext.cpp index 3856f1f9..2827335c 100644 --- a/modules/oji/src/nsCSecurityContext.cpp +++ b/modules/oji/src/nsCSecurityContext.cpp @@ -57,6 +57,7 @@ #include "nsIScriptSecurityManager.h" #include "nsIServiceManager.h" #include "nsCRT.h" +#include "nsNetUtil.h" #include "nsTraceRefcnt.h" @@ -103,38 +104,70 @@ nsCSecurityContext::Implies(const char* target, const char* action, PRBool *bAll return NS_OK; } - -NS_METHOD -nsCSecurityContext::GetOrigin(char* buf, int buflen) +nsresult +nsCSecurityContext::GetOriginImpl(nsXPIDLCString& origin) { + nsresult rv = NS_OK; + if (!m_pPrincipal) { // Get the Script Security Manager. - nsresult rv = NS_OK; nsCOMPtr secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv) || !secMan) { + if (NS_FAILED(rv) || !secMan) return NS_ERROR_FAILURE; - } secMan->GetSubjectPrincipal(getter_AddRefs(m_pPrincipal)); - if (!m_pPrincipal) { + if (!m_pPrincipal) return NS_ERROR_FAILURE; - } } - nsXPIDLCString origin; m_pPrincipal->GetOrigin(getter_Copies(origin)); + if (origin.IsEmpty()) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// This method is called from the OJI plugin without checking its return +// value (from getAndPackSecurityInfo() in remotejni.cpp). So we need to +// set the origin appropriately except in the very worst of circumstances, +// and only then do an error return. +NS_METHOD +nsCSecurityContext::GetOrigin(char* buf, int buflen) +{ + nsXPIDLCString origin; + PRBool javaCompatible = PR_FALSE; + + if (NS_SUCCEEDED(GetOriginImpl(origin))) { + if (NS_FAILED(NS_CheckIsJavaCompatibleURLString(origin, &javaCompatible))) + javaCompatible = PR_FALSE; + } else { + javaCompatible = PR_FALSE; + } PRInt32 originlen = origin.Length(); - if (origin.IsEmpty() || originlen > buflen - 1) { - return NS_ERROR_FAILURE; + + // Don't pass back a value that Java won't be able to understand or + // won't handle correctly. Instead pass back something that Java will + // understand but won't be able to use to access the network, and for + // which same-origin checks will always fail. + if (!javaCompatible) { + if (mFakeOrigin.IsVoid()) { + if (NS_FAILED(NS_MakeRandomInvalidURLString(mFakeOrigin))) + return NS_ERROR_FAILURE; + } + origin.Assign(mFakeOrigin); + originlen = origin.Length(); } + if (originlen > buflen - 1) + return NS_ERROR_FAILURE; + // Copy the string into to user supplied buffer. Is there a better // way to do this? memcpy(buf, origin, originlen); - buf[originlen] = nsnull; // Gotta terminate it. + buf[originlen] = '\0'; // Gotta terminate it. return NS_OK; } diff --git a/modules/oji/src/nsCSecurityContext.h b/modules/oji/src/nsCSecurityContext.h index 99c13b58..abb0312d 100644 --- a/modules/oji/src/nsCSecurityContext.h +++ b/modules/oji/src/nsCSecurityContext.h @@ -50,6 +50,7 @@ #include "nsISecurityContext.h" #include "nsIPrincipal.h" #include "nsCOMPtr.h" +#include "nsString.h" struct JSContext; @@ -105,13 +106,22 @@ public: nsCSecurityContext(nsIPrincipal* principal); virtual ~nsCSecurityContext(void); + //////////////////////////////////////////////////////////////////////////// + // Miscellaneous + + const nsCString& GetFakeOrigin() const { return mFakeOrigin; } + void SetFakeOrigin(nsCString& fakeOrigin) { mFakeOrigin.Assign(fakeOrigin); } + protected: JSStackFrame *m_pJStoJavaFrame; JSContext *m_pJSCX; private: + nsresult GetOriginImpl(nsXPIDLCString& origin); + nsCOMPtr m_pPrincipal; PRBool m_HasUniversalJavaCapability; PRBool m_HasUniversalBrowserReadCapability; + nsXPIDLCString mFakeOrigin; }; #endif // nsCSecurityContext_h___ diff --git a/modules/plugin/base/src/ns4xPlugin.cpp b/modules/plugin/base/src/ns4xPlugin.cpp index 9d427da1..a70630ec 100644 --- a/modules/plugin/base/src/ns4xPlugin.cpp +++ b/modules/plugin/base/src/ns4xPlugin.cpp @@ -66,6 +66,10 @@ #include "jscntxt.h" #include "nsIXPConnect.h" +#include "nsXPIDLString.h" +#include "nsString.h" + +#include "nsNetUtil.h" #if defined(XP_MACOSX) #include @@ -1837,8 +1841,88 @@ _getproperty(NPP npp, NPObject* npobj, NPIdentifier property, NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_GetProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, property)); + + if (!npobj->_class->getProperty(npobj, property, result)) + return false; - return npobj->_class->getProperty(npobj, property, result); + // If a Java plugin tries to get the document.URL or document.documentURI + // property from us, don't pass back a value that Java won't be able to + // understand -- one that will make the URL(String) constructor throw a + // MalformedURL exception. Passing such a value causes Java Plugin2 to + // crash (to throw a RuntimeException in Plugin2Manager.getDocumentBase()). + // Also don't pass back a value that Java is likely to mishandle. + + ns4xPluginInstance* inst = (ns4xPluginInstance*) npp->ndata; + if (!inst) + return false; + if (!inst->mIsJavaPlugin) + return true; + + if (!NPVARIANT_IS_STRING(*result)) + return true; + + NPUTF8* propertyName = _utf8fromidentifier(property); + if (!propertyName) + return true; + bool notURL = + (PL_strcasecmp(propertyName, "URL") && + PL_strcasecmp(propertyName, "documentURI")); + _memfree(propertyName); + if (notURL) + return true; + + NPObject* window_obj = _getwindowobject(npp); + if (!window_obj) + return true; + + NPVariant doc_v; + NPObject* document_obj = nsnull; + NPIdentifier doc_id = _getstringidentifier("document"); + bool ok = npobj->_class->getProperty(window_obj, doc_id, &doc_v); + _releaseobject(window_obj); + if (ok) { + if (NPVARIANT_IS_OBJECT(doc_v)) { + document_obj = NPVARIANT_TO_OBJECT(doc_v); + } else { + _releasevariantvalue(&doc_v); + return true; + } + } else { + return true; + } + _releaseobject(document_obj); + if (document_obj != npobj) + return true; + + NPString urlnp = NPVARIANT_TO_STRING(*result); + nsXPIDLCString url; + url.Assign(urlnp.utf8characters, urlnp.utf8length); + + PRBool javaCompatible = PR_FALSE; + if (NS_FAILED(NS_CheckIsJavaCompatibleURLString(url, &javaCompatible))) + javaCompatible = PR_FALSE; + if (javaCompatible) + return true; + + // If Java won't be able to interpret the original value of document.URL or + // document.documentURI, or is likely to mishandle it, pass back something + // that Java will understand but won't be able to use to access the network, + // and for which same-origin checks will always fail. + + if (inst->mFakeURL.IsVoid()) { + // Abort (do an error return) if NS_MakeRandomInvalidURLString() fails. + if (NS_FAILED(NS_MakeRandomInvalidURLString(inst->mFakeURL))) { + _releasevariantvalue(result); + return false; + } + } + + _releasevariantvalue(result); + char* fakeurl = (char *) _memalloc(inst->mFakeURL.Length() + 1); + strcpy(fakeurl, inst->mFakeURL); + STRINGZ_TO_NPVARIANT(fakeurl, *result); + + return true; } bool NP_EXPORT diff --git a/modules/plugin/base/src/ns4xPluginInstance.cpp b/modules/plugin/base/src/ns4xPluginInstance.cpp index e60e1afb..fdad51f2 100644 --- a/modules/plugin/base/src/ns4xPluginInstance.cpp +++ b/modules/plugin/base/src/ns4xPluginInstance.cpp @@ -835,6 +835,7 @@ ns4xPluginInstance::ns4xPluginInstance(NPPluginFuncs* callbacks, mStarted = PR_FALSE; mStreams = nsnull; mCached = PR_FALSE; + mIsJavaPlugin = PR_FALSE; PLUGIN_LOG(PLUGIN_LOG_BASIC, ("ns4xPluginInstance ctor: this=%p\n",this)); } @@ -1027,6 +1028,17 @@ ns4xPluginInstance::GetDOMWindow() return window; } +PRBool IsJavaMIMEType(const char* aType) +{ + return aType && + ((0 == PL_strncasecmp(aType, "application/x-java-vm", + sizeof("application/x-java-vm") - 1)) || + (0 == PL_strncasecmp(aType, "application/x-java-applet", + sizeof("application/x-java-applet") - 1)) || + (0 == PL_strncasecmp(aType, "application/x-java-bean", + sizeof("application/x-java-bean") - 1))); +} + //////////////////////////////////////////////////////////////////////// nsresult ns4xPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer) { @@ -1184,6 +1196,8 @@ nsresult ns4xPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer) } } + mIsJavaPlugin = IsJavaMIMEType(mimetype); + // Assign mPeer now and mark this instance as started before calling NPP_New // because the plugin may call other NPAPI functions, like NPN_GetURLNotify, // that assume these are set before returning. If the plugin returns failure, diff --git a/modules/plugin/base/src/ns4xPluginInstance.h b/modules/plugin/base/src/ns4xPluginInstance.h index 57fedf75..843ef527 100644 --- a/modules/plugin/base/src/ns4xPluginInstance.h +++ b/modules/plugin/base/src/ns4xPluginInstance.h @@ -56,6 +56,8 @@ #include "nsIPluginTagInfo2.h" #include "nsIScriptablePlugin.h" #include "nsIPluginInstanceInternal.h" +#include "nsXPIDLString.h" +#include "nsString.h" #include "npupp.h" #ifdef OJI @@ -230,10 +232,14 @@ protected: PRPackedBool mCached; public: + PRPackedBool mIsJavaPlugin; + PRLibrary* fLibrary; nsInstanceStream *mStreams; nsVoidArray mPopupStates; + + nsXPIDLCString mFakeURL; }; #endif // ns4xPluginInstance_h__ diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp index 28a154ea..a35749f0 100644 --- a/modules/plugin/base/src/nsJSNPRuntime.cpp +++ b/modules/plugin/base/src/nsJSNPRuntime.cpp @@ -815,7 +815,8 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JSObject *obj) NPObject *npobj = (NPObject *)::JS_GetPrivate(cx, obj); - return _retainobject(npobj); + if (LookupNPP(npobj) == npp) + return _retainobject(npobj); } if (!sJSObjWrappers.ops) { @@ -1536,14 +1537,10 @@ static NPP LookupNPP(NPObject *npobj) { if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) { - NS_ERROR("NPP requested for NPObject of class " - "nsJSObjWrapper::sJSObjWrapperNPClass!\n"); - - return nsnull; + nsJSObjWrapper* o = static_cast(npobj); + return o->mNpp; } - - NPObjWrapperHashEntry *entry = NS_STATIC_CAST(NPObjWrapperHashEntry *, PL_DHashTableOperate(&sNPObjWrappers, npobj, @@ -1750,6 +1747,11 @@ NPObjectMember_Mark(JSContext *cx, JSObject *obj, void *arg) "NPObject Member => fieldValue", arg); } + if (!JSVAL_IS_PRIMITIVE(memberPrivate->methodName)) { + ::JS_MarkGCThing(cx, JSVAL_TO_OBJECT(memberPrivate->methodName), + "NPObject Member => methodName", arg); + } + // There's no strong reference from our private data to the // NPObject, so make sure to mark the NPObject wrapper to keep the // NPObject alive as long as this NPObjectMember is alive. diff --git a/netwerk/base/public/nsChannelProperties.h b/netwerk/base/public/nsChannelProperties.h index 48d344d0..1b62ccea 100644 --- a/netwerk/base/public/nsChannelProperties.h +++ b/netwerk/base/public/nsChannelProperties.h @@ -58,11 +58,21 @@ */ #define NS_CHANNEL_PROP_CONTENT_LENGTH_STR "content-length" +/** + * MIME Content-Disposition header of channel. + * Not available before onStartRequest. + * Type: nsACString + */ +#define NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR "content-disposition" + #ifdef IMPL_NS_NET #define NS_CHANNEL_PROP_CONTENT_LENGTH gNetStrings->kContentLength +#define NS_CHANNEL_PROP_CONTENT_DISPOSITION gNetStrings->kContentDisposition #else #define NS_CHANNEL_PROP_CONTENT_LENGTH \ NS_LITERAL_STRING(NS_CHANNEL_PROP_CONTENT_LENGTH_STR) +#define NS_CHANNEL_PROP_CONTENT_DISPOSITION \ + NS_LITERAL_STRING(NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR) #endif #endif diff --git a/netwerk/base/public/nsNetStrings.h b/netwerk/base/public/nsNetStrings.h index 603457a1..44d63a77 100644 --- a/netwerk/base/public/nsNetStrings.h +++ b/netwerk/base/public/nsNetStrings.h @@ -49,6 +49,7 @@ public: /** "content-length" */ const nsLiteralString kContentLength; + const nsLiteralString kContentDisposition; }; extern NS_HIDDEN_(nsNetStrings*) gNetStrings; diff --git a/netwerk/base/public/nsNetUtil.h b/netwerk/base/public/nsNetUtil.h index a0b82cc7..41752eeb 100644 --- a/netwerk/base/public/nsNetUtil.h +++ b/netwerk/base/public/nsNetUtil.h @@ -41,17 +41,21 @@ #ifndef nsNetUtil_h__ #define nsNetUtil_h__ +#include + #include "nsNetError.h" #include "nsNetCID.h" #include "nsReadableUtils.h" #include "nsString.h" #include "nsMemory.h" #include "nsCOMPtr.h" +#include "nsCRT.h" #include "prio.h" // for read/write flags, permissions, etc. #include "nsIURI.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" +#include "nsIURLParser.h" #include "nsISafeOutputStream.h" #include "nsIStreamListener.h" #include "nsIRequestObserverProxy.h" @@ -63,6 +67,7 @@ #include "nsIIOService.h" #include "nsIServiceManager.h" #include "nsIChannel.h" +#include "nsChannelProperties.h" #include "nsIInputStreamChannel.h" #include "nsITransport.h" #include "nsIStreamTransportService.h" @@ -87,6 +92,8 @@ #include "nsInterfaceRequestorAgg.h" #include "nsInt64.h" #include "nsINetUtil.h" +#include "nsIPropertyBag2.h" +#include "nsAutoLock.h" // Helper, to simplify getting the I/O service. inline const nsGetServiceByCIDWithError @@ -185,6 +192,19 @@ NS_NewChannel(nsIChannel **result, return rv; } +// For now, works only with JARChannel. Future: with all channels that may +// have Content-Disposition header (JAR, nsIHttpChannel, and nsIMultiPartChannel). +inline nsresult +NS_GetContentDisposition(nsIRequest *channel, + nsACString &result) +{ + nsCOMPtr props(do_QueryInterface(channel)); + if (props) + return props->GetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION, + result); + return NS_ERROR_NOT_AVAILABLE; +} + // Use this function with CAUTION. It creates a stream that blocks when you // Read() from it and blocking the UI thread is a bad idea. If you don't want // to implement a full blown asynchronous consumer (via nsIStreamListener) look @@ -1016,4 +1036,134 @@ NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *aCallbacks, return NS_NewInterfaceRequestorAggregation(aCallbacks, cbs, aResult); } +#define NSID_LENGTH 39 + +inline nsresult +GenerateUUIDInPlace(nsID* id) +{ + static PRLock* mLock = NULL; + if(!mLock) { + mLock = PR_NewLock(); + NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY); + } + + // The various code in this method is probably not threadsafe, so lock + // across the whole method. + nsAutoLock lock(mLock); + + PRUint8 mRBytes = 4; +#ifdef RAND_MAX + if ((unsigned long) RAND_MAX < (unsigned long)0xffffffff) + mRBytes = 3; + if ((unsigned long) RAND_MAX < (unsigned long)0x00ffffff) + mRBytes = 2; + if ((unsigned long) RAND_MAX < (unsigned long)0x0000ffff) + mRBytes = 1; + if ((unsigned long) RAND_MAX < (unsigned long)0x000000ff) + return NS_ERROR_FAILURE; +#endif + + PRSize bytesLeft = sizeof(nsID); + while (bytesLeft > 0) { + long rval = rand(); + + PRUint8 *src = (PRUint8*)&rval; + // We want to grab the mRBytes least significant bytes of rval, since + // mRBytes less than sizeof(rval) means the high bytes are 0. +#ifdef IS_BIG_ENDIAN + src += sizeof(rval) - mRBytes; +#endif + PRUint8 *dst = ((PRUint8*) id) + (sizeof(nsID) - bytesLeft); + PRSize toWrite = (bytesLeft < mRBytes ? bytesLeft : mRBytes); + for (PRSize i = 0; i < toWrite; i++) + dst[i] = src[i]; + + bytesLeft -= toWrite; + } + + /* Put in the version */ + id->m2 &= 0x0fff; + id->m2 |= 0x4000; + + /* Put in the variant */ + id->m3[0] &= 0x3f; + id->m3[0] |= 0x80; + + return NS_OK; +} + +/** + * Helper function to create a random URL string that's properly formed + * but guaranteed to be invalid. + */ +#define NU_FAKE_SCHEME "http://" +#define NU_FAKE_TLD ".invalid" +inline nsresult +NS_MakeRandomInvalidURLString(nsCString& result) +{ + nsresult rv; + + nsID idee; + rv = GenerateUUIDInPlace(&idee); + NS_ENSURE_SUCCESS(rv, rv); + + char chars[NSID_LENGTH]; + strncpy(chars, idee.ToString(), NSID_LENGTH); + + result.AssignLiteral(NU_FAKE_SCHEME); + // Strip off the '{' and '}' at the beginning and end of the UUID + result.Append(chars + 1, NSID_LENGTH - 3); + result.AppendLiteral(NU_FAKE_TLD); + + return NS_OK; +} +#undef NU_FAKE_SCHEME +#undef NU_FAKE_TLD + +/** + * Helper function to determine whether urlString is Java-compatible -- + * whether it can be passed to the Java URL(String) constructor without the + * latter throwing a MalformedURLException, or without Java otherwise + * mishandling it. + */ +inline nsresult +NS_CheckIsJavaCompatibleURLString(nsCString& urlString, PRBool *result) +{ + *result = PR_FALSE; // Default to "no" + + nsresult rv = NS_OK; + nsCOMPtr urlParser = + do_GetService(NS_STDURLPARSER_CONTRACTID, &rv); + if (NS_FAILED(rv) || !urlParser) + return NS_ERROR_FAILURE; + + PRBool compatible = PR_TRUE; + PRUint32 schemePos = 0; + PRInt32 schemeLen = 0; + urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen, + nsnull, nsnull, nsnull, nsnull); + if (schemeLen != -1) { + nsCString scheme; + scheme.Assign(urlString.get() + schemePos, schemeLen); + // By default Java only understands a small number of URL schemes, and of + // these only some are likely to represent user input (for example from a + // link or the location bar) that Java can legitimately be expected to + // handle. (Besides those listed below, Java also understands the "jar", + // "mailto" and "netdoc" schemes. But it probably doesn't expect these + // from a browser, and is therefore likely to mishandle them.) + if (nsCRT::strcasecmp(scheme.get(), "http") && + nsCRT::strcasecmp(scheme.get(), "https") && + nsCRT::strcasecmp(scheme.get(), "file") && + nsCRT::strcasecmp(scheme.get(), "ftp") && + nsCRT::strcasecmp(scheme.get(), "gopher")) + compatible = PR_FALSE; + } else { + compatible = PR_FALSE; + } + + *result = compatible; + + return NS_OK; +} + #endif // !nsNetUtil_h__ diff --git a/netwerk/base/src/nsNetStrings.cpp b/netwerk/base/src/nsNetStrings.cpp index b8d47d8f..d28e9b96 100644 --- a/netwerk/base/src/nsNetStrings.cpp +++ b/netwerk/base/src/nsNetStrings.cpp @@ -40,7 +40,8 @@ NS_HIDDEN_(nsNetStrings*) gNetStrings; nsNetStrings::nsNetStrings() - : NS_LITERAL_STRING_INIT(kContentLength, NS_CHANNEL_PROP_CONTENT_LENGTH_STR) + : NS_LITERAL_STRING_INIT(kContentLength, NS_CHANNEL_PROP_CONTENT_LENGTH_STR), + NS_LITERAL_STRING_INIT(kContentDisposition, NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR) {} diff --git a/netwerk/base/src/nsURLHelper.cpp b/netwerk/base/src/nsURLHelper.cpp index 087da144..d281974f 100644 --- a/netwerk/base/src/nsURLHelper.cpp +++ b/netwerk/base/src/nsURLHelper.cpp @@ -913,3 +913,94 @@ net_IsValidHostName(const nsCSubstring &host) // @ \ ^ { | } ~ DEL "\x40\x5c\x5e\x7b\x7c\x7d\x7e\x7f") == end; } + +PRBool +net_IsValidIPv4Addr(const char *addr, PRInt32 addrLen) +{ + const char *p; + + PRInt32 octet = -1; // means no digit yet + PRInt32 dotCount = 0; // number of dots in the address + + for (p = addr; addrLen; ++p, --addrLen) { + if (*p == '.') { + dotCount++; + if (octet == -1) { + // invalid octet + return PR_FALSE; + } + octet = -1; + } else if (*p >= '0' && *p <='9') { + if (octet == 0) { + // leading 0 is not allowed + return PR_FALSE; + } else if (octet == -1) { + octet = *p - '0'; + } else { + octet *= 10; + octet += *p - '0'; + if (octet > 255) + return PR_FALSE; + } + } else { + // invalid character + return PR_FALSE; + } + } + + return (dotCount == 3 && octet != -1); +} + +PRBool +net_IsValidIPv6Addr(const char *addr, PRInt32 addrLen) +{ + const char *p; + + PRInt32 digits = 0; // number of digits in current block + PRInt32 colons = 0; // number of colons in a row during parsing + PRInt32 blocks = 0; // number of hexadecimal blocks + PRBool haveZeros = PR_FALSE; // true if double colon is present in the address + + for (p = addr; addrLen; ++p, --addrLen) { + if (*p == ':') { + if (colons == 0) { + if (digits != 0) { + digits = 0; + blocks++; + } + } else if (colons == 1) { + if (haveZeros) + return PR_FALSE; // only one occurrence is allowed + haveZeros = PR_TRUE; + } else { + // too many colons in a row + return PR_FALSE; + } + colons++; + } else if ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || + (*p >= 'A' && *p <= 'F')) { + if (colons == 1 && blocks == 0) // starts with a single colon + return PR_FALSE; + if (digits == 4) // too many digits + return PR_FALSE; + colons = 0; + digits++; + } else if (*p == '.') { + // check valid IPv4 from the beginning of the last block + if (!net_IsValidIPv4Addr(p - digits, addrLen + digits)) + return PR_FALSE; + return (haveZeros && blocks < 6) || (!haveZeros && blocks == 6); + } else { + // invalid character + return PR_FALSE; + } + } + + if (colons == 1) // ends with a single colon + return PR_FALSE; + + if (digits) // there is a block at the end + blocks++; + + return (haveZeros && blocks < 8) || (!haveZeros && blocks == 8); +} diff --git a/netwerk/base/src/nsURLHelper.h b/netwerk/base/src/nsURLHelper.h index f7232fbd..02602b49 100644 --- a/netwerk/base/src/nsURLHelper.h +++ b/netwerk/base/src/nsURLHelper.h @@ -235,4 +235,14 @@ inline char *net_RFindCharNotInSet(const char *str, const char *set) */ NS_HIDDEN_(PRBool) net_IsValidHostName(const nsCSubstring &host); +/** + * Checks whether the IPv4 address is valid according to RFC 3986 section 3.2.2. + */ +NS_HIDDEN_(PRBool) net_IsValidIPv4Addr(const char *addr, PRInt32 addrLen); + +/** + * Checks whether the IPv6 address is valid according to RFC 3986 section 3.2.2. + */ +NS_HIDDEN_(PRBool) net_IsValidIPv6Addr(const char *addr, PRInt32 addrLen); + #endif // !nsURLHelper_h__ diff --git a/netwerk/base/src/nsURLParsers.cpp b/netwerk/base/src/nsURLParsers.cpp index 1203ce86..dac39350 100644 --- a/netwerk/base/src/nsURLParsers.cpp +++ b/netwerk/base/src/nsURLParsers.cpp @@ -631,6 +631,13 @@ nsAuthURLParser::ParseServerInfo(const char *serverinfo, PRInt32 serverinfoLen, if (port) *port = -1; } + + // In case of IPv6 address check its validity + if (*hostnameLen > 1 && *(serverinfo + *hostnamePos) == '[' && + *(serverinfo + *hostnamePos + *hostnameLen - 1) == ']' && + !net_IsValidIPv6Addr(serverinfo + *hostnamePos + 1, *hostnameLen - 2)) + return NS_ERROR_MALFORMED_URI; + return NS_OK; } diff --git a/netwerk/protocol/http/src/nsHttpAtomList.h b/netwerk/protocol/http/src/nsHttpAtomList.h index 77096dae..f11c724d 100644 --- a/netwerk/protocol/http/src/nsHttpAtomList.h +++ b/netwerk/protocol/http/src/nsHttpAtomList.h @@ -62,6 +62,7 @@ HTTP_ATOM(Authorization, "Authorization") HTTP_ATOM(Cache_Control, "Cache-Control") HTTP_ATOM(Connection, "Connection") HTTP_ATOM(Content_Base, "Content-Base") +HTTP_ATOM(Content_Disposition, "Content-Disposition") HTTP_ATOM(Content_Encoding, "Content-Encoding") HTTP_ATOM(Content_Language, "Content-Language") HTTP_ATOM(Content_Length, "Content-Length") diff --git a/netwerk/protocol/http/src/nsHttpChannel.cpp b/netwerk/protocol/http/src/nsHttpChannel.cpp index 36174539..efd8ff65 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -706,8 +706,12 @@ nsresult nsHttpChannel::CallOnStartRequest() { if (mResponseHead && mResponseHead->ContentType().IsEmpty()) { + NS_ASSERTION(mConnectionInfo, "Should have connection info here"); if (!mContentTypeHint.IsEmpty()) mResponseHead->SetContentType(mContentTypeHint); + else if (mResponseHead->Version() == NS_HTTP_VERSION_0_9 && + mConnectionInfo->Port() != mConnectionInfo->DefaultPort()) + mResponseHead->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN)); else { // Uh-oh. We had better find out what type we are! diff --git a/netwerk/socket/base/nsSOCKSIOLayer.cpp b/netwerk/socket/base/nsSOCKSIOLayer.cpp index 7e0f75c2..a714cd61 100644 --- a/netwerk/socket/base/nsSOCKSIOLayer.cpp +++ b/netwerk/socket/base/nsSOCKSIOLayer.cpp @@ -162,21 +162,41 @@ nsSOCKSSocketInfo::SetInternalProxyAddr(PRNetAddr *aInternalProxyAddr) return NS_OK; } +static PRInt32 +pr_RecvAll(PRFileDesc *fd, unsigned char *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 bytesRead = 0; + PRInt32 offset = 0; + + while (offset < amount) { + bytesRead = PR_Recv(fd, buf + offset, amount - offset, flags, timeout); + if (bytesRead > 0) { + offset += bytesRead; + } else if (bytesRead == 0 || offset != 0) { + return offset; + } else { + return bytesRead; + } + } + return offset; +} // Negotiate a SOCKS 5 connection. Assumes the TCP connection to the socks // server port has been established. static nsresult ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRIntervalTime timeout) { + int request_len = 0; + int response_len = 0; + int desired_len = 0; + unsigned char request[22]; + unsigned char response[262]; + NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(extAddr, NS_ERROR_NOT_INITIALIZED); - unsigned char request[22]; - int request_len = 0; - unsigned char response[22]; - int response_len = 0; - request[0] = 0x05; // SOCKS version 5 request[1] = 0x01; // number of auth procotols we recognize // auth protocols @@ -197,11 +217,11 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter return NS_ERROR_FAILURE; } - // get the server's response. Use PR_Recv() instead of - response_len = 2; - response_len = PR_Recv(fd, response, response_len, 0, timeout); + // get the server's response. + desired_len = 2; + response_len = pr_RecvAll(fd, response, desired_len, 0, timeout); - if (response_len <= 0) { + if (response_len < desired_len) { LOGERROR(("PR_Recv() failed. response_len = %d.", response_len)); return NS_ERROR_FAILURE; @@ -357,17 +377,14 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter return NS_ERROR_FAILURE; } - response_len = 22; - response_len = PR_Recv(fd, response, response_len, 0, timeout); - if (response_len <= 0) { - - // bad read + desired_len = 5; + response_len = pr_RecvAll(fd, response, desired_len, 0, timeout); + if (response_len < desired_len) { // bad read LOGERROR(("PR_Recv() failed getting connect command reply. response_len = %d.", response_len)); return NS_ERROR_FAILURE; } if (response[0] != 0x05) { - // bad response LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0])); return NS_ERROR_FAILURE; @@ -397,6 +414,26 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter } + switch (response[3]) { + case 0x01: // IPv4 + desired_len = 4 + 2 - 1; + break; + case 0x03: // FQDN + desired_len = response[4] + 2; + break; + case 0x04: // IPv6 + desired_len = 16 + 2 - 1; + break; + default: // unknown format + return NS_ERROR_FAILURE; + break; + } + response_len = pr_RecvAll(fd, response + 5, desired_len, 0, timeout); + if (response_len < desired_len) { // bad read + LOGERROR(("PR_Recv() failed getting connect command reply. response_len = %d.", response_len)); + return NS_ERROR_FAILURE; + } + response_len += 5; // get external bound address (this is what // the outside world sees as "us") @@ -434,17 +471,16 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter *ip++ = response[18]; *ip++ = response[19]; break; - case 0x03: // FQDN (should not get this back) - default: // unknown format + case 0x03: // FQDN // if we get here, we don't know our external address. // however, as that's possibly not critical to the user, // we let it slide. - PR_InitializeNetAddr(PR_IpAddrNull, 0, extAddr); - //return NS_ERROR_FAILURE; + extPort = (response[response_len - 2] << 8) | + response[response_len - 1]; + PR_InitializeNetAddr(PR_IpAddrNull, extPort, extAddr); break; } return NS_OK; - } // Negotiate a SOCKS 4 connection. Assumes the TCP connection to the socks @@ -452,15 +488,16 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter static nsresult ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) { - NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED); - - unsigned char request[12]; int request_len = 0; int write_len; - unsigned char response[10]; int response_len = 0; + int desired_len = 0; char *ip = nsnull; + unsigned char request[12]; + unsigned char response[10]; + + NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED); request[0] = 0x04; // SOCKS version 4 request[1] = 0x01; // CD command code -- 1 for connect @@ -564,10 +601,9 @@ ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) } // get the server's response - response_len = 8; // size of the response - response_len = PR_Recv(fd, response, response_len, 0, timeout); - - if (response_len <= 0) { + desired_len = 8; // size of the response + response_len = pr_RecvAll(fd, response, desired_len, 0, timeout); + if (response_len < desired_len) { LOGERROR(("PR_Recv() failed. response_len = %d.", response_len)); return NS_ERROR_FAILURE; } diff --git a/netwerk/streamconv/converters/ParseFTPList.cpp b/netwerk/streamconv/converters/ParseFTPList.cpp index 9a14b924..4ee5646d 100644 --- a/netwerk/streamconv/converters/ParseFTPList.cpp +++ b/netwerk/streamconv/converters/ParseFTPList.cpp @@ -39,10 +39,17 @@ #include #include #include +#include "nsDebug.h" #include "ParseFTPList.h" /* ==================================================================== */ +static inline int ParsingFailed(struct list_state *state) +{ + if (state->parsed_one || state->lstyle) /* junk if we fail to parse */ + return '?'; /* this time but had previously parsed successfully */ + return '"'; /* its part of a comment or error message */ +} int ParseFTPList(const char *line, struct list_state *state, struct list_result *result ) @@ -122,6 +129,9 @@ int ParseFTPList(const char *line, struct list_state *state, } } + if (!numtoks) + return ParsingFailed(state); + linelen_sans_wsp = &(tokens[numtoks-1][toklen[numtoks-1]]) - tokens[0]; if (numtoks == (sizeof(tokens)/sizeof(tokens[0])) ) { @@ -355,11 +365,16 @@ int ParseFTPList(const char *line, struct list_state *state, pos++; p++; } - if (lstyle && pos < (toklen[0]-1) && *p == ']') + if (lstyle && pos < (toklen[0]-1)) { + /* ']' was found and there is at least one character after it */ + NS_ASSERTION(*p == ']', "unexpected state"); pos++; p++; tokmarker = pos; /* length of leading "[DIR1.DIR2.etc]" */ + } else { + /* not a CMU style listing */ + lstyle = 0; } } while (lstyle && pos < toklen[0] && *p != ';') @@ -386,7 +401,7 @@ int ParseFTPList(const char *line, struct list_state *state, pos -= tokmarker; /* => fnlength sans "[DIR1.DIR2.etc]" */ p = &(tokens[0][tokmarker]); /* offset of basename */ - if (!lstyle || pos > 80) /* VMS filenames can't be longer than that */ + if (!lstyle || pos == 0 || pos > 80) /* VMS filenames can't be longer than that */ { lstyle = 0; } @@ -1632,9 +1647,7 @@ int ParseFTPList(const char *line, struct list_state *state, } /* if (linelen > 0) */ - if (state->parsed_one || state->lstyle) /* junk if we fail to parse */ - return '?'; /* this time but had previously parsed sucessfully */ - return '"'; /* its part of a comment or error message */ + return ParsingFailed(state); } /* ==================================================================== */ @@ -1653,7 +1666,7 @@ static int do_it(FILE *outfile, char *p; int rc; - rc = ParseFTPLIST( line, state, &result ); + rc = ParseFTPList( line, state, &result ); if (!outfile) { diff --git a/netwerk/streamconv/converters/nsDirIndexParser.cpp b/netwerk/streamconv/converters/nsDirIndexParser.cpp index f687fe1e..ae1da935 100644 --- a/netwerk/streamconv/converters/nsDirIndexParser.cpp +++ b/netwerk/streamconv/converters/nsDirIndexParser.cpp @@ -179,8 +179,6 @@ nsDirIndexParser::ParseFormat(const char* aFormatStr) { // Parse a "200" format line, and remember the fields and their // ordering in mFormat. Multiple 200 lines stomp on each other. - delete[] mFormat; - // Lets find out how many elements we have. // easier to do this then realloc const char* pos = aFormatStr; @@ -203,6 +201,7 @@ nsDirIndexParser::ParseFormat(const char* aFormatStr) { } while (*pos); + delete[] mFormat; mFormat = new int[num+1]; // Prevent NULL Deref - Bug 443299 if (mFormat == nsnull) diff --git a/netwerk/streamconv/converters/nsIndexedToHTML.cpp b/netwerk/streamconv/converters/nsIndexedToHTML.cpp index b6219cd2..a9fe9ff4 100644 --- a/netwerk/streamconv/converters/nsIndexedToHTML.cpp +++ b/netwerk/streamconv/converters/nsIndexedToHTML.cpp @@ -133,6 +133,30 @@ nsIndexedToHTML::AsyncConvertData(const char *aFromType, NS_IMETHODIMP nsIndexedToHTML::OnStartRequest(nsIRequest* request, nsISupports *aContext) { + nsString buffer; + nsresult rv = DoOnStartRequest(request, aContext, buffer); + if (NS_FAILED(rv)) { + request->Cancel(rv); + } + + // Push buffer to the listener now, so the initial HTML will not + // be parsed in OnDataAvailable(). + + rv = mListener->OnStartRequest(request, aContext); + if (NS_FAILED(rv)) return rv; + + // The request may have been canceled, and if that happens, we want to + // suppress calls to OnDataAvailable. + request->GetStatus(&rv); + if (NS_FAILED(rv)) return rv; + + rv = FormatInputStream(request, aContext, buffer); + return rv; +} + +nsresult +nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext, + nsString& aBuffer) { nsresult rv; nsCOMPtr channel = do_QueryInterface(request); @@ -393,18 +417,7 @@ nsIndexedToHTML::OnStartRequest(nsIRequest* request, nsISupports *aContext) { buffer.AppendLiteral("\n"); } - // Push buffer to the listener now, so the initial HTML will not - // be parsed in OnDataAvailable(). - - rv = mListener->OnStartRequest(request, aContext); - if (NS_FAILED(rv)) return rv; - - // The request may have been canceled, and if that happens, we want to - // suppress calls to OnDataAvailable. - request->GetStatus(&rv); - if (NS_FAILED(rv)) return rv; - - rv = FormatInputStream(request, aContext, buffer); + aBuffer = buffer; return rv; } diff --git a/netwerk/streamconv/converters/nsIndexedToHTML.h b/netwerk/streamconv/converters/nsIndexedToHTML.h index 5829af96..52069b1a 100644 --- a/netwerk/streamconv/converters/nsIndexedToHTML.h +++ b/netwerk/streamconv/converters/nsIndexedToHTML.h @@ -76,7 +76,10 @@ public: protected: void FormatSizeString(PRInt64 inSize, nsString& outSizeString); - nsresult FormatInputStream(nsIRequest* aRequest, nsISupports *aContext, const nsAString &aBuffer); + nsresult FormatInputStream(nsIRequest* aRequest, nsISupports *aContext, const nsAString &aBuffer); + // Helper to properly implement OnStartRequest + nsresult DoOnStartRequest(nsIRequest* request, nsISupports *aContext, + nsString& aBuffer); protected: nsCOMPtr mParser; @@ -97,4 +100,3 @@ private: }; #endif - diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.cpp b/netwerk/streamconv/converters/nsMultiMixedConv.cpp index ccefbcb4..cbf06554 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp +++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp @@ -48,6 +48,7 @@ #include "nsCRT.h" #include "nsIHttpChannelInternal.h" #include "nsURLHelper.h" +#include "nsIStreamConverterService.h" // // Helper function for determining the length of data bytes up to @@ -67,7 +68,10 @@ LengthToToken(const char *cursor, const char *token) return len; } -nsPartChannel::nsPartChannel(nsIChannel *aMultipartChannel, PRUint32 aPartID) : +nsPartChannel::nsPartChannel(nsIChannel *aMultipartChannel, PRUint32 aPartID, + nsIStreamListener* aListener) : + mMultipartChannel(aMultipartChannel), + mListener(aListener), mStatus(NS_OK), mContentLength(LL_MAXUINT), mIsByteRangeRequest(PR_FALSE), @@ -96,6 +100,26 @@ void nsPartChannel::InitializeByteRange(PRInt64 aStart, PRInt64 aEnd) mByteRangeEnd = aEnd; } +nsresult nsPartChannel::SendOnStartRequest(nsISupports* aContext) +{ + return mListener->OnStartRequest(this, aContext); +} + +nsresult nsPartChannel::SendOnDataAvailable(nsISupports* aContext, + nsIInputStream* aStream, + PRUint32 aOffset, PRUint32 aLen) +{ + return mListener->OnDataAvailable(this, aContext, aStream, aOffset, aLen); +} + +nsresult nsPartChannel::SendOnStopRequest(nsISupports* aContext, + nsresult aStatus) +{ + // Drop the listener + nsCOMPtr listener; + listener.swap(mListener); + return listener->OnStopRequest(this, aContext, aStatus); +} // // nsISupports implementation... @@ -734,15 +758,30 @@ nsresult nsMultiMixedConv::SendStart(nsIChannel *aChannel) { nsresult rv = NS_OK; - if (mContentType.IsEmpty()) + nsCOMPtr partListener(mFinalListener); + if (mContentType.IsEmpty()) { mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE); + nsCOMPtr serv = + do_GetService("@mozilla.org/streamConverters;1", &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr converter; + rv = serv->AsyncConvertData(UNKNOWN_CONTENT_TYPE, + "*/*", + mFinalListener, + mContext, + getter_AddRefs(converter)); + if (NS_SUCCEEDED(rv)) { + partListener = converter; + } + } + } // if we already have an mPartChannel, that means we never sent a Stop() // before starting up another "part." that would be bad. NS_ASSERTION(!mPartChannel, "tisk tisk, shouldn't be overwriting a channel"); nsPartChannel *newChannel; - newChannel = new nsPartChannel(aChannel, mCurrentPartID++); + newChannel = new nsPartChannel(aChannel, mCurrentPartID++, partListener); if (!newChannel) return NS_ERROR_OUT_OF_MEMORY; @@ -780,7 +819,7 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) { // Let's start off the load. NOTE: we don't forward on the channel passed // into our OnDataAvailable() as it's the root channel for the raw stream. - return mFinalListener->OnStartRequest(mPartChannel, mContext); + return mPartChannel->SendOnStartRequest(mContext); } @@ -789,7 +828,7 @@ nsMultiMixedConv::SendStop(nsresult aStatus) { nsresult rv = NS_OK; if (mPartChannel) { - rv = mFinalListener->OnStopRequest(mPartChannel, mContext, aStatus); + rv = mPartChannel->SendOnStopRequest(mContext, aStatus); // don't check for failure here, we need to remove the channel from // the loadgroup. @@ -836,7 +875,7 @@ nsMultiMixedConv::SendData(char *aBuffer, PRUint32 aLen) { nsCOMPtr inStream(do_QueryInterface(ss, &rv)); if (NS_FAILED(rv)) return rv; - return mFinalListener->OnDataAvailable(mPartChannel, mContext, inStream, offset, aLen); + return mPartChannel->SendOnDataAvailable(mContext, inStream, offset, aLen); } PRInt32 diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.h b/netwerk/streamconv/converters/nsMultiMixedConv.h index db96aaa1..a3664ccf 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.h +++ b/netwerk/streamconv/converters/nsMultiMixedConv.h @@ -68,10 +68,15 @@ class nsPartChannel : public nsIChannel, public nsIMultiPartChannel { public: - nsPartChannel(nsIChannel *aMultipartChannel, PRUint32 aPartID); + nsPartChannel(nsIChannel *aMultipartChannel, PRUint32 aPartID, + nsIStreamListener* aListener); void InitializeByteRange(PRInt64 aStart, PRInt64 aEnd); void SetIsLastPart() { mIsLastPart = PR_TRUE; } + nsresult SendOnStartRequest(nsISupports* aContext); + nsresult SendOnDataAvailable(nsISupports* aContext, nsIInputStream* aStream, + PRUint32 aOffset, PRUint32 aLen); + nsresult SendOnStopRequest(nsISupports* aContext, nsresult aStatus); NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST @@ -84,6 +89,7 @@ protected: protected: nsCOMPtr mMultipartChannel; + nsCOMPtr mListener; nsresult mStatus; nsLoadFlags mLoadFlags; diff --git a/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp b/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp index 4d5c1f94..16412924 100644 --- a/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp +++ b/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp @@ -37,6 +37,7 @@ #include "nsTXTToHTMLConv.h" #include "nsNetUtil.h" +#include "nsEscape.h" #include "nsIStringStream.h" #include "nsAutoPtr.h" @@ -315,11 +316,24 @@ nsTXTToHTMLConv::CatHTML(PRInt32 front, PRInt32 back) nsString linkText; // href is implied mBuffer.Mid(linkText, front, back-front); + mBuffer.Insert(NS_LITERAL_STRING("modText, cursor); - cursor += modLen-front+back; + cursor += modLen; + } + + NS_ConvertUTF16toUTF8 linkTextUTF8(linkText); + nsCString escaped; + if (NS_EscapeURL(linkTextUTF8.Data(), linkTextUTF8.Length(), esc_Minimal, escaped)) { + mBuffer.Cut(cursor, back - front); + CopyUTF8toUTF16(escaped, linkText); + mBuffer.Insert(linkText, cursor); + back = front + linkText.Length(); + } + + cursor += back-front; mBuffer.Insert(NS_LITERAL_STRING("\">"), cursor); cursor += 2; mBuffer.Insert(linkText, cursor); diff --git a/netwerk/streamconv/test/Makefile.in b/netwerk/streamconv/test/Makefile.in index cd287365..68f4f7c1 100644 --- a/netwerk/streamconv/test/Makefile.in +++ b/netwerk/streamconv/test/Makefile.in @@ -73,4 +73,3 @@ DEFINES += -DNGPREFS endif endif # WINNT -DEFINES += -DIMPL_NS_NET diff --git a/netwerk/test/unit/test_bug504014.js b/netwerk/test/unit/test_bug504014.js new file mode 100644 index 00000000..527a02a2 --- /dev/null +++ b/netwerk/test/unit/test_bug504014.js @@ -0,0 +1,73 @@ +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; + +var valid_URIs = [ "http://[::]/", + "http://[::1]/", + "http://[1::]/", + "http://[::]/", + "http://[::1]/", + "http://[1::]/", + "http://[1:2:3:4:5:6:7::]/", + "http://[::1:2:3:4:5:6:7]/", + "http://[1:2:a:B:c:D:e:F]/", + "http://[1::8]/", + "http://[1:2::8]/", + "http://[0000:0123:4567:89AB:CDEF:abcd:ef00:0000]/", + "http://[::192.168.1.1]/", + "http://[1::0.0.0.0]/", + "http://[1:2::255.255.255.255]/", + "http://[1:2:3::255.255.255.255]/", + "http://[1:2:3:4::255.255.255.255]/", + "http://[1:2:3:4:5::255.255.255.255]/", + "http://[1:2:3:4:5:6:255.255.255.255]/"]; + +var invalid_URIs = [ "http://[1]/", + "http://[192.168.1.1]/", + "http://[:::]/", + "http://[:::1]/", + "http://[1:::]/", + "http://[::1::]/", + "http://[1:2:3:4:5:6:7:]/", + "http://[:2:3:4:5:6:7:8]/", + "http://[1:2:3:4:5:6:7:8:]/", + "http://[:1:2:3:4:5:6:7:8]/", + "http://[1:2:3:4:5:6:7:8::]/", + "http://[::1:2:3:4:5:6:7:8]/", + "http://[1:2:3:4:5:6:7]/", + "http://[1:2:3:4:5:6:7:8:9]/", + "http://[00001:2:3:4:5:6:7:8]/", + "http://[0001:2:3:4:5:6:7:89abc]/", + "http://[A:b:C:d:E:f:G:h]/", + "http://[::192.168.1]/", + "http://[::192.168.1.]/", + "http://[::.168.1.1]/", + "http://[::192..1.1]/", + "http://[::0192.168.1.1]/", + "http://[::256.255.255.255]/", + "http://[::1x.255.255.255]/", + "http://[::192.4294967464.1.1]/", + "http://[1:2:3:4:5:6::255.255.255.255]/", + "http://[1:2:3:4:5:6:7:255.255.255.255]/"]; + +function run_test() { + var ios = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + + for (var i=0 ; i", type: "text/xml" } + ]; + +function responseHandler(request, buffer) +{ + do_check_eq(buffer, testData[testNum].data); + do_check_eq(request.QueryInterface(Ci.nsIChannel).contentType, + testData[testNum].type); + if (++testNum == numTests) + httpserver.stop(do_test_finished); +} + +var multipartListener = { + _buffer: "", + + QueryInterface: function(iid) { + if (iid.equals(Components.interfaces.nsIStreamListener) || + iid.equals(Components.interfaces.nsIRequestObserver) || + iid.equals(Components.interfaces.nsISupports)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + onStartRequest: function(request, context) { + this._buffer = ""; + }, + + onDataAvailable: function(request, context, stream, offset, count) { + try { + this._buffer = this._buffer.concat(read_stream(stream, count)); + dump("BUFFEEE: " + this._buffer + "\n\n"); + } catch (ex) { + do_throw("Error in onDataAvailable: " + ex); + } + }, + + onStopRequest: function(request, context, status) { + try { + responseHandler(request, this._buffer); + } catch (ex) { + do_throw("Error in closure function: " + ex); + } + } +}; + +function run_test() +{ + httpserver = new nsHttpServer(); + httpserver.registerPathHandler("/multipart", contentHandler); + httpserver.start(4444); + + var streamConv = Cc["@mozilla.org/streamConverters;1"] + .getService(Ci.nsIStreamConverterService); + var conv = streamConv.asyncConvertData("multipart/mixed", + "*/*", + multipartListener, + null); + + var chan = make_channel(uri); + chan.asyncOpen(conv, null); + do_test_pending(); +} diff --git a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp index 3fe7bf0f..43eb429f 100644 --- a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp +++ b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp @@ -602,7 +602,15 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress, nsCOMPtr windowForProgress; aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress)); - const PRBool isToplevelProgress = (windowForProgress.get() == mWindow.get()); + PRBool isNoContentResponse = PR_FALSE; + nsCOMPtr httpChannel = do_QueryInterface(aRequest); + if (httpChannel) + { + PRUint32 response; + isNoContentResponse = NS_SUCCEEDED(httpChannel->GetResponseStatus(&response)) && + (response == 204 || response == 205); + } + const PRBool isToplevelProgress = (windowForProgress.get() == mWindow.get()) && !isNoContentResponse; #ifdef PR_LOGGING if (windowForProgress) diff --git a/security/manager/pki/resources/content/device_manager.js b/security/manager/pki/resources/content/device_manager.js index a70e2b2a..4957847e 100644 --- a/security/manager/pki/resources/content/device_manager.js +++ b/security/manager/pki/resources/content/device_manager.js @@ -47,6 +47,8 @@ const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1"; const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB; const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock; const nsDialogParamBlock = "@mozilla.org/embedcomp/dialogparam;1"; +const nsIPKCS11 = Components.interfaces.nsIPKCS11; +const nsPKCS11ContractID = "@mozilla.org/security/pkcs11;1"; var bundle; var secmoddb; @@ -63,6 +65,31 @@ function LoadModules() RefreshDeviceList(); } +function getPKCS11() +{ + return Components.classes[nsPKCS11ContractID].getService(nsIPKCS11); +} + +function getNSSString(name) +{ + return srGetStrBundle("chrome://pipnss/locale/pipnss.properties"). + GetStringFromName(name); +} + +function doPrompt(msg) +{ + prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Components.interfaces.nsIPromptService); + prompts.alert(window, null, msg); +} + +function doConfirm(msg) +{ + prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Components.interfaces.nsIPromptService); + return prompts.confirm(window, null, msg); +} + function RefreshDeviceList() { var modules = secmoddb.listModules(); @@ -383,11 +410,27 @@ function doLoad() RefreshDeviceList(); } -function doUnload() +function deleteSelected() { getSelectedItem(); - if (selected_module) { - pkcs11.deletemodule(selected_module.name); + if (selected_module && + doConfirm(getNSSString("DelModuleWarning"))) { + try { + getPKCS11().deleteModule(selected_module.name); + } + catch (e) { + doPrompt(getNSSString("DelModuleError")); + return false; + } + selected_module = null; + return true; + } + return false; +} + +function doUnload() +{ + if (deleteSelected()) { ClearDeviceList(); RefreshDeviceList(); } @@ -436,7 +479,17 @@ function doLoadDevice() { var name_box = document.getElementById("device_name"); var path_box = document.getElementById("device_path"); - pkcs11.addmodule(name_box.value, path_box.value, 0,0); + try { + getPKCS11().addModule(name_box.value, path_box.value, 0,0); + } + catch (e) { + if (e.result == Components.results.NS_ERROR_ILLEGAL_VALUE) + doPrompt(getNSSString("AddModuleDup")); + else + doPrompt(getNSSString("AddModuleFailure")); + + return false; + } return true; } diff --git a/security/manager/ssl/public/Makefile.in b/security/manager/ssl/public/Makefile.in index 691982b1..6b57dd83 100644 --- a/security/manager/ssl/public/Makefile.in +++ b/security/manager/ssl/public/Makefile.in @@ -65,6 +65,7 @@ XPIDLSRCS = \ nsIX509Cert3.idl \ nsIX509Cert18Branch.idl \ nsIX509CertDB2.idl \ + nsIPKCS11.idl \ nsIPKCS11Slot.idl \ nsIPK11TokenDB.idl \ nsICertPickDialogs.idl \ diff --git a/security/manager/ssl/public/nsIPKCS11.idl b/security/manager/ssl/public/nsIPKCS11.idl new file mode 100644 index 00000000..50b68c1e --- /dev/null +++ b/security/manager/ssl/public/nsIPKCS11.idl @@ -0,0 +1,49 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Johnny Stenback + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +[scriptable, uuid(5743f870-958e-4f02-aef2-c0afeef67f05)] +interface nsIPKCS11 : nsISupports +{ + void deleteModule(in AString moduleName); + void addModule(in AString moduleName, + in AString libraryFullPath, + in long cryptoMechanismFlags, + in long cipherFlags); +}; diff --git a/security/manager/ssl/src/nsCrypto.cpp b/security/manager/ssl/src/nsCrypto.cpp index 8314a86d..6724c74a 100644 --- a/security/manager/ssl/src/nsCrypto.cpp +++ b/security/manager/ssl/src/nsCrypto.cpp @@ -215,9 +215,8 @@ NS_IMPL_RELEASE(nsCRMFObject) // QueryInterface implementation for nsPkcs11 NS_INTERFACE_MAP_BEGIN(nsPkcs11) - NS_INTERFACE_MAP_ENTRY(nsIDOMPkcs11) + NS_INTERFACE_MAP_ENTRY(nsIPKCS11) NS_INTERFACE_MAP_ENTRY(nsISupports) - NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(Pkcs11) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsPkcs11) @@ -608,6 +607,9 @@ cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo, void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params, (params) ? strlen(params):0, keySize); + if (!keyGenParams) { + return NS_ERROR_INVALID_ARG; + } // Make sure the token has password already set on it before trying // to generate the key. @@ -2559,33 +2561,18 @@ confirm_user(const PRUnichar *message) //Delete a PKCS11 module from the user's profile. NS_IMETHODIMP -nsPkcs11::Deletemodule(const nsAString& aModuleName, PRInt32* aReturn) +nsPkcs11::DeleteModule(const nsAString& aModuleName) { nsNSSShutDownPreventionLock locker; nsresult rv; nsString errorMessage; nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); + if (NS_FAILED(rv)) + return rv; + if (aModuleName.IsEmpty()) { - *aReturn = JS_ERR_BAD_MODULE_NAME; - nssComponent->GetPIPNSSBundleString("DelModuleBadName", errorMessage); - alertUser(errorMessage.get()); - return NS_OK; - } - nsString final; - nsAutoString temp; - //Make sure the user knows we're trying to do this. - nssComponent->GetPIPNSSBundleString("DelModuleWarning", final); - final.Append(NS_LITERAL_STRING("\n").get()); - PRUnichar *tempUni = ToNewUnicode(aModuleName); - const PRUnichar *formatStrings[1] = { tempUni }; - rv = nssComponent->PIPBundleFormatStringFromName("AddModuleName", - formatStrings, 1, temp); - nsMemory::Free(tempUni); - final.Append(temp); - if (!confirm_user(final.get())) { - *aReturn = JS_ERR_USER_CANCEL_ACTION; - return NS_OK; + return NS_ERROR_ILLEGAL_VALUE; } char *modName = ToNewCString(aModuleName); @@ -2597,69 +2584,25 @@ nsPkcs11::Deletemodule(const nsAString& aModuleName, PRInt32* aReturn) nssComponent->ShutdownSmartCardThread(module); SECMOD_DestroyModule(module); } - if (modType == SECMOD_EXTERNAL) { - nssComponent->GetPIPNSSBundleString("DelModuleExtSuccess", errorMessage); - *aReturn = JS_OK_DEL_EXTERNAL_MOD; - } else { - nssComponent->GetPIPNSSBundleString("DelModuleIntSuccess", errorMessage); - *aReturn = JS_OK_DEL_INTERNAL_MOD; - } + rv = NS_OK; } else { - *aReturn = JS_ERR_DEL_MOD; - nssComponent->GetPIPNSSBundleString("DelModuleError", errorMessage); + rv = NS_ERROR_FAILURE; } - alertUser(errorMessage.get()); - return NS_OK; + NS_Free(modName); + return rv; } //Add a new PKCS11 module to the user's profile. NS_IMETHODIMP -nsPkcs11::Addmodule(const nsAString& aModuleName, +nsPkcs11::AddModule(const nsAString& aModuleName, const nsAString& aLibraryFullPath, PRInt32 aCryptoMechanismFlags, - PRInt32 aCipherFlags, PRInt32* aReturn) + PRInt32 aCipherFlags) { nsNSSShutDownPreventionLock locker; nsresult rv; nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); - nsString final; - nsAutoString temp; - rv = nssComponent->GetPIPNSSBundleString("AddModulePrompt", final); - if (NS_FAILED(rv)) - return rv; - - final.Append(NS_LITERAL_STRING("\n").get()); - - PRUnichar *tempUni = ToNewUnicode(aModuleName); - const PRUnichar *formatStrings[1] = { tempUni }; - rv = nssComponent->PIPBundleFormatStringFromName("AddModuleName", - formatStrings, 1, temp); - nsMemory::Free(tempUni); - - if (NS_FAILED(rv)) - return rv; - - final.Append(temp); - final.Append(NS_LITERAL_STRING("\n").get()); - - tempUni = ToNewUnicode(aLibraryFullPath); - formatStrings[0] = tempUni; - rv = nssComponent->PIPBundleFormatStringFromName("AddModulePath", - formatStrings, 1, temp); - nsMemory::Free(tempUni); - if (NS_FAILED(rv)) - return rv; - - final.Append(temp); - final.Append(NS_LITERAL_STRING("\n").get()); - - if (!confirm_user(final.get())) { - // The user has canceled. So let's return now. - *aReturn = JS_ERR_USER_CANCEL_ACTION; - return NS_OK; - } - char *moduleName = ToNewCString(aModuleName); char *fullPath = ToNewCString(aLibraryFullPath); PRUint32 mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags); @@ -2681,22 +2624,13 @@ nsPkcs11::Addmodule(const nsAString& aModuleName, // what the return value for SEDMOD_AddNewModule is switch (srv) { case SECSuccess: - nssComponent->GetPIPNSSBundleString("AddModuleSuccess", final); - *aReturn = JS_OK_ADD_MOD; - break; + return NS_OK; case SECFailure: - nssComponent->GetPIPNSSBundleString("AddModuleFailure", final); - *aReturn = JS_ERR_ADD_MOD; - break; - case -2: - nssComponent->GetPIPNSSBundleString("AddModuleDup", final); - *aReturn = JS_ERR_ADD_DUPLICATE_MOD; - break; - default: - NS_ASSERTION(0,"Bogus return value, this should never happen"); return NS_ERROR_FAILURE; + case -2: + return NS_ERROR_ILLEGAL_VALUE; } - alertUser(final.get()); - return NS_OK; + NS_ASSERTION(0,"Bogus return value, this should never happen"); + return NS_ERROR_FAILURE; } diff --git a/security/manager/ssl/src/nsCrypto.h b/security/manager/ssl/src/nsCrypto.h index 9520ca10..cd003421 100644 --- a/security/manager/ssl/src/nsCrypto.h +++ b/security/manager/ssl/src/nsCrypto.h @@ -41,7 +41,7 @@ #include "nsCOMPtr.h" #include "nsIDOMCRMFObject.h" #include "nsIDOMCrypto.h" -#include "nsIDOMPkcs11.h" +#include "nsIPKCS11.h" #include "nsIRunnable.h" #include "nsString.h" #include "nsNSSEvent.h" @@ -97,14 +97,14 @@ private: PRBool mEnableSmartCardEvents; }; -class nsPkcs11 : public nsIDOMPkcs11 +class nsPkcs11 : public nsIPKCS11 { public: nsPkcs11(); virtual ~nsPkcs11(); NS_DECL_ISUPPORTS - NS_DECL_NSIDOMPKCS11 + NS_DECL_NSIPKCS11 }; diff --git a/security/manager/ssl/src/nsNSSCallbacks.cpp b/security/manager/ssl/src/nsNSSCallbacks.cpp index 22c4a5eb..6750a9b2 100644 --- a/security/manager/ssl/src/nsNSSCallbacks.cpp +++ b/security/manager/ssl/src/nsNSSCallbacks.cpp @@ -66,6 +66,7 @@ #include "ssl.h" #include "cert.h" #include "ocsp.h" +#include "secerr.h" static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); @@ -875,21 +876,136 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) { PR_Free(signer); } +struct nsSerialBinaryBlacklistEntry +{ + unsigned int len; + const char *binary_serial; +}; + +// bug 642395 +static struct nsSerialBinaryBlacklistEntry myUTNBlacklistEntries[] = { + { 17, "\x00\x92\x39\xd5\x34\x8f\x40\xd1\x69\x5a\x74\x54\x70\xe1\xf2\x3f\x43" }, + { 17, "\x00\xd8\xf3\x5f\x4e\xb7\x87\x2b\x2d\xab\x06\x92\xe3\x15\x38\x2f\xb0" }, + { 16, "\x72\x03\x21\x05\xc5\x0c\x08\x57\x3d\x8e\xa5\x30\x4e\xfe\xe8\xb0" }, + { 17, "\x00\xb0\xb7\x13\x3e\xd0\x96\xf9\xb5\x6f\xae\x91\xc8\x74\xbd\x3a\xc0" }, + { 16, "\x39\x2a\x43\x4f\x0e\x07\xdf\x1f\x8a\xa3\x05\xde\x34\xe0\xc2\x29" }, + { 16, "\x3e\x75\xce\xd4\x6b\x69\x30\x21\x21\x88\x30\xae\x86\xa8\x2a\x71" }, + { 17, "\x00\xe9\x02\x8b\x95\x78\xe4\x15\xdc\x1a\x71\x0a\x2b\x88\x15\x44\x47" }, + { 17, "\x00\xd7\x55\x8f\xda\xf5\xf1\x10\x5b\xb2\x13\x28\x2b\x70\x77\x29\xa3" }, + { 16, "\x04\x7e\xcb\xe9\xfc\xa5\x5f\x7b\xd0\x9e\xae\x36\xe1\x0c\xae\x1e" }, + { 17, "\x00\xf5\xc8\x6a\xf3\x61\x62\xf1\x3a\x64\xf5\x4f\x6d\xc9\x58\x7c\x06" }, + { 0, 0 } // end marker +}; + +// Bug 682927: Do not trust any DigiNotar-issued certificates. +// We do this check after normal certificate validation because we do not +// want to override a "revoked" OCSP response. +PRErrorCode +PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert, + CERTCertList * serverCertChain) +{ + PRBool isDigiNotarIssuedCert = PR_FALSE; + + for (CERTCertListNode *node = CERT_LIST_HEAD(serverCertChain); + !CERT_LIST_END(node, serverCertChain); + node = CERT_LIST_NEXT(node)) { + if (!node->cert->issuerName) + continue; + + if (strstr(node->cert->issuerName, "CN=DigiNotar")) { + isDigiNotarIssuedCert = PR_TRUE; + // Do not let the user override the error if the cert was + // chained from the "DigiNotar Root CA" cert and the cert was issued + // within the time window in which we think the mis-issuance(s) occurred. + if (strstr(node->cert->issuerName, "CN=DigiNotar Root CA")) { + PRTime cutoff = 0, notBefore = 0, notAfter = 0; + PRStatus status = PR_ParseTimeString("01-JUL-2011 00:00", PR_TRUE, &cutoff); + NS_ASSERTION(status == PR_SUCCESS, "PR_ParseTimeString failed"); + if (status != PR_SUCCESS || + CERT_GetCertTimes(serverCert, ¬Before, ¬After) != SECSuccess || + notBefore >= cutoff) { + return SEC_ERROR_REVOKED_CERTIFICATE; + } + } + } + } + + if (isDigiNotarIssuedCert) + return SEC_ERROR_UNTRUSTED_ISSUER; // user can override this + else + return 0; // No DigiNotor cert => carry on as normal +} + SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd, PRBool checksig, PRBool isServer) { nsNSSShutDownPreventionLock locker; + CERTCertificate *serverCert = SSL_PeerCertificate(fd); + if (serverCert && + serverCert->serialNumber.data && + serverCert->issuerName && + !strcmp(serverCert->issuerName, + "CN=UTN-USERFirst-Hardware,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US")) { + + unsigned char *server_cert_comparison_start = (unsigned char*)serverCert->serialNumber.data; + unsigned int server_cert_comparison_len = serverCert->serialNumber.len; + + while (server_cert_comparison_len) { + if (*server_cert_comparison_start != 0) + break; + + ++server_cert_comparison_start; + --server_cert_comparison_len; + } + + nsSerialBinaryBlacklistEntry *walk = myUTNBlacklistEntries; + for ( ; walk && walk->len; ++walk) { + + unsigned char *locked_cert_comparison_start = (unsigned char*)walk->binary_serial; + unsigned int locked_cert_comparison_len = walk->len; + + while (locked_cert_comparison_len) { + if (*locked_cert_comparison_start != 0) + break; + + ++locked_cert_comparison_start; + --locked_cert_comparison_len; + } + + if (server_cert_comparison_len == locked_cert_comparison_len && + !memcmp(server_cert_comparison_start, locked_cert_comparison_start, locked_cert_comparison_len)) { + PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0); + return SECFailure; + } + } + } + // first the default action SECStatus rv = SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer); // We want to remember the CA certs in the temp db, so that the application can find the // complete chain at any time it might need it. // But we keep only those CA certs in the temp db, that we didn't already know. + + CERTCertList *certList = nsnull; + if (rv == SECSuccess) { + certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA); + if (!certList) { + rv = SECFailure; + } else { + PRErrorCode blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(serverCert, + certList); + if (blacklistErrorCode != 0) { + nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret; + infoObject->SetCertIssuerBlacklisted(); + PORT_SetError(blacklistErrorCode); + rv = SECFailure; + } + } + } if (SECSuccess == rv) { - CERTCertificate *serverCert = SSL_PeerCertificate(fd); if (serverCert) { - CERTCertList *certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA); nsCOMPtr nssComponent; @@ -926,7 +1042,9 @@ SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd, } } - CERT_DestroyCertList(certList); + if(certList) { + CERT_DestroyCertList(certList); + } CERT_DestroyCertificate(serverCert); } } diff --git a/security/manager/ssl/src/nsNSSCallbacks.h b/security/manager/ssl/src/nsNSSCallbacks.h index 2c98dd2a..9da214a9 100644 --- a/security/manager/ssl/src/nsNSSCallbacks.h +++ b/security/manager/ssl/src/nsNSSCallbacks.h @@ -235,7 +235,7 @@ public: void unregisterHttpClient(); }; +PRErrorCode PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert, + CERTCertList * serverCertChain); + #endif // _NSNSSCALLBACKS_H_ - - - diff --git a/security/manager/ssl/src/nsNSSIOLayer.cpp b/security/manager/ssl/src/nsNSSIOLayer.cpp index b5384546..d74165f7 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -194,7 +194,8 @@ nsNSSSocketInfo::nsNSSSocketInfo() mBadCertUIStatus(bcuis_not_shown), mHandshakeStartTime(0), mPort(0), - mCAChain(nsnull) + mCAChain(nsnull), + mIsCertIssuerBlacklisted(PR_FALSE) { mThreadData = new nsSSLSocketThreadData; } @@ -2658,6 +2659,10 @@ done: static SECStatus nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket) { + // cert was revoked, don't do anything else + if (PR_GetError() == SEC_ERROR_REVOKED_CERTIFICATE) + return SECFailure; + nsNSSShutDownPreventionLock locker; SECStatus rv = SECFailure; int error; @@ -2665,6 +2670,13 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket) CERTCertificate *peerCert; nsNSSCertificate *nssCert; + if (infoObject->IsCertIssuerBlacklisted()) { + error = SEC_ERROR_UNTRUSTED_CERT; + } + else { + error = PR_GetError(); + } + error = PR_GetError(); peerCert = SSL_PeerCertificate(sslSocket); nssCert = new nsNSSCertificate(peerCert); diff --git a/security/manager/ssl/src/nsNSSIOLayer.h b/security/manager/ssl/src/nsNSSIOLayer.h index d6f7dc19..2975f247 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.h +++ b/security/manager/ssl/src/nsNSSIOLayer.h @@ -183,6 +183,12 @@ public: PRStatus CloseSocketAndDestroy(); + PRBool IsCertIssuerBlacklisted() const { + return mIsCertIssuerBlacklisted; + } + void SetCertIssuerBlacklisted() { + mIsCertIssuerBlacklisted = PR_TRUE; + } protected: nsCOMPtr mCallbacks; PRFileDesc* mFd; @@ -203,6 +209,7 @@ protected: PRInt32 mPort; nsXPIDLCString mHostName; CERTCertList *mCAChain; + PRErrorCode mIsCertIssuerBlacklisted; /* SSL Status */ nsCOMPtr mSSLStatus; diff --git a/security/nss/lib/certdb/certdb.c b/security/nss/lib/certdb/certdb.c index 54b6420b..aba2481f 100644 --- a/security/nss/lib/certdb/certdb.c +++ b/security/nss/lib/certdb/certdb.c @@ -1415,6 +1415,15 @@ sec_lower_string(char *s) return; } +static PRBool +cert_IsIPAddr(const char *hn) +{ + PRBool isIPaddr = PR_FALSE; + PRNetAddr netAddr; + isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr)); + return isIPaddr; +} + /* ** Add a domain name to the list of names that the user has explicitly ** allowed (despite cert name mismatches) for use with a server cert. @@ -1888,7 +1897,17 @@ CERT_VerifyCertName(CERTCertificate *cert, const char *hn) cn = CERT_GetCommonName(&cert->subject); } if ( cn ) { - rv = cert_TestHostName(cn, hn); + PRBool isIPaddr = cert_IsIPAddr(hn); + if (isIPaddr) { + if (PORT_Strcasecmp(hn, cn) == 0) { + rv = SECSuccess; + } else { + PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); + rv = SECFailure; + } + } else { + rv = cert_TestHostName(cn, hn); + } PORT_Free(cn); } else PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c index 963b985d..2a341307 100644 --- a/security/nss/lib/cryptohi/seckey.c +++ b/security/nss/lib/cryptohi/seckey.c @@ -227,7 +227,17 @@ SECKEYPrivateKey * SECKEY_CreateDHPrivateKey(SECKEYDHParams *param, SECKEYPublicKey **pubk, void *cx) { SECKEYPrivateKey *privk; - PK11SlotInfo *slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,cx); + PK11SlotInfo *slot; + + if (!param || !param->base.data || !param->prime.data || + param->prime.len < 512/8 || param->base.len == 0 || + param->base.len > param->prime.len + 1 || + (param->base.len == 1 && param->base.data[0] == 0)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,cx); if (!slot) { return NULL; } @@ -1460,16 +1470,20 @@ SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk) /* interpret modulus length as key strength... in * fortezza that's the public key length */ - + if (!pubk) + goto loser; switch (pubk->keyType) { case rsaKey: + if (!pubk->u.rsa.modulus.data) break; b0 = pubk->u.rsa.modulus.data[0]; return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1; case dsaKey: + if (!pubk->u.dsa.publicValue.data) break; b0 = pubk->u.dsa.publicValue.data[0]; return b0 ? pubk->u.dsa.publicValue.len : pubk->u.dsa.publicValue.len - 1; case dhKey: + if (!pubk->u.dh.publicValue.data) break; b0 = pubk->u.dh.publicValue.data[0]; return b0 ? pubk->u.dh.publicValue.len : pubk->u.dh.publicValue.len - 1; @@ -1482,6 +1496,7 @@ SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk) default: break; } +loser: PORT_SetError(SEC_ERROR_INVALID_KEY); return 0; } diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 7f332e9e..76ad8a29 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -4985,14 +4985,22 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (rv != SECSuccess) { goto loser; /* malformed. */ } + if (dh_p.len < 512/8) + goto alert_loser; rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } + if (dh_g.len == 0 || dh_g.len > dh_p.len + 1 || + (dh_g.len == 1 && dh_g.data[0] == 0)) + goto alert_loser; rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } + if (dh_Ys.len == 0 || dh_Ys.len > dh_p.len + 1 || + (dh_Ys.len == 1 && dh_Ys.data[0] == 0)) + goto alert_loser; rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ diff --git a/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp b/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp index d4127f37..ec7cb244 100644 --- a/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp +++ b/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp @@ -995,6 +995,13 @@ nsAutoCompleteController::StartSearch() ++searchesFailed; --mSearchesOngoing; } + // nsIAutoCompleteSearch::StartSearch might cause us to be detached from + // our input field, so it's not safe to assume that it's safe to iterate + // over the next iteration. + if (!mInput) { + // The search operation has been finished. + return NS_OK; + } } if (searchesFailed == count) { diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index a68a96c5..81863df8 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -1370,7 +1370,7 @@ XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult) if (NS_FAILED(rv)) return rv; -#elif +#else #error Oops, you need platform-specific code here #endif diff --git a/uriloader/base/nsURILoader.cpp b/uriloader/base/nsURILoader.cpp index d87255d5..1f8d957d 100644 --- a/uriloader/base/nsURILoader.cpp +++ b/uriloader/base/nsURILoader.cpp @@ -64,7 +64,7 @@ #include "nsXPIDLString.h" #include "nsString.h" - +#include "nsNetUtil.h" #include "nsIDOMWindowInternal.h" #include "nsReadableUtils.h" #include "nsDOMError.h" @@ -446,6 +446,9 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports * if (multipartChannel) { rv = multipartChannel->GetContentDisposition(disposition); + } else { + // Soon-to-be common way to get Disposition: right now only JARChannel + rv = NS_GetContentDisposition(request, disposition); } } diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 2cc165b7..52d2b331 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -2158,6 +2158,19 @@ nsresult nsExternalAppHandler::ExecuteDesiredAction() if (NS_SUCCEEDED(rv)) rv = OpenWithApplication(); } + else + { + // Cancel the download and report an error. We do not want to end up in + // a state where it appears that we have a normal download that is + // pointing to a file that we did not actually create. + nsAutoString path; + mTempFile->GetPath(path); + SendStatusChange(kWriteError, rv, nsnull, path); + Cancel(rv); + + // We still need to notify if we have a progress listener, so we cannot + // return at this point. + } } else // Various unknown actions go here too { diff --git a/view/src/nsScrollPortView.cpp b/view/src/nsScrollPortView.cpp index b3239b97..6b41cd6b 100644 --- a/view/src/nsScrollPortView.cpp +++ b/view/src/nsScrollPortView.cpp @@ -756,10 +756,13 @@ nsScrollPortView::IncrementalScroll() return; } + nsWeakView thisView = this; if (mSmoothScroll->mFrameIndex < SMOOTH_SCROLL_FRAMES) { ScrollToImpl(mOffsetX + mSmoothScroll->mVelocities[mSmoothScroll->mFrameIndex*2], mOffsetY + mSmoothScroll->mVelocities[mSmoothScroll->mFrameIndex*2 + 1], 0); + if (!thisView.IsAlive()) + return; mSmoothScroll->mFrameIndex++; } else { delete mSmoothScroll; diff --git a/view/src/nsView.cpp b/view/src/nsView.cpp index bee53429..68f03344 100644 --- a/view/src/nsView.cpp +++ b/view/src/nsView.cpp @@ -168,7 +168,8 @@ nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent) if (view) { - view->GetViewManager()->DispatchEvent(aEvent, &result); + nsCOMPtr vm = view->GetViewManager(); + vm->DispatchEvent(aEvent, &result); } return result; diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index b0d0f85d..fd54731c 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -1637,6 +1637,8 @@ NS_IMETHODIMP nsViewManager::Composite() NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags) { + NS_PRECONDITION(nsnull != aView, "null view"); + // Mark the entire view as damaged nsView* view = NS_STATIC_CAST(nsView*, aView); @@ -1998,7 +2000,9 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS vm->mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE); // Paint later. - vm->UpdateView(vm->mRootView, NS_VMREFRESH_NO_SYNC); + if (vm->mRootView) { + vm->UpdateView(vm->mRootView, NS_VMREFRESH_NO_SYNC); + } didResize = PR_TRUE; } } diff --git a/xpcom/ds/nsCOMArray.cpp b/xpcom/ds/nsCOMArray.cpp index fa070842..13673de1 100644 --- a/xpcom/ds/nsCOMArray.cpp +++ b/xpcom/ds/nsCOMArray.cpp @@ -55,11 +55,7 @@ nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) nsCOMArray_base::~nsCOMArray_base() { - PRInt32 count = Count(), i; - for (i = 0; i < count; ++i) { - nsISupports* obj = ObjectAt(i); - NS_IF_RELEASE(obj); - } + Clear(); } PRInt32 @@ -136,9 +132,10 @@ nsCOMArray_base::RemoveObjectAt(PRInt32 aIndex) { if (PRUint32(aIndex) < PRUint32(Count())) { nsISupports* element = ObjectAt(aIndex); - NS_IF_RELEASE(element); - return mArray.RemoveElementAt(aIndex); + PRBool result = mArray.RemoveElementAt(aIndex); + NS_IF_RELEASE(element); + return result; } return PR_FALSE; @@ -156,7 +153,9 @@ ReleaseObjects(void* aElement, void*) void nsCOMArray_base::Clear() { - mArray.EnumerateForwards(ReleaseObjects, nsnull); - mArray.Clear(); + nsAutoVoidArray objects; + objects = mArray; + mArray.Clear(); + objects.EnumerateForwards(ReleaseObjects, nsnull); } diff --git a/xpcom/ds/nsVoidArray.h b/xpcom/ds/nsVoidArray.h index 90a6260c..12f16efd 100644 --- a/xpcom/ds/nsVoidArray.h +++ b/xpcom/ds/nsVoidArray.h @@ -184,7 +184,13 @@ public: virtual PRBool SizeTo(PRInt32 aMin); virtual void Compact(); - + + nsAutoVoidArray& operator=(const nsVoidArray& other) + { + nsVoidArray::operator=(other); + return *this; + } + protected: // The internal storage enum { kAutoBufSize = 8 }; diff --git a/xpcom/glue/nsCOMPtr.h b/xpcom/glue/nsCOMPtr.h index 5d1c8362..4a8d26b6 100644 --- a/xpcom/glue/nsCOMPtr.h +++ b/xpcom/glue/nsCOMPtr.h @@ -818,6 +818,26 @@ class nsCOMPtr // Other pointer operators + already_AddRefed + forget() + // return the value of mRawPtr and null out mRawPtr. Useful for + // already_AddRefed return values. + { + T* temp = 0; + swap(temp); + return temp; + } + + void + forget( T** rhs ) + // Set the target of rhs to the value of mRawPtr and null out mRawPtr. + // Useful to avoid unnecessary AddRef/Release pairs with "out" + // parameters. + { + NS_ASSERTION(rhs, "Null pointer passed to forget!"); + *rhs = 0; + swap(*rhs); + } nsDerivedSafe* get() const @@ -1125,6 +1145,26 @@ class nsCOMPtr // Other pointer operators + already_AddRefed + forget() + // return the value of mRawPtr and null out mRawPtr. Useful for + // already_AddRefed return values. + { + nsISupports* temp = 0; + swap(temp); + return temp; + } + + void + forget( nsISupports** rhs ) + // Set the target of rhs to the value of mRawPtr and null out mRawPtr. + // Useful to avoid unnecessary AddRef/Release pairs with "out" + // parameters. + { + NS_ASSERTION(rhs, "Null pointer passed to forget!"); + *rhs = 0; + swap(*rhs); + } nsDerivedSafe* get() const diff --git a/xpcom/glue/nsISupportsImpl.h b/xpcom/glue/nsISupportsImpl.h index 9085a148..a20b3c1f 100644 --- a/xpcom/glue/nsISupportsImpl.h +++ b/xpcom/glue/nsISupportsImpl.h @@ -576,6 +576,17 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ NS_IMPL_QUERY_BODY(i6) \ NS_IMPL_QUERY_TAIL_INHERITING(Super) \ +#define NS_IMPL_QUERY_INTERFACE_INHERITED7(Class,Super,i1,i2,i3,i4,i5,i6,i7) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_BODY(i4) \ + NS_IMPL_QUERY_BODY(i5) \ + NS_IMPL_QUERY_BODY(i6) \ + NS_IMPL_QUERY_BODY(i7) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + /** * Convenience macros for implementing all nsISupports methods for * a simple class. @@ -684,6 +695,11 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ NS_IMPL_ADDREF_INHERITED(Class, Super) \ NS_IMPL_RELEASE_INHERITED(Class, Super) \ +#define NS_IMPL_ISUPPORTS_INHERITED7(Class, Super, i1, i2, i3, i4, i5, i6, i7) \ + NS_IMPL_QUERY_INTERFACE_INHERITED7(Class, Super, i1, i2, i3, i4, i5, i6, i7) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + /////////////////////////////////////////////////////////////////////////////// /** * diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index 80100a46..da2b8feb 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -1360,6 +1360,45 @@ nsLocalFile::IsExecutable(PRBool *_retval) return NS_OK; } + // Check extension (bug 663899). On certain platforms, the file + // extension may cause the OS to treat it as executable regardless of + // the execute bit, such as .jar on Mac OS X. We borrow the code from + // nsLocalFileWin, slightly modified. + + // Don't be fooled by symlinks. + PRBool symLink; + nsresult rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; + + nsAutoString path; + if (symLink) + GetTarget(path); + else + GetPath(path); + + PRInt32 dotIdx = path.RFindChar(PRUnichar('.')); + if (dotIdx != kNotFound) { + // Convert extension to lower case. + PRUnichar *p = path.BeginWriting(); + for(p += dotIdx + 1; *p; p++) + *p += (*p >= L'A' && *p <= L'Z') ? 'a' - 'A' : 0; + + // Search for any of the set of executable extensions. + static const char * const executableExts[] = { + "air", // Adobe AIR installer + "jar"}; // java application bundle + nsDependentSubstring ext = Substring(path, dotIdx + 1); + for (int i = 0; i < NS_ARRAY_LENGTH(executableExts); i++) { + if (ext.EqualsASCII(executableExts[i])) { + // Found a match. Set result and quit. + *_retval = PR_TRUE; + return NS_OK; + } + } + } + + // Failing that, check the execute bit. *_retval = (access(mPath.get(), X_OK) == 0); if (*_retval || errno == EACCES) return NS_OK; diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp index 154fbcee..a8c13245 100644 --- a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp +++ b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp @@ -213,6 +213,7 @@ XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, PRUint32 overflow = invoke_count_words (paramCount, params); PRUint32 result; + register PRUint32 reg_paramCount __asm ("4") = paramCount; __asm__ __volatile__ ( "lr 7,15\n\t" @@ -240,14 +241,15 @@ XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, "la 15,32(7)\n\t" "lr %0,2\n\t" - : "=r" (result) - : "r" (paramCount), - "r" (params), + : "=r" (result), + "=r" (reg_paramCount) + : "r" (params), "r" (overflow), "a" (invoke_copy_to_stack), "a" (that), - "a" (method) - : "2", "3", "4", "5", "6", "7", "14", "cc", "memory", "%f0", "%f2" + "a" (method), + "1" (reg_paramCount) + : "2", "3", "5", "6", "7", "14", "cc", "memory", "%f0", "%f2" ); return result; diff --git a/xpcom/string/src/nsPrintfCString.cpp b/xpcom/string/src/nsPrintfCString.cpp index 8bb06da6..5c743611 100644 --- a/xpcom/string/src/nsPrintfCString.cpp +++ b/xpcom/string/src/nsPrintfCString.cpp @@ -71,7 +71,8 @@ nsPrintfCString::nsPrintfCString( size_type n, const char_type* format, ... ) if ( n > logical_capacity ) { SetCapacity(n); - if (Capacity() < n) + size_type capacity = Capacity(); + if (capacity == size_type(-1) || capacity < n) return; // out of memory !! logical_capacity = n; } diff --git a/xpcom/string/src/nsSubstring.cpp b/xpcom/string/src/nsSubstring.cpp index 8e47a2bb..ad2d5fe6 100644 --- a/xpcom/string/src/nsSubstring.cpp +++ b/xpcom/string/src/nsSubstring.cpp @@ -199,6 +199,9 @@ nsStringBuffer::Alloc(size_t size) STRING_STAT_INCREMENT(Alloc); NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); + NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(PRUint32(-1)) && + sizeof(nsStringBuffer) + size > size, + "mStorageSize will truncate"); nsStringBuffer *hdr = (nsStringBuffer *) malloc(sizeof(nsStringBuffer) + size); @@ -216,6 +219,9 @@ nsStringBuffer::Realloc(nsStringBuffer* hdr, size_t size) STRING_STAT_INCREMENT(Realloc); NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); + NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(PRUint32(-1)) && + sizeof(nsStringBuffer) + size > size, + "mStorageSize will truncate"); // no point in trying to save ourselves if we hit this assertion NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string"); diff --git a/xpcom/string/src/nsTSubstring.cpp b/xpcom/string/src/nsTSubstring.cpp index 1eb89b2d..fcbe0837 100644 --- a/xpcom/string/src/nsTSubstring.cpp +++ b/xpcom/string/src/nsTSubstring.cpp @@ -36,6 +36,7 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nspr.h" /** * helper function for down-casting a nsTSubstring to a nsTFixedString. @@ -63,10 +64,13 @@ nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint3 size_type curCapacity = Capacity(); - // If |capacity > size_type(-1)/2|, then our doubling algorithm may not be + // If |capacity > kMaxCapacity|, then our doubling algorithm may not be // able to allocate it. Just bail out in cases like that. We don't want // to be allocating 2GB+ strings anyway. - if (capacity > size_type(-1)/2) { + PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0); + const size_type kMaxCapacity = + (size_type(-1)/2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2; + if (capacity > kMaxCapacity) { // Also assert for |capacity| equal to |size_type(-1)|, since we use that value to // flag immutability. NS_ASSERTION(capacity != size_type(-1), "Bogus capacity"); @@ -82,15 +86,15 @@ nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint3 if (capacity <= curCapacity) return PR_TRUE; - if (curCapacity > 0) - { - // use doubling algorithm when forced to increase available - // capacity. - PRUint32 temp = curCapacity; - while (temp < capacity) - temp <<= 1; - capacity = temp; - } + if (curCapacity > 0) { + // Use doubling algorithm when forced to increase available capacity. + size_type temp = curCapacity; + while (temp < capacity) + temp <<= 1; + NS_ASSERTION(NS_MIN(temp, kMaxCapacity) >= capacity, + "should have hit the early return at the top"); + capacity = NS_MIN(temp, kMaxCapacity); + } } // @@ -548,7 +552,8 @@ nsTSubstring_CharT::SetLength( size_type length ) // out. We should improve that. For now we just verify that the capacity // changed as expected as a means of error checking. - if (Capacity() >= length) + size_type capacity = Capacity(); + if (capacity != size_type(-1) && capacity >= length) mLength = length; } diff --git a/xpfe/components/autocomplete/public/nsILDAPAutoCompleteSession.idl b/xpfe/components/autocomplete/public/nsILDAPAutoCompleteSession.idl index 9f08e914..b5da212c 100644 --- a/xpfe/components/autocomplete/public/nsILDAPAutoCompleteSession.idl +++ b/xpfe/components/autocomplete/public/nsILDAPAutoCompleteSession.idl @@ -49,6 +49,9 @@ interface nsIMutableArray; /** * Extends nsIAutoCompleteSession to have various LDAP-specific parameters. * and output format. + * + * Note: the formatter attribute should be set prior to starting the LDAP + * lookup via nsIAutoCompleteSession::OnStartLookup. */ [scriptable, uuid(e7f26534-f96c-4c87-803c-30cdf0bc2973)] interface nsILDAPAutoCompleteSession : nsIAutoCompleteSession { @@ -115,7 +118,8 @@ interface nsILDAPAutoCompleteSession : nsIAutoCompleteSession { /** * Callback used to format an individual LDAP message into an - * nsIAutoCompleteItem. + * nsIAutoCompleteItem. This is required to be set before calling + * OnStartLookup. */ attribute nsILDAPAutoCompFormatter formatter; diff --git a/xpfe/components/autocomplete/src/nsLDAPAutoCompleteSession.cpp b/xpfe/components/autocomplete/src/nsLDAPAutoCompleteSession.cpp index 7dd01f5e..f567e8ad 100644 --- a/xpfe/components/autocomplete/src/nsLDAPAutoCompleteSession.cpp +++ b/xpfe/components/autocomplete/src/nsLDAPAutoCompleteSession.cpp @@ -105,6 +105,13 @@ nsLDAPAutoCompleteSession::OnStartLookup(const PRUnichar *searchString, { nsresult rv; // hold return values from XPCOM calls + NS_ENSURE_ARG_POINTER(listener); + if (!mFormatter) + { + NS_WARNING("mFormatter should not be null for nsLDAPAutoCompleteSession::OnStartLookup"); + return NS_ERROR_NOT_INITIALIZED; + } + #ifdef PR_LOGGING // initialize logging, if it hasn't been already // @@ -118,14 +125,8 @@ nsLDAPAutoCompleteSession::OnStartLookup(const PRUnichar *searchString, PR_LOG(sLDAPAutoCompleteLogModule, PR_LOG_DEBUG, ("nsLDAPAutoCompleteSession::OnStartLookup entered\n")); - - if (!listener) { - NS_ERROR("nsLDAPAutoCompleteSession::OnStartLookup(): NULL listener" - "passed in"); - return NS_ERROR_NULL_POINTER; - } else { - mListener = listener; // save it for later callbacks - } + + mListener = listener; // ignore the empty string, strings with @ in them, and strings // that are too short @@ -156,9 +157,6 @@ nsLDAPAutoCompleteSession::OnStartLookup(const PRUnichar *searchString, return NS_ERROR_FAILURE; } - NS_ASSERTION(mFormatter, "nsLDAPAutoCompleteSession::OnStartLookup(): " - "formatter attribute has not been set"); - // see if this is a narrow search that we could potentially do locally // if (previousSearchResult) { diff --git a/xpfe/components/shistory/src/nsSHTransaction.cpp b/xpfe/components/shistory/src/nsSHTransaction.cpp index 7df15527..2050349a 100644 --- a/xpfe/components/shistory/src/nsSHTransaction.cpp +++ b/xpfe/components/shistory/src/nsSHTransaction.cpp @@ -111,10 +111,12 @@ nsSHTransaction::GetNext(nsISHTransaction * * aResult) NS_IMETHODIMP nsSHTransaction::SetNext(nsISHTransaction * aNext) { - NS_ENSURE_SUCCESS(aNext->SetPrev(this), NS_ERROR_FAILURE); + if (aNext) { + NS_ENSURE_SUCCESS(aNext->SetPrev(this), NS_ERROR_FAILURE); + } - mNext = aNext; - return NS_OK; + mNext = aNext; + return NS_OK; } NS_IMETHODIMP diff --git a/xpfe/components/shistory/src/nsSHistory.cpp b/xpfe/components/shistory/src/nsSHistory.cpp index 5bae5bba..a3c56509 100644 --- a/xpfe/components/shistory/src/nsSHistory.cpp +++ b/xpfe/components/shistory/src/nsSHistory.cpp @@ -561,9 +561,14 @@ nsSHistory::PurgeHistory(PRInt32 aEntries) PRInt32 cnt = 0; while (cnt < aEntries) { nsCOMPtr nextTxn; - if (mListRoot) + if (mListRoot) { mListRoot->GetNext(getter_AddRefs(nextTxn)); + mListRoot->SetNext(nsnull); + } mListRoot = nextTxn; + if (mListRoot) { + mListRoot->SetPrev(nsnull); + } cnt++; } mLength -= cnt;