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:
Jan de Mooij 2018-07-21 14:34:58 +02:00
parent 8c93c6e9e8
commit 30d5135f62
13 changed files with 226 additions and 172 deletions

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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();

View File

@ -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));

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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 {