mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1475559 part 6 - Add principals argument to SavedFrame APIs and do frame filtering based on it. r=bz
This removes AutoMaybeEnterFrameRealm. Most places pass cx->realm->principals: it preserves behavior when the (possibly wrapped) SavedFrame and cx are same-compartment. The main exception is the JSStackFrame DOM bindings code where we have to be a bit smarter about which principals to use.
This commit is contained in:
parent
8c93c6e9e8
commit
30d5135f62
@ -52,16 +52,21 @@ DEF_TEST(DeserializedStackFrameUbiStackFrames, {
|
||||
JS::RootedObject savedFrame(cx);
|
||||
EXPECT_TRUE(ubiFrame.constructSavedFrameStack(cx, &savedFrame));
|
||||
|
||||
JSPrincipals* principals = JS::GetRealmPrincipals(js::GetContextRealm(cx));
|
||||
|
||||
uint32_t frameLine;
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameLine(cx, savedFrame, &frameLine));
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok,
|
||||
JS::GetSavedFrameLine(cx, principals, savedFrame, &frameLine));
|
||||
EXPECT_EQ(line, frameLine);
|
||||
|
||||
uint32_t frameColumn;
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameColumn(cx, savedFrame, &frameColumn));
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok,
|
||||
JS::GetSavedFrameColumn(cx, principals, savedFrame, &frameColumn));
|
||||
EXPECT_EQ(column, frameColumn);
|
||||
|
||||
JS::RootedObject parent(cx);
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameParent(cx, savedFrame, &parent));
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok,
|
||||
JS::GetSavedFrameParent(cx, principals, savedFrame, &parent));
|
||||
EXPECT_EQ(nullptr, parent);
|
||||
|
||||
ASSERT_EQ(NS_strlen(source), 21U);
|
||||
|
@ -732,9 +732,10 @@ ChromeUtils::CreateError(const GlobalObject& aGlobal, const nsAString& aMessage,
|
||||
stack = UncheckedUnwrap(aStack);
|
||||
ar.emplace(cx, stack);
|
||||
|
||||
if (JS::GetSavedFrameLine(cx, stack, &line) != JS::SavedFrameResult::Ok ||
|
||||
JS::GetSavedFrameColumn(cx, stack, &column) != JS::SavedFrameResult::Ok ||
|
||||
JS::GetSavedFrameSource(cx, stack, &fileName) != JS::SavedFrameResult::Ok) {
|
||||
JSPrincipals* principals = JS::GetRealmPrincipals(js::GetContextRealm(cx));
|
||||
if (JS::GetSavedFrameLine(cx, principals, stack, &line) != JS::SavedFrameResult::Ok ||
|
||||
JS::GetSavedFrameColumn(cx, principals, stack, &column) != JS::SavedFrameResult::Ok ||
|
||||
JS::GetSavedFrameSource(cx, principals, stack, &fileName) != JS::SavedFrameResult::Ok) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -287,9 +287,54 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSStackFrame)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// 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));
|
||||
|
||||
JSPrincipals* currentPrincipals =
|
||||
JS::GetRealmPrincipals(js::GetContextRealm(aCx));
|
||||
JSPrincipals* stackPrincipals =
|
||||
JS::GetRealmPrincipals(js::GetNonCCWObjectRealm(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 access is happening
|
||||
// over Xrays.
|
||||
// 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.
|
||||
@ -302,6 +347,7 @@ template<typename ReturnType, typename GetterOutParamType>
|
||||
static void
|
||||
GetValueIfNotCached(JSContext* aCx, const JS::Heap<JSObject*>& aStack,
|
||||
JS::SavedFrameResult (*aPropGetter)(JSContext*,
|
||||
JSPrincipals*,
|
||||
JS::Handle<JSObject*>,
|
||||
GetterOutParamType,
|
||||
JS::SavedFrameSelfHosted),
|
||||
@ -309,11 +355,11 @@ GetValueIfNotCached(JSContext* aCx, const JS::Heap<JSObject*>& aStack,
|
||||
ReturnType aValue)
|
||||
{
|
||||
MOZ_ASSERT(aStack);
|
||||
MOZ_ASSERT(JS::IsUnwrappedSavedFrame(aStack));
|
||||
|
||||
JS::Rooted<JSObject*> stack(aCx, aStack);
|
||||
// Allow caching if aCx and stack are same-compartment. Otherwise take the
|
||||
// slow path.
|
||||
*aCanCache = js::GetContextCompartment(aCx) == js::GetObjectCompartment(stack);
|
||||
|
||||
JSPrincipals* principals = GetPrincipalsForStackGetter(aCx, stack, aCanCache);
|
||||
if (*aCanCache && aIsCached) {
|
||||
*aUseCachedValue = true;
|
||||
return;
|
||||
@ -321,7 +367,8 @@ GetValueIfNotCached(JSContext* aCx, const JS::Heap<JSObject*>& aStack,
|
||||
|
||||
*aUseCachedValue = false;
|
||||
|
||||
aPropGetter(aCx, stack, aValue, JS::SavedFrameSelfHosted::Exclude);
|
||||
aPropGetter(aCx, principals, stack, aValue,
|
||||
JS::SavedFrameSelfHosted::Exclude);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JSStackFrame::GetFilenameXPCOM(JSContext* aCx, nsAString& aFilename)
|
||||
@ -613,19 +660,17 @@ JSStackFrame::GetFormattedStack(JSContext* aCx, nsAString& aStack)
|
||||
// make the templates more complicated to deal, but in the meantime
|
||||
// let's just inline GetValueIfNotCached here.
|
||||
|
||||
// Allow caching if aCx and stack are same-compartment. Otherwise take the
|
||||
// slow path.
|
||||
bool canCache =
|
||||
js::GetContextCompartment(aCx) == js::GetObjectCompartment(mStack);
|
||||
JS::Rooted<JSObject*> stack(aCx, mStack);
|
||||
|
||||
bool canCache;
|
||||
JSPrincipals* principals = GetPrincipalsForStackGetter(aCx, stack, &canCache);
|
||||
if (canCache && mFormattedStackInitialized) {
|
||||
aStack = mFormattedStack;
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> stack(aCx, mStack);
|
||||
|
||||
JS::Rooted<JSString*> formattedStack(aCx);
|
||||
if (!JS::BuildStackString(aCx, stack, &formattedStack)) {
|
||||
if (!JS::BuildStackString(aCx, principals, stack, &formattedStack)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
aStack.Truncate();
|
||||
return;
|
||||
|
@ -22,10 +22,10 @@ using namespace mozilla::dom;
|
||||
namespace {
|
||||
|
||||
static nsCString
|
||||
FormatStackString(JSContext* cx, JS::HandleObject aStack) {
|
||||
FormatStackString(JSContext* cx, JSPrincipals* aPrincipals, JS::HandleObject aStack)
|
||||
{
|
||||
JS::RootedString formattedStack(cx);
|
||||
|
||||
if (!JS::BuildStackString(cx, aStack, &formattedStack)) {
|
||||
if (!JS::BuildStackString(cx, aPrincipals, aStack, &formattedStack)) {
|
||||
return nsCString();
|
||||
}
|
||||
|
||||
@ -106,9 +106,12 @@ nsScriptErrorWithStack::ToString(nsACString& /*UTF8*/ aResult)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JSPrincipals* principals =
|
||||
JS::GetRealmPrincipals(js::GetNonCCWObjectRealm(mStackGlobal));
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::RootedObject stack(cx, mStack);
|
||||
nsCString stackString = FormatStackString(cx, stack);
|
||||
nsCString stackString = FormatStackString(cx, principals, stack);
|
||||
nsCString combined = message + NS_LITERAL_CSTRING("\n") + stackString;
|
||||
aResult.Assign(combined);
|
||||
|
||||
|
@ -27,37 +27,39 @@ BEGIN_TEST(testSavedStacks_ApiDefaultValues)
|
||||
{
|
||||
js::RootedSavedFrame savedFrame(cx, nullptr);
|
||||
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
|
||||
// Source
|
||||
JS::RootedString str(cx);
|
||||
JS::SavedFrameResult result = JS::GetSavedFrameSource(cx, savedFrame, &str);
|
||||
JS::SavedFrameResult result = JS::GetSavedFrameSource(cx, principals, savedFrame, &str);
|
||||
CHECK(result == JS::SavedFrameResult::AccessDenied);
|
||||
CHECK(str.get() == cx->runtime()->emptyString);
|
||||
|
||||
// Line
|
||||
uint32_t line = 123;
|
||||
result = JS::GetSavedFrameLine(cx, savedFrame, &line);
|
||||
result = JS::GetSavedFrameLine(cx, principals, savedFrame, &line);
|
||||
CHECK(result == JS::SavedFrameResult::AccessDenied);
|
||||
CHECK(line == 0);
|
||||
|
||||
// Column
|
||||
uint32_t column = 123;
|
||||
result = JS::GetSavedFrameColumn(cx, savedFrame, &column);
|
||||
result = JS::GetSavedFrameColumn(cx, principals, savedFrame, &column);
|
||||
CHECK(result == JS::SavedFrameResult::AccessDenied);
|
||||
CHECK(column == 0);
|
||||
|
||||
// Function display name
|
||||
result = JS::GetSavedFrameFunctionDisplayName(cx, savedFrame, &str);
|
||||
result = JS::GetSavedFrameFunctionDisplayName(cx, principals, savedFrame, &str);
|
||||
CHECK(result == JS::SavedFrameResult::AccessDenied);
|
||||
CHECK(str.get() == nullptr);
|
||||
|
||||
// Parent
|
||||
JS::RootedObject parent(cx);
|
||||
result = JS::GetSavedFrameParent(cx, savedFrame, &parent);
|
||||
result = JS::GetSavedFrameParent(cx, principals, savedFrame, &parent);
|
||||
CHECK(result == JS::SavedFrameResult::AccessDenied);
|
||||
CHECK(parent.get() == nullptr);
|
||||
|
||||
// Stack string
|
||||
CHECK(JS::BuildStackString(cx, savedFrame, &str));
|
||||
CHECK(JS::BuildStackString(cx, principals, savedFrame, &str));
|
||||
CHECK(str.get() == cx->runtime()->emptyString);
|
||||
|
||||
return true;
|
||||
@ -114,7 +116,8 @@ BEGIN_TEST(testSavedStacks_RangeBasedForLoops)
|
||||
auto CheckStacks = [&]() {
|
||||
for (auto& expectation : expectations) {
|
||||
JS::RootedString str(cx);
|
||||
CHECK(JS::BuildStackString(cx, savedFrame, &str, 0, expectation.format));
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
CHECK(JS::BuildStackString(cx, principals, savedFrame, &str, 0, expectation.format));
|
||||
JSLinearString* lin = str->ensureLinear(cx);
|
||||
CHECK(lin);
|
||||
CHECK(js::StringEqualsAscii(lin, expectation.expected));
|
||||
@ -225,9 +228,11 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames)
|
||||
JS::Rooted<js::SavedFrame*> selfHostedFrame(cx, savedFrame->getParent());
|
||||
CHECK(selfHostedFrame->isSelfHosted(cx));
|
||||
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
|
||||
// Source
|
||||
JS::RootedString str(cx);
|
||||
JS::SavedFrameResult result = JS::GetSavedFrameSource(cx, selfHostedFrame, &str,
|
||||
JS::SavedFrameResult result = JS::GetSavedFrameSource(cx, principals, selfHostedFrame, &str,
|
||||
JS::SavedFrameSelfHosted::Exclude);
|
||||
CHECK(result == JS::SavedFrameResult::Ok);
|
||||
JSLinearString* lin = str->ensureLinear(cx);
|
||||
@ -235,7 +240,8 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames)
|
||||
CHECK(js::StringEqualsAscii(lin, "filename.js"));
|
||||
|
||||
// Source, including self-hosted frames
|
||||
result = JS::GetSavedFrameSource(cx, selfHostedFrame, &str, JS::SavedFrameSelfHosted::Include);
|
||||
result = JS::GetSavedFrameSource(cx, principals, selfHostedFrame, &str,
|
||||
JS::SavedFrameSelfHosted::Include);
|
||||
CHECK(result == JS::SavedFrameResult::Ok);
|
||||
lin = str->ensureLinear(cx);
|
||||
CHECK(lin);
|
||||
@ -243,19 +249,20 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames)
|
||||
|
||||
// Line
|
||||
uint32_t line = 123;
|
||||
result = JS::GetSavedFrameLine(cx, selfHostedFrame, &line, JS::SavedFrameSelfHosted::Exclude);
|
||||
result = JS::GetSavedFrameLine(cx, principals, selfHostedFrame, &line,
|
||||
JS::SavedFrameSelfHosted::Exclude);
|
||||
CHECK(result == JS::SavedFrameResult::Ok);
|
||||
CHECK_EQUAL(line, 3U);
|
||||
|
||||
// Column
|
||||
uint32_t column = 123;
|
||||
result = JS::GetSavedFrameColumn(cx, selfHostedFrame, &column,
|
||||
result = JS::GetSavedFrameColumn(cx, principals, selfHostedFrame, &column,
|
||||
JS::SavedFrameSelfHosted::Exclude);
|
||||
CHECK(result == JS::SavedFrameResult::Ok);
|
||||
CHECK_EQUAL(column, 5U);
|
||||
|
||||
// Function display name
|
||||
result = JS::GetSavedFrameFunctionDisplayName(cx, selfHostedFrame, &str,
|
||||
result = JS::GetSavedFrameFunctionDisplayName(cx, principals, selfHostedFrame, &str,
|
||||
JS::SavedFrameSelfHosted::Exclude);
|
||||
CHECK(result == JS::SavedFrameResult::Ok);
|
||||
lin = str->ensureLinear(cx);
|
||||
@ -264,7 +271,8 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames)
|
||||
|
||||
// Parent
|
||||
JS::RootedObject parent(cx);
|
||||
result = JS::GetSavedFrameParent(cx, savedFrame, &parent, JS::SavedFrameSelfHosted::Exclude);
|
||||
result = JS::GetSavedFrameParent(cx, principals, savedFrame, &parent,
|
||||
JS::SavedFrameSelfHosted::Exclude);
|
||||
CHECK(result == JS::SavedFrameResult::Ok);
|
||||
// JS::GetSavedFrameParent does this super funky and potentially unexpected
|
||||
// thing where it doesn't return the next subsumed parent but any next
|
||||
@ -277,7 +285,8 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames)
|
||||
// here is the selfHostedFrame's parent (because, as just explained, it
|
||||
// isn't) and instead check that asking for the source property gives us the
|
||||
// expected value.
|
||||
result = JS::GetSavedFrameSource(cx, parent, &str, JS::SavedFrameSelfHosted::Exclude);
|
||||
result = JS::GetSavedFrameSource(cx, principals, parent, &str,
|
||||
JS::SavedFrameSelfHosted::Exclude);
|
||||
CHECK(result == JS::SavedFrameResult::Ok);
|
||||
lin = str->ensureLinear(cx);
|
||||
CHECK(lin);
|
||||
|
@ -5117,7 +5117,9 @@ JS_PUBLIC_API(void)
|
||||
JS::DumpPromiseAllocationSite(JSContext* cx, JS::HandleObject promise)
|
||||
{
|
||||
RootedObject stack(cx, promise->as<PromiseObject>().allocationSite());
|
||||
UniqueChars stackStr(reinterpret_cast<char*>(BuildUTF8StackString(cx, stack).get()));
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
UniqueChars stackStr(
|
||||
reinterpret_cast<char*>(BuildUTF8StackString(cx, principals, stack).get()));
|
||||
if (stackStr.get())
|
||||
fputs(stackStr.get(), stderr);
|
||||
}
|
||||
@ -5126,7 +5128,9 @@ JS_PUBLIC_API(void)
|
||||
JS::DumpPromiseResolutionSite(JSContext* cx, JS::HandleObject promise)
|
||||
{
|
||||
RootedObject stack(cx, promise->as<PromiseObject>().resolutionSite());
|
||||
UniqueChars stackStr(reinterpret_cast<char*>(BuildUTF8StackString(cx, stack).get()));
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
UniqueChars stackStr(
|
||||
reinterpret_cast<char*>(BuildUTF8StackString(cx, principals, stack).get()));
|
||||
if (stackStr.get())
|
||||
fputs(stackStr.get(), stderr);
|
||||
}
|
||||
|
@ -6243,23 +6243,24 @@ CopyAsyncStack(JSContext* cx, HandleObject asyncStack,
|
||||
* and the object is not the SavedFrame.prototype object.
|
||||
*
|
||||
* Each of these functions will find the first SavedFrame object in the chain
|
||||
* whose underlying stack frame principals are subsumed by the cx's current
|
||||
* compartment's principals, and operate on that SavedFrame object. This
|
||||
* prevents leaking information about privileged frames to un-privileged
|
||||
* callers. As a result, the SavedFrame in parameters do _NOT_ need to be in the
|
||||
* same compartment as the cx, and the various out parameters are _NOT_
|
||||
* guaranteed to be in the same compartment as cx.
|
||||
* whose underlying stack frame principals are subsumed by the given
|
||||
* |principals|, and operate on that SavedFrame object. This prevents leaking
|
||||
* information about privileged frames to un-privileged callers
|
||||
*
|
||||
* The SavedFrame in parameters do _NOT_ need to be in the same compartment as
|
||||
* the cx, and the various out parameters are _NOT_ guaranteed to be in the same
|
||||
* compartment as cx.
|
||||
*
|
||||
* You may consider or skip over self-hosted frames by passing
|
||||
* `SavedFrameSelfHosted::Include` or `SavedFrameSelfHosted::Exclude`
|
||||
* respectively.
|
||||
*
|
||||
* Additionally, it may be the case that there is no such SavedFrame object
|
||||
* whose captured frame's principals are subsumed by the caller's compartment's
|
||||
* principals! If the `HandleObject savedFrame` argument is null, or the
|
||||
* caller's principals do not subsume any of the chained SavedFrame object's
|
||||
* principals, `SavedFrameResult::AccessDenied` is returned and a (hopefully)
|
||||
* sane default value is chosen for the out param.
|
||||
* whose captured frame's principals are subsumed by |principals|! If the
|
||||
* `HandleObject savedFrame` argument is null, or the |principals| do not
|
||||
* subsume any of the chained SavedFrame object's principals,
|
||||
* `SavedFrameResult::AccessDenied` is returned and a (hopefully) sane default
|
||||
* value is chosen for the out param.
|
||||
*
|
||||
* See also `js/src/doc/SavedFrame/SavedFrame.md`.
|
||||
*/
|
||||
@ -6279,21 +6280,24 @@ enum class SavedFrameSelfHosted {
|
||||
* string.
|
||||
*/
|
||||
extern JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep,
|
||||
GetSavedFrameSource(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleString sourcep,
|
||||
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
|
||||
|
||||
/**
|
||||
* Given a SavedFrame JSObject, get its line property. Defaults to 0.
|
||||
*/
|
||||
extern JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
|
||||
GetSavedFrameLine(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
uint32_t* linep,
|
||||
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
|
||||
|
||||
/**
|
||||
* Given a SavedFrame JSObject, get its column property. Defaults to 0.
|
||||
*/
|
||||
extern JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
|
||||
GetSavedFrameColumn(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
uint32_t* columnp,
|
||||
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
|
||||
|
||||
/**
|
||||
@ -6302,14 +6306,16 @@ GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
|
||||
* function. Defaults to nullptr.
|
||||
*/
|
||||
extern JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep,
|
||||
GetSavedFrameFunctionDisplayName(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleString namep,
|
||||
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
|
||||
|
||||
/**
|
||||
* Given a SavedFrame JSObject, get its asyncCause string. Defaults to nullptr.
|
||||
*/
|
||||
extern JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep,
|
||||
GetSavedFrameAsyncCause(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleString asyncCausep,
|
||||
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
|
||||
|
||||
/**
|
||||
@ -6318,8 +6324,9 @@ GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleStr
|
||||
* guaranteed to be in the cx's compartment. Defaults to nullptr.
|
||||
*/
|
||||
extern JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp,
|
||||
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
|
||||
GetSavedFrameAsyncParent(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleObject asyncParentp,
|
||||
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
|
||||
|
||||
/**
|
||||
* Given a SavedFrame JSObject, get its parent SavedFrame object or nullptr if
|
||||
@ -6327,7 +6334,8 @@ GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleOb
|
||||
* guaranteed to be in the cx's compartment. Defaults to nullptr.
|
||||
*/
|
||||
extern JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp,
|
||||
GetSavedFrameParent(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleObject parentp,
|
||||
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
|
||||
|
||||
/**
|
||||
@ -6338,13 +6346,15 @@ GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject
|
||||
* The same notes above about SavedFrame accessors applies here as well: cx
|
||||
* doesn't need to be in stack's compartment, and stack can be null, a
|
||||
* SavedFrame object, or a wrapper (CCW or Xray) around a SavedFrame object.
|
||||
* SavedFrames not subsumed by |principals| are skipped.
|
||||
*
|
||||
* Optional indent parameter specifies the number of white spaces to indent
|
||||
* each line.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp,
|
||||
size_t indent = 0, js::StackFormat stackFormat = js::StackFormat::Default);
|
||||
BuildStackString(JSContext* cx, JSPrincipals* principals, HandleObject stack,
|
||||
MutableHandleString stringp, size_t indent = 0,
|
||||
js::StackFormat stackFormat = js::StackFormat::Default);
|
||||
|
||||
/**
|
||||
* Return true iff the given object is either a SavedFrame object or wrapper
|
||||
|
@ -379,7 +379,7 @@ js::ComputeStackString(JSContext* cx)
|
||||
return nullptr;
|
||||
|
||||
RootedString str(cx);
|
||||
if (!BuildStackString(cx, stack, &str))
|
||||
if (!BuildStackString(cx, cx->realm()->principals(), stack, &str))
|
||||
return nullptr;
|
||||
|
||||
return str.get();
|
||||
|
@ -7686,8 +7686,9 @@ PrintStackTrace(JSContext* cx, HandleValue exn)
|
||||
if (!stackObj)
|
||||
return true;
|
||||
|
||||
JSPrincipals* principals = exnObj->as<ErrorObject>().realm()->principals();
|
||||
RootedString stackStr(cx);
|
||||
if (!BuildStackString(cx, stackObj, &stackStr, 2))
|
||||
if (!BuildStackString(cx, principals, stackObj, &stackStr, 2))
|
||||
return false;
|
||||
|
||||
UniqueChars stack(JS_EncodeStringToUTF8(cx, stackStr));
|
||||
|
@ -236,9 +236,13 @@ js::ErrorObject::getStack_impl(JSContext* cx, const CallArgs& args)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do frame filtering based on the ErrorObject's principals. This ensures we
|
||||
// don't see chrome frames when chrome code accesses .stack over Xrays.
|
||||
JSPrincipals* principals = obj->as<ErrorObject>().realm()->principals();
|
||||
|
||||
RootedObject savedFrameObj(cx, obj->as<ErrorObject>().stack());
|
||||
RootedString stackString(cx);
|
||||
if (!BuildStackString(cx, savedFrameObj, &stackString))
|
||||
if (!BuildStackString(cx, principals, savedFrameObj, &stackString))
|
||||
return false;
|
||||
|
||||
if (cx->runtime()->stackFormat() == js::StackFormat::V8) {
|
||||
|
@ -607,14 +607,13 @@ SavedFrame::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
static bool
|
||||
SavedFrameSubsumedByCaller(JSContext* cx, HandleSavedFrame frame)
|
||||
SavedFrameSubsumedByPrincipals(JSContext* cx, JSPrincipals* principals, HandleSavedFrame frame)
|
||||
{
|
||||
auto subsumes = cx->runtime()->securityCallbacks->subsumes;
|
||||
if (!subsumes)
|
||||
return true;
|
||||
|
||||
auto currentRealmPrincipals = cx->realm()->principals();
|
||||
MOZ_ASSERT(!ReconstructedSavedFramePrincipals::is(currentRealmPrincipals));
|
||||
MOZ_ASSERT(!ReconstructedSavedFramePrincipals::is(principals));
|
||||
|
||||
auto framePrincipals = frame->getPrincipals();
|
||||
|
||||
@ -625,7 +624,7 @@ SavedFrameSubsumedByCaller(JSContext* cx, HandleSavedFrame frame)
|
||||
if (framePrincipals == &ReconstructedSavedFramePrincipals::IsNotSystem)
|
||||
return true;
|
||||
|
||||
return subsumes(currentRealmPrincipals, framePrincipals);
|
||||
return subsumes(principals, framePrincipals);
|
||||
}
|
||||
|
||||
// Return the first SavedFrame in the chain that starts with |frame| whose
|
||||
@ -634,7 +633,7 @@ SavedFrameSubsumedByCaller(JSContext* cx, HandleSavedFrame frame)
|
||||
// had the |asyncCause| property set, otherwise it is explicitly set to false.
|
||||
template<typename Matcher>
|
||||
static SavedFrame*
|
||||
GetFirstMatchedFrame(JSContext* cx, Matcher& matches,
|
||||
GetFirstMatchedFrame(JSContext* cx, JSPrincipals* principals, Matcher& matches,
|
||||
HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted,
|
||||
bool& skippedAsync)
|
||||
{
|
||||
@ -644,7 +643,7 @@ GetFirstMatchedFrame(JSContext* cx, Matcher& matches,
|
||||
while (rootedFrame) {
|
||||
if ((selfHosted == JS::SavedFrameSelfHosted::Include ||
|
||||
!rootedFrame->isSelfHosted(cx)) &&
|
||||
matches(cx, rootedFrame))
|
||||
matches(cx, principals, rootedFrame))
|
||||
{
|
||||
return rootedFrame;
|
||||
}
|
||||
@ -659,15 +658,16 @@ GetFirstMatchedFrame(JSContext* cx, Matcher& matches,
|
||||
}
|
||||
|
||||
// Return the first SavedFrame in the chain that starts with |frame| whose
|
||||
// principals are subsumed by the principals of the context's current
|
||||
// compartment, according to |subsumes|. If there is no such frame, return
|
||||
// nullptr. |skippedAsync| is set to true if any of the skipped frames had the
|
||||
// |asyncCause| property set, otherwise it is explicitly set to false.
|
||||
// principals are subsumed by |principals|, according to |subsumes|. If there is
|
||||
// no such frame, return nullptr. |skippedAsync| is set to true if any of the
|
||||
// skipped frames had the |asyncCause| property set, otherwise it is explicitly
|
||||
// set to false.
|
||||
static SavedFrame*
|
||||
GetFirstSubsumedFrame(JSContext* cx, HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted,
|
||||
bool& skippedAsync)
|
||||
GetFirstSubsumedFrame(JSContext* cx, JSPrincipals* principals, HandleSavedFrame frame,
|
||||
JS::SavedFrameSelfHosted selfHosted, bool& skippedAsync)
|
||||
{
|
||||
return GetFirstMatchedFrame(cx, SavedFrameSubsumedByCaller, frame, selfHosted, skippedAsync);
|
||||
return GetFirstMatchedFrame(cx, principals, SavedFrameSubsumedByPrincipals, frame, selfHosted,
|
||||
skippedAsync);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject*)
|
||||
@ -682,13 +682,14 @@ GetFirstSubsumedSavedFrame(JSContext* cx, JSPrincipals* principals,
|
||||
if (!subsumes)
|
||||
return nullptr;
|
||||
|
||||
auto matcher = [&](JSContext* cx, HandleSavedFrame frame) -> bool {
|
||||
auto matcher =
|
||||
[subsumes](JSContext* cx, JSPrincipals* principals, HandleSavedFrame frame) -> bool {
|
||||
return subsumes(principals, frame->getPrincipals());
|
||||
};
|
||||
|
||||
bool skippedAsync;
|
||||
RootedSavedFrame frame(cx, &savedFrame->as<SavedFrame>());
|
||||
return GetFirstMatchedFrame(cx, matcher, frame, selfHosted, skippedAsync);
|
||||
return GetFirstMatchedFrame(cx, principals, matcher, frame, selfHosted, skippedAsync);
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
@ -748,56 +749,9 @@ SavedFrame_checkThis(JSContext* cx, CallArgs& args, const char* fnName,
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace {
|
||||
|
||||
// It's possible that our caller is privileged (and hence would see the entire
|
||||
// stack) but we're working with an SavedFrame object that was captured in
|
||||
// unprivileged code. If so, drop privileges down to its level. 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.
|
||||
//
|
||||
// We want callers to pass us the object they were actually passed, not an
|
||||
// unwrapped form of it. That way Xray access to SavedFrame objects should not
|
||||
// be affected by AutoMaybeEnterFrameRealm and the only things that will
|
||||
// be affected will be cases in which privileged code works with some C++ object
|
||||
// that then pokes at an unprivileged StackFrame it has on hand.
|
||||
class MOZ_STACK_CLASS AutoMaybeEnterFrameRealm
|
||||
{
|
||||
public:
|
||||
AutoMaybeEnterFrameRealm(JSContext* cx,
|
||||
HandleObject obj
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
MOZ_RELEASE_ASSERT(cx->realm());
|
||||
if (obj)
|
||||
MOZ_RELEASE_ASSERT(obj->deprecatedRealm());
|
||||
|
||||
// Note that obj might be null here, since we're doing this before
|
||||
// UnwrapSavedFrame.
|
||||
if (obj && cx->realm() != obj->deprecatedRealm())
|
||||
{
|
||||
JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes;
|
||||
if (subsumes && subsumes(cx->realm()->principals(),
|
||||
obj->deprecatedRealm()->principals()))
|
||||
{
|
||||
ar_.emplace(cx, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Maybe<JSAutoRealm> ar_;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static inline js::SavedFrame*
|
||||
UnwrapSavedFrame(JSContext* cx, HandleObject obj, SavedFrameSelfHosted selfHosted,
|
||||
bool& skippedAsync)
|
||||
UnwrapSavedFrame(JSContext* cx, JSPrincipals* principals, HandleObject obj,
|
||||
SavedFrameSelfHosted selfHosted, bool& skippedAsync)
|
||||
{
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
@ -808,11 +762,12 @@ UnwrapSavedFrame(JSContext* cx, HandleObject obj, SavedFrameSelfHosted selfHoste
|
||||
|
||||
MOZ_RELEASE_ASSERT(js::SavedFrame::isSavedFrameAndNotProto(*savedFrameObj));
|
||||
js::RootedSavedFrame frame(cx, &savedFrameObj->as<js::SavedFrame>());
|
||||
return GetFirstSubsumedFrame(cx, frame, selfHosted, skippedAsync);
|
||||
return GetFirstSubsumedFrame(cx, principals, frame, selfHosted, skippedAsync);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep,
|
||||
GetSavedFrameSource(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleString sourcep,
|
||||
SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
|
||||
{
|
||||
js::AssertHeapIsIdle();
|
||||
@ -820,9 +775,9 @@ GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString
|
||||
MOZ_RELEASE_ASSERT(cx->realm());
|
||||
|
||||
{
|
||||
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
|
||||
bool skippedAsync;
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted,
|
||||
skippedAsync));
|
||||
if (!frame) {
|
||||
sourcep.set(cx->runtime()->emptyString);
|
||||
return SavedFrameResult::AccessDenied;
|
||||
@ -835,7 +790,8 @@ GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
|
||||
GetSavedFrameLine(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
uint32_t* linep,
|
||||
SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
|
||||
{
|
||||
js::AssertHeapIsIdle();
|
||||
@ -843,9 +799,9 @@ GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
|
||||
MOZ_RELEASE_ASSERT(cx->realm());
|
||||
MOZ_ASSERT(linep);
|
||||
|
||||
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
|
||||
bool skippedAsync;
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted,
|
||||
skippedAsync));
|
||||
if (!frame) {
|
||||
*linep = 0;
|
||||
return SavedFrameResult::AccessDenied;
|
||||
@ -855,7 +811,8 @@ GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
|
||||
GetSavedFrameColumn(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
uint32_t* columnp,
|
||||
SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
|
||||
{
|
||||
js::AssertHeapIsIdle();
|
||||
@ -863,9 +820,9 @@ GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
|
||||
MOZ_RELEASE_ASSERT(cx->realm());
|
||||
MOZ_ASSERT(columnp);
|
||||
|
||||
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
|
||||
bool skippedAsync;
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted,
|
||||
skippedAsync));
|
||||
if (!frame) {
|
||||
*columnp = 0;
|
||||
return SavedFrameResult::AccessDenied;
|
||||
@ -875,7 +832,8 @@ GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep,
|
||||
GetSavedFrameFunctionDisplayName(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleString namep,
|
||||
SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
|
||||
{
|
||||
js::AssertHeapIsIdle();
|
||||
@ -883,9 +841,9 @@ GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, Mutable
|
||||
MOZ_RELEASE_ASSERT(cx->realm());
|
||||
|
||||
{
|
||||
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
|
||||
bool skippedAsync;
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted,
|
||||
skippedAsync));
|
||||
if (!frame) {
|
||||
namep.set(nullptr);
|
||||
return SavedFrameResult::AccessDenied;
|
||||
@ -898,7 +856,8 @@ GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, Mutable
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep,
|
||||
GetSavedFrameAsyncCause(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleString asyncCausep,
|
||||
SavedFrameSelfHosted unused_ /* = SavedFrameSelfHosted::Include */)
|
||||
{
|
||||
js::AssertHeapIsIdle();
|
||||
@ -906,14 +865,14 @@ GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleStr
|
||||
MOZ_RELEASE_ASSERT(cx->realm());
|
||||
|
||||
{
|
||||
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
|
||||
bool skippedAsync;
|
||||
// This function is always called with self-hosted frames excluded by
|
||||
// GetValueIfNotCached in dom/bindings/Exceptions.cpp. However, we want
|
||||
// to include them because our Promise implementation causes us to have
|
||||
// the async cause on a self-hosted frame. So we just ignore the
|
||||
// parameter and always include self-hosted frames.
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, SavedFrameSelfHosted::Include,
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame,
|
||||
SavedFrameSelfHosted::Include,
|
||||
skippedAsync));
|
||||
if (!frame) {
|
||||
asyncCausep.set(nullptr);
|
||||
@ -929,16 +888,17 @@ GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleStr
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp,
|
||||
GetSavedFrameAsyncParent(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleObject asyncParentp,
|
||||
SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
|
||||
{
|
||||
js::AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
MOZ_RELEASE_ASSERT(cx->realm());
|
||||
|
||||
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
|
||||
bool skippedAsync;
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted,
|
||||
skippedAsync));
|
||||
if (!frame) {
|
||||
asyncParentp.set(nullptr);
|
||||
return SavedFrameResult::AccessDenied;
|
||||
@ -948,8 +908,8 @@ GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleOb
|
||||
// The current value of |skippedAsync| is not interesting, because we are
|
||||
// interested in whether we would cross any async parents to get from here
|
||||
// to the first subsumed parent frame instead.
|
||||
js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, parent, selfHosted,
|
||||
skippedAsync));
|
||||
js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, principals, parent,
|
||||
selfHosted, skippedAsync));
|
||||
|
||||
// Even if |parent| is not subsumed, we still want to return a pointer to it
|
||||
// rather than |subsumedParent| so it can pick up any |asyncCause| from the
|
||||
@ -962,16 +922,17 @@ GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleOb
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(SavedFrameResult)
|
||||
GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp,
|
||||
GetSavedFrameParent(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
|
||||
MutableHandleObject parentp,
|
||||
SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
|
||||
{
|
||||
js::AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
MOZ_RELEASE_ASSERT(cx->realm());
|
||||
|
||||
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
|
||||
bool skippedAsync;
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted,
|
||||
skippedAsync));
|
||||
if (!frame) {
|
||||
parentp.set(nullptr);
|
||||
return SavedFrameResult::AccessDenied;
|
||||
@ -981,8 +942,8 @@ GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject
|
||||
// The current value of |skippedAsync| is not interesting, because we are
|
||||
// interested in whether we would cross any async parents to get from here
|
||||
// to the first subsumed parent frame instead.
|
||||
js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, parent, selfHosted,
|
||||
skippedAsync));
|
||||
js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, principals, parent,
|
||||
selfHosted, skippedAsync));
|
||||
|
||||
// Even if |parent| is not subsumed, we still want to return a pointer to it
|
||||
// rather than |subsumedParent| so it can pick up any |asyncCause| from the
|
||||
@ -1068,8 +1029,8 @@ FormatV8StackFrame(JSContext* cx, js::StringBuffer& sb,
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp,
|
||||
size_t indent, js::StackFormat format)
|
||||
BuildStackString(JSContext* cx, JSPrincipals* principals, HandleObject stack,
|
||||
MutableHandleString stringp, size_t indent, js::StackFormat format)
|
||||
{
|
||||
js::AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
@ -1086,9 +1047,9 @@ BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp,
|
||||
// the cx's original compartment, and fulfill our contract with callers to
|
||||
// place the output string in the cx's current realm.
|
||||
{
|
||||
AutoMaybeEnterFrameRealm ar(cx, stack);
|
||||
bool skippedAsync;
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, stack, SavedFrameSelfHosted::Exclude,
|
||||
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, stack,
|
||||
SavedFrameSelfHosted::Exclude,
|
||||
skippedAsync));
|
||||
if (!frame) {
|
||||
stringp.set(cx->runtime()->emptyString);
|
||||
@ -1097,12 +1058,12 @@ BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp,
|
||||
|
||||
js::RootedSavedFrame parent(cx);
|
||||
do {
|
||||
MOZ_ASSERT(SavedFrameSubsumedByCaller(cx, frame));
|
||||
MOZ_ASSERT(SavedFrameSubsumedByPrincipals(cx, principals, frame));
|
||||
MOZ_ASSERT(!frame->isSelfHosted(cx));
|
||||
|
||||
parent = frame->getParent();
|
||||
bool skippedNextAsync;
|
||||
js::RootedSavedFrame nextFrame(cx, js::GetFirstSubsumedFrame(cx, parent,
|
||||
js::RootedSavedFrame nextFrame(cx, js::GetFirstSubsumedFrame(cx, principals, parent,
|
||||
SavedFrameSelfHosted::Exclude, skippedNextAsync));
|
||||
|
||||
switch (format) {
|
||||
@ -1154,8 +1115,9 @@ namespace js {
|
||||
SavedFrame::sourceProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame);
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
RootedString source(cx);
|
||||
if (JS::GetSavedFrameSource(cx, frame, &source) == JS::SavedFrameResult::Ok) {
|
||||
if (JS::GetSavedFrameSource(cx, principals, frame, &source) == JS::SavedFrameResult::Ok) {
|
||||
if (!cx->compartment()->wrap(cx, &source))
|
||||
return false;
|
||||
args.rval().setString(source);
|
||||
@ -1169,8 +1131,9 @@ SavedFrame::sourceProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
SavedFrame::lineProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame);
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
uint32_t line;
|
||||
if (JS::GetSavedFrameLine(cx, frame, &line) == JS::SavedFrameResult::Ok)
|
||||
if (JS::GetSavedFrameLine(cx, principals, frame, &line) == JS::SavedFrameResult::Ok)
|
||||
args.rval().setNumber(line);
|
||||
else
|
||||
args.rval().setNull();
|
||||
@ -1181,8 +1144,9 @@ SavedFrame::lineProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
SavedFrame::columnProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_SAVEDFRAME(cx, argc, vp, "(get column)", args, frame);
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
uint32_t column;
|
||||
if (JS::GetSavedFrameColumn(cx, frame, &column) == JS::SavedFrameResult::Ok)
|
||||
if (JS::GetSavedFrameColumn(cx, principals, frame, &column) == JS::SavedFrameResult::Ok)
|
||||
args.rval().setNumber(column);
|
||||
else
|
||||
args.rval().setNull();
|
||||
@ -1193,8 +1157,10 @@ SavedFrame::columnProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
SavedFrame::functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", args, frame);
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
RootedString name(cx);
|
||||
JS::SavedFrameResult result = JS::GetSavedFrameFunctionDisplayName(cx, frame, &name);
|
||||
JS::SavedFrameResult result =
|
||||
JS::GetSavedFrameFunctionDisplayName(cx, principals, frame, &name);
|
||||
if (result == JS::SavedFrameResult::Ok && name) {
|
||||
if (!cx->compartment()->wrap(cx, &name))
|
||||
return false;
|
||||
@ -1209,8 +1175,9 @@ SavedFrame::functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
SavedFrame::asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_SAVEDFRAME(cx, argc, vp, "(get asyncCause)", args, frame);
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
RootedString asyncCause(cx);
|
||||
JS::SavedFrameResult result = JS::GetSavedFrameAsyncCause(cx, frame, &asyncCause);
|
||||
JS::SavedFrameResult result = JS::GetSavedFrameAsyncCause(cx, principals, frame, &asyncCause);
|
||||
if (result == JS::SavedFrameResult::Ok && asyncCause) {
|
||||
if (!cx->compartment()->wrap(cx, &asyncCause))
|
||||
return false;
|
||||
@ -1225,8 +1192,9 @@ SavedFrame::asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
SavedFrame::asyncParentProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_SAVEDFRAME(cx, argc, vp, "(get asyncParent)", args, frame);
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
RootedObject asyncParent(cx);
|
||||
(void) JS::GetSavedFrameAsyncParent(cx, frame, &asyncParent);
|
||||
(void) JS::GetSavedFrameAsyncParent(cx, principals, frame, &asyncParent);
|
||||
if (!cx->compartment()->wrap(cx, &asyncParent))
|
||||
return false;
|
||||
args.rval().setObjectOrNull(asyncParent);
|
||||
@ -1237,8 +1205,9 @@ SavedFrame::asyncParentProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
SavedFrame::parentProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", args, frame);
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
RootedObject parent(cx);
|
||||
(void) JS::GetSavedFrameParent(cx, frame, &parent);
|
||||
(void) JS::GetSavedFrameParent(cx, principals, frame, &parent);
|
||||
if (!cx->compartment()->wrap(cx, &parent))
|
||||
return false;
|
||||
args.rval().setObjectOrNull(parent);
|
||||
@ -1249,8 +1218,9 @@ SavedFrame::parentProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
SavedFrame::toStringMethod(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_SAVEDFRAME(cx, argc, vp, "toString", args, frame);
|
||||
JSPrincipals* principals = cx->realm()->principals();
|
||||
RootedString string(cx);
|
||||
if (!JS::BuildStackString(cx, frame, &string))
|
||||
if (!JS::BuildStackString(cx, principals, frame, &string))
|
||||
return false;
|
||||
args.rval().setString(string);
|
||||
return true;
|
||||
@ -1860,10 +1830,10 @@ const SavedStacks::MetadataBuilder SavedStacks::metadataBuilder;
|
||||
/* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsNotSystem;
|
||||
|
||||
UTF8CharsZ
|
||||
BuildUTF8StackString(JSContext* cx, HandleObject stack)
|
||||
BuildUTF8StackString(JSContext* cx, JSPrincipals* principals, HandleObject stack)
|
||||
{
|
||||
RootedString stackStr(cx);
|
||||
if (!JS::BuildStackString(cx, stack, &stackStr))
|
||||
if (!JS::BuildStackString(cx, principals, stack, &stackStr))
|
||||
return UTF8CharsZ();
|
||||
|
||||
char* chars = JS_EncodeStringToUTF8(cx, stackStr);
|
||||
|
@ -323,7 +323,7 @@ struct MutableWrappedPtrOperations<SavedStacks::LocationValue, Wrapper>
|
||||
};
|
||||
|
||||
UTF8CharsZ
|
||||
BuildUTF8StackString(JSContext* cx, HandleObject stack);
|
||||
BuildUTF8StackString(JSContext* cx, JSPrincipals* principals, HandleObject stack);
|
||||
|
||||
uint32_t
|
||||
FixupColumnForDisplay(uint32_t column);
|
||||
|
@ -2063,13 +2063,15 @@ nsXPCComponents_Utils::ReportError(HandleValue error, HandleValue stack, JSConte
|
||||
stackGlobal = JS::CurrentGlobalOrNull(cx);
|
||||
js::AssertSameCompartment(stackObj, stackGlobal);
|
||||
|
||||
if (GetSavedFrameLine(cx, stackObj, &lineNo) != SavedFrameResult::Ok) {
|
||||
JSPrincipals* principals = JS::GetRealmPrincipals(js::GetContextRealm(cx));
|
||||
|
||||
if (GetSavedFrameLine(cx, principals, stackObj, &lineNo) != SavedFrameResult::Ok) {
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
|
||||
RootedString source(cx);
|
||||
nsAutoJSString str;
|
||||
if (GetSavedFrameSource(cx, stackObj, &source) == SavedFrameResult::Ok &&
|
||||
if (GetSavedFrameSource(cx, principals, stackObj, &source) == SavedFrameResult::Ok &&
|
||||
str.init(cx, source)) {
|
||||
fileName = str;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user