Impressum Exceptions.cpp
Interaktion und PortierbarkeitC
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Throw the given exception value if it's safe. If it's not safe, then // synthesize and throw a new exception value for NS_ERROR_UNEXPECTED. The // incoming value must be in the compartment of aCx. This function guarantees // that an exception is pending on aCx when it returns. staticvoid ThrowExceptionValueIfSafe(JSContext* aCx,
JS::Handle<JS::Value> exnVal,
Exception* aOriginalException) {
MOZ_ASSERT(aOriginalException);
if (!exnVal.isObject()) {
JS_SetPendingException(aCx, exnVal); return;
}
JS::Rooted<JSObject*> exnObj(aCx, &exnVal.toObject());
MOZ_ASSERT(js::IsObjectInContextCompartment(exnObj, aCx), "exnObj needs to be in the right compartment for the " "CheckedUnwrapDynamic thing to make sense");
// aCx's current Realm is where we're throwing, so using it in the // CheckedUnwrapDynamic check makes sense. if (js::CheckedUnwrapDynamic(exnObj, aCx)) { // This is an object we're allowed to work with, so just go ahead and throw // it.
JS_SetPendingException(aCx, exnVal); return;
}
// We could probably Throw(aCx, NS_ERROR_UNEXPECTED) here, and it would do the // right thing due to there not being an existing exception on the runtime at // this point, but it's clearer to explicitly do the thing we want done. This // is also why we don't just call ThrowExceptionObject on the Exception we // create: it would do the right thing, but that fact is not obvious.
RefPtr<Exception> syntheticException = CreateException(NS_ERROR_UNEXPECTED);
JS::Rooted<JS::Value> syntheticVal(aCx); if (!GetOrCreateDOMReflector(aCx, syntheticException, &syntheticVal)) { return;
}
MOZ_ASSERT(
syntheticVal.isObject() && !js::IsWrapper(&syntheticVal.toObject()), "Must have a reflector here, not a wrapper");
JS_SetPendingException(aCx, syntheticVal);
}
// If we stored the original thrown JS value in the exception // (see XPCConvert::ConstructException) and we are in a web context // (i.e., not chrome), rethrow the original value. This only applies to JS // implemented components so we only need to check for this on the main // thread. if (NS_IsMainThread() && !nsContentUtils::IsCallerChrome() &&
aException->StealJSVal(thrown.address())) { // Now check for the case when thrown is a number which matches // aException->GetResult(). This would indicate that what actually got // thrown was an nsresult value. In that situation, we should go back // through dom::Throw with that nsresult value, because it will make sure to // create the right sort of Exception or DOMException, with the right // global. if (thrown.isNumber()) {
nsresult exceptionResult = aException->GetResult(); if (double(exceptionResult) == thrown.toNumber()) { Throw(aCx, exceptionResult); return;
}
} if (!JS_WrapValue(aCx, &thrown)) { return;
}
ThrowExceptionValueIfSafe(aCx, thrown, aException); return;
}
if (!GetOrCreateDOMReflector(aCx, aException, &thrown)) { return;
}
boolThrow(JSContext* aCx, nsresult aRv, const nsACString& aMessage) { if (aRv == NS_ERROR_UNCATCHABLE_EXCEPTION) { // Nuke any existing exception on aCx, to make sure we're uncatchable.
JS_ClearPendingException(aCx); returnfalse;
}
if (JS_IsExceptionPending(aCx)) { // Don't clobber the existing exception. returnfalse;
}
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
RefPtr<Exception> existingException = context->GetPendingException(); // Make sure to clear the pending exception now. Either we're going to reuse // it (and we already grabbed it), or we plan to throw something else and this // pending exception is no longer relevant.
context->SetPendingException(nullptr);
// Ignore the pending exception if we have a non-default message passed in. if (aMessage.IsEmpty() && existingException) { if (aRv == existingException->GetResult()) { // Reuse the existing exception.
ThrowExceptionObject(aCx, existingException); returnfalse;
}
}
void ThrowAndReport(nsPIDOMWindowInner* aWindow, nsresult aRv) {
MOZ_ASSERT(aRv != NS_ERROR_UNCATCHABLE_EXCEPTION, "Doesn't make sense to report uncatchable exceptions!");
AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(aWindow))) { return;
}
Throw(jsapi.cx(), aRv);
}
already_AddRefed<Exception> CreateException(nsresult aRv, const nsACString& aMessage) { // Do we use DOM exceptions for this error code? switch (NS_ERROR_GET_MODULE(aRv)) { case NS_ERROR_MODULE_DOM: case NS_ERROR_MODULE_SVG: case NS_ERROR_MODULE_DOM_FILE: case NS_ERROR_MODULE_DOM_XPATH: case NS_ERROR_MODULE_DOM_INDEXEDDB: case NS_ERROR_MODULE_DOM_FILEHANDLE: case NS_ERROR_MODULE_DOM_ANIM: case NS_ERROR_MODULE_DOM_PUSH: case NS_ERROR_MODULE_DOM_MEDIA: if (aMessage.IsEmpty()) { return DOMException::Create(aRv);
} return DOMException::Create(aRv, aMessage); default: break;
}
// If not, use the default.
RefPtr<Exception> exception = new Exception(aMessage, aRv, ""_ns, nullptr, nullptr); return exception.forget();
}
already_AddRefed<nsIStackFrame> GetCurrentJSStack(int32_t aMaxDepth) { // is there a current context available?
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (!cx || !js::GetContextRealm(cx)) { return nullptr;
}
class JSStackFrame final : public nsIStackFrame, public xpc::JSStackFrameBase { public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(JSStackFrame)
NS_DECL_NSISTACKFRAME
// aStack must not be null. explicit JSStackFrame(JS::Handle<JSObject*> aStack);
private: virtual ~JSStackFrame();
void Clear() override { mStack = nullptr; }
// Remove this frame from the per-realm list of live frames, // and clear out the stack pointer. void UnregisterAndClear();
// Helper method to determine the JSPrincipals* to pass to JS SavedFrame APIs. // // @argument aStack the stack we're working with; must be non-null. // @argument [out] aCanCache whether we can use cached JSStackFrame values. static JSPrincipals* GetPrincipalsForStackGetter(JSContext* aCx,
JS::Handle<JSObject*> aStack, bool* aCanCache) {
MOZ_ASSERT(JS::IsUnwrappedSavedFrame(aStack));
// Fast path for when the principals are equal. This check is also necessary // for workers: no nsIPrincipal there so we can't use the code below. if (currentPrincipals == stackPrincipals) {
*aCanCache = true; return stackPrincipals;
}
MOZ_ASSERT(NS_IsMainThread());
if (nsJSPrincipals::get(currentPrincipals)
->Subsumes(nsJSPrincipals::get(stackPrincipals))) { // The current principals subsume the stack's principals. In this case use // the stack's principals: the idea is that this way devtools code that's // asking an exception object for a stack to display will end up with the // stack the web developer would see via doing .stack in a web page, with // Firefox implementation details excluded.
// Because we use the stack's principals and don't rely on the current // context realm, we can use cached values.
*aCanCache = true; return stackPrincipals;
}
// The stack was captured in more-privileged code, so use the less privileged // principals. Don't use cached values because we don't want these values to // depend on the current realm/principals.
*aCanCache = false; return currentPrincipals;
}
// Helper method to get the value of a stack property, if it's not already // cached. This will make sure we skip the cache if the property value depends // on the (current) context's realm/principals. // // @argument aStack the stack we're working with; must be non-null. // @argument aPropGetter the getter function to call. // @argument aIsCached whether we've cached this property's value before. // // @argument [out] aCanCache whether the value can get cached. // @argument [out] aUseCachedValue if true, just use the cached value. // @argument [out] aValue the value we got from the stack. template <typename ReturnType, typename GetterOutParamType> staticvoid GetValueIfNotCached(
JSContext* aCx, const JS::Heap<JSObject*>& aStack,
JS::SavedFrameResult (*aPropGetter)(JSContext*, JSPrincipals*,
JS::Handle<JSObject*>,
GetterOutParamType,
JS::SavedFrameSelfHosted), bool aIsCached, bool* aCanCache, bool* aUseCachedValue, ReturnType aValue) {
MOZ_ASSERT(aStack);
MOZ_ASSERT(JS::IsUnwrappedSavedFrame(aStack));
// Sadly we can't use GetValueIfNotCached here, because our getter // returns bool, not JS::SavedFrameResult. Maybe it's possible to // make the templates more complicated to deal, but in the meantime // let's just inline GetValueIfNotCached here.
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.18Bemerkung:
Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.