Backed out 7 changesets (bug 1117242) for mochitest failures.

Backed out changeset 694f7ac58964 (bug 1117242)
Backed out changeset b3f8122dd990 (bug 1117242)
Backed out changeset 442d41779bd8 (bug 1117242)
Backed out changeset ccf6dfe1ac75 (bug 1117242)
Backed out changeset 86421767cd26 (bug 1117242)
Backed out changeset 2f996950fb2f (bug 1117242)
Backed out changeset 4414e9d0b66b (bug 1117242)

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2015-02-06 13:40:53 -05:00
Родитель 82cbc626c5
Коммит 4e69725665
16 изменённых файлов: 131 добавлений и 364 удалений

Просмотреть файл

@ -967,30 +967,9 @@ SaveStack(JSContext *cx, unsigned argc, jsval *vp)
maxFrameCount = d;
}
JSCompartment *targetCompartment = cx->compartment();
if (args.length() >= 2) {
if (!args[1].isObject()) {
js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
JSDVG_SEARCH_STACK, args[0], JS::NullPtr(),
"not an object", NULL);
return false;
}
RootedObject obj(cx, UncheckedUnwrap(&args[1].toObject()));
if (!obj)
return false;
targetCompartment = obj->compartment();
}
RootedObject stack(cx);
{
AutoCompartment ac(cx, targetCompartment);
if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount))
return false;
}
if (stack && !cx->compartment()->wrap(cx, &stack))
Rooted<JSObject*> stack(cx);
if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount))
return false;
args.rval().setObjectOrNull(stack);
return true;
}
@ -2417,15 +2396,13 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
" SavedStacks cache."),
JS_FN_HELP("saveStack", SaveStack, 0, 0,
"saveStack([maxDepth [, compartment]])",
" Capture a stack. If 'maxDepth' is given, capture at most 'maxDepth' number\n"
" of frames. If 'compartment' is given, allocate the js::SavedFrame instances\n"
" with the given object's compartment."),
"saveStack()",
" Capture a stack.\n"),
JS_FN_HELP("enableTrackAllocations", EnableTrackAllocations, 0, 0,
"enableTrackAllocations()",
" Start capturing the JS stack at every allocation. Note that this sets an\n"
" object metadata callback that will override any other object metadata\n"
" Start capturing the JS stack at every allocation. Note that this sets an "
" object metadata callback that will override any other object metadata "
" callback that may be set."),
JS_FN_HELP("disableTrackAllocations", DisableTrackAllocations, 0, 0,

Просмотреть файл

@ -5,44 +5,6 @@ JavaScript call stack at a past moment of execution. Younger frames hold a
reference to the frames that invoked them. The older tails are shared across
many younger frames.
`SavedFrame` stacks should generally be captured, allocated, and live within the
compartment that is being observed or debugged. Usually this is a content
compartment.
## Capturing `SavedFrame` Stacks
### From C++
Use `JS::CaptureCurrentStack` declared in `jsapi.h`.
### From JS
Use `saveStack`, accessible via `Components.utils.getJSTestingFunction()`.
## Including and Excluding Chrome Frames
Consider the following `SavedFrame` stack. Arrows represent links from child to
parent frame, `content.js` is from a compartment with content principals, and
`chrome.js` is from a compartment with chrome principals.
function A from content.js
|
V
function B from chrome.js
|
V
function C from content.js
The content compartment will ever have one view of this stack: `A -> C`.
However, a chrome compartment has a choice: it can either take the same view
that the content compartment has (`A -> C`), or it can view all stack frames,
including the frames from chrome compartments (`A -> B -> C`). To view
everything, use an `XrayWrapper`. This is the default wrapper. To see the stack
as the content compartment sees it, waive the xray wrapper with
`Components.utils.waiveXrays`:
const contentViewOfStack = Components.utils.waiveXrays(someStack);
## Accessor Properties of the `SavedFrame.prototype` Object

Просмотреть файл

@ -17,7 +17,6 @@ namespace js {
class PropertyName;
class NativeObject;
class ArrayObject;
class GlobalObject;
class PlainObject;
class ScriptSourceObject;
class Shape;
@ -32,7 +31,6 @@ typedef JS::Handle<JSAtom*> HandleAtom;
typedef JS::Handle<JSLinearString*> HandleLinearString;
typedef JS::Handle<PropertyName*> HandlePropertyName;
typedef JS::Handle<ArrayObject*> HandleArrayObject;
typedef JS::Rooted<GlobalObject*> RootedGlobalObject;
typedef JS::Handle<PlainObject*> HandlePlainObject;
typedef JS::Handle<ScriptSourceObject*> HandleScriptSource;

Просмотреть файл

@ -42,7 +42,7 @@ var count = 0;
low .eval('function b() { check("b", extract(saveStack())); c(); }');
mid .eval('function c() { check("cba", extract(saveStack())); d(); }');
high.eval('function d() { check("dcba", extract(saveStack())); e(); }');
eval('function e() { check("ecba", extract(saveStack())); f(); }');
eval('function e() { check("edcba", extract(saveStack())); f(); }'); // no principal, so checks skipped
low .eval('function f() { check("fb", extract(saveStack())); g(); }');
mid .eval('function g() { check("gfecba", extract(saveStack())); h(); }');
high.eval('function h() { check("hgfedcba", extract(saveStack())); }');

Просмотреть файл

@ -33,7 +33,7 @@ var high = newGlobal({ principal: 0xfffff });
low .eval('function b() { check("b", saveStack().toString()); c(); }');
mid .eval('function c() { check("cba", saveStack().toString()); d(); }');
high.eval('function d() { check("dcba", saveStack().toString()); e(); }');
eval('function e() { check("ecba", saveStack().toString()); f(); }');
eval('function e() { check("edcba", saveStack().toString()); f(); }'); // no principal, so checks skipped
low .eval('function f() { check("fb", saveStack().toString()); g(); }');
mid .eval('function g() { check("gfecba", saveStack().toString()); h(); }');
high.eval('function h() { check("hgfedcba", saveStack().toString()); }');

Просмотреть файл

@ -1,23 +0,0 @@
// With arrows representing child-to-parent links, create a SavedFrame stack
// like this:
//
// high.a -> low.b
//
// in `low`'s compartment and give `low` a reference to this stack. Assert the
// stack's youngest frame's properties doesn't leak information about `high.a`
// that `low` shouldn't have access to, and instead returns information about
// `low.b`.
var low = newGlobal({ principal: 0 });
var high = newGlobal({ principal: 0xfffff });
low.high = high;
high.low = low;
high.eval("function a() { return saveStack(0, low); }");
low.eval("function b() { return high.a(); }")
var stack = low.b();
assertEq(stack.functionDisplayName, "b");
assertEq(stack.parent, null);

Просмотреть файл

@ -1,15 +0,0 @@
// Test what happens when a compartment gets a SavedFrame that it doesn't have
// the principals to access any of its frames.
var low = newGlobal({ principal: 0 });
var high = newGlobal({ principal: 0xfffff });
low.high = high;
high.low = low;
high.eval("function a() { return saveStack(1, low); }");
var stack = low.eval("high.a();")
assertEq(stack.functionDisplayName, null);
assertEq(stack.parent, null);
assertEq(stack.toString(), "");

Просмотреть файл

@ -111,8 +111,6 @@ IF_SAB(real,imaginary)(SharedFloat64Array, 50, js_InitViaClassSpec,
IF_SAB(real,imaginary)(SharedUint8ClampedArray, 51, js_InitViaClassSpec, SHARED_TYPED_ARRAY_CLASP(Uint8Clamped)) \
real(TypedArray, 52, js_InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \
IF_SAB(real,imaginary)(Atomics, 53, js_InitAtomicsClass, OCLASP(Atomics)) \
real(SavedFrame, 54, js_InitViaClassSpec, &js::SavedFrame::class_) \
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)

Просмотреть файл

@ -61,6 +61,8 @@ using mozilla::PodCopy;
using mozilla::PodZero;
using mozilla::RotateLeft;
typedef Rooted<GlobalObject *> RootedGlobalObject;
/* static */ BindingIter
Bindings::argumentsBinding(ExclusiveContext *cx, InternalBindingsHandle bindings)
{

Просмотреть файл

@ -306,7 +306,7 @@ class GlobalObject : public NativeObject
NativeObject *getOrCreateObjectPrototype(JSContext *cx) {
if (functionObjectClassesInitialized())
return &getPrototype(JSProto_Object).toObject().as<NativeObject>();
RootedGlobalObject self(cx, this);
Rooted<GlobalObject*> self(cx, this);
if (!ensureConstructor(cx, self, JSProto_Object))
return nullptr;
return &self->getPrototype(JSProto_Object).toObject().as<NativeObject>();
@ -315,7 +315,7 @@ class GlobalObject : public NativeObject
NativeObject *getOrCreateFunctionPrototype(JSContext *cx) {
if (functionObjectClassesInitialized())
return &getPrototype(JSProto_Function).toObject().as<NativeObject>();
RootedGlobalObject self(cx, this);
Rooted<GlobalObject*> self(cx, this);
if (!ensureConstructor(cx, self, JSProto_Object))
return nullptr;
return &self->getPrototype(JSProto_Function).toObject().as<NativeObject>();
@ -369,13 +369,6 @@ class GlobalObject : public NativeObject
return nullptr;
}
static NativeObject *getOrCreateSavedFramePrototype(JSContext *cx,
Handle<GlobalObject*> global) {
if (!ensureConstructor(cx, global, JSProto_SavedFrame))
return nullptr;
return &global->getPrototype(JSProto_SavedFrame).toObject().as<NativeObject>();
}
static JSObject *getOrCreateArrayBufferPrototype(JSContext *cx, Handle<GlobalObject*> global) {
if (!ensureConstructor(cx, global, JSProto_ArrayBuffer))
return nullptr;
@ -475,7 +468,7 @@ class GlobalObject : public NativeObject
Value v = getSlotRef(slot);
if (v.isObject())
return &v.toObject();
RootedGlobalObject self(cx, this);
Rooted<GlobalObject*> self(cx, this);
if (!init(cx, self))
return nullptr;
return &self->getSlot(slot).toObject();
@ -553,7 +546,7 @@ class GlobalObject : public NativeObject
}
JSObject *getOrCreateDataViewPrototype(JSContext *cx) {
RootedGlobalObject self(cx, this);
Rooted<GlobalObject*> self(cx, this);
if (!ensureConstructor(cx, self, JSProto_DataView))
return nullptr;
return &self->getPrototype(JSProto_DataView).toObject();

Просмотреть файл

@ -16,13 +16,12 @@
#include "jshashutil.h"
#include "jsmath.h"
#include "jsnum.h"
#include "jsscript.h"
#include "prmjtime.h"
#include "gc/Marking.h"
#include "gc/Rooting.h"
#include "js/Vector.h"
#include "vm/Debugger.h"
#include "vm/GlobalObject.h"
#include "vm/StringBuffer.h"
#include "jscntxtinlines.h"
@ -137,67 +136,18 @@ SavedFrame::HashPolicy::rekey(Key &key, const Key &newKey)
key = newKey;
}
/* static */ bool
SavedFrame::finishSavedFrameInit(JSContext *cx, HandleObject ctor, HandleObject proto)
{
// The only object with the SavedFrame::class_ that doesn't have a source
// should be the prototype.
proto->as<NativeObject>().setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());
return FreezeObject(cx, proto);
}
/* static */ const Class SavedFrame::class_ = {
"SavedFrame",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) |
JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) |
JSCLASS_IS_ANONYMOUS,
nullptr, // addProperty
nullptr, // delProperty
nullptr, // getProperty
nullptr, // setProperty
nullptr, // enumerate
nullptr, // resolve
nullptr, // convert
SavedFrame::finalize, // finalize
nullptr, // call
nullptr, // hasInstance
nullptr, // construct
nullptr, // trace
// ClassSpec
{
GenericCreateConstructor<SavedFrame::construct, 0, JSFunction::FinalizeKind>,
GenericCreatePrototype,
SavedFrame::staticFunctions,
SavedFrame::protoFunctions,
SavedFrame::protoAccessors,
SavedFrame::finishSavedFrameInit,
ClassSpec::DontDefineConstructor
}
};
/* static */ const JSFunctionSpec
SavedFrame::staticFunctions[] = {
JS_FS_END
};
/* static */ const JSFunctionSpec
SavedFrame::protoFunctions[] = {
JS_FN("constructor", SavedFrame::construct, 0, 0),
JS_FN("toString", SavedFrame::toStringMethod, 0, 0),
JS_FS_END
};
/* static */ const JSPropertySpec
SavedFrame::protoAccessors[] = {
JS_PSG("source", SavedFrame::sourceProperty, 0),
JS_PSG("line", SavedFrame::lineProperty, 0),
JS_PSG("column", SavedFrame::columnProperty, 0),
JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0),
JS_PSG("parent", SavedFrame::parentProperty, 0),
JS_PS_END
JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT),
nullptr, // addProperty
nullptr, // delProperty
nullptr, // getProperty
nullptr, // setProperty
nullptr, // enumerate
nullptr, // resolve
nullptr, // convert
SavedFrame::finalize
};
/* static */ void
@ -309,56 +259,33 @@ SavedFrame::construct(JSContext *cx, unsigned argc, Value *vp)
return false;
}
// Return the first SavedFrame in the chain that starts with |frame| whose
// principals are subsumed by |principals|, according to |subsumes|. If there is
// no such frame, return nullptr.
static SavedFrame *
GetFirstSubsumedFrame(JSContext *cx, SavedFrame *frame)
{
JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes;
if (!subsumes)
return frame;
JSPrincipals *principals = cx->compartment()->principals;
while (frame && !subsumes(principals, frame->getPrincipals()))
frame = frame->getParent();
return frame;
}
/* static */ bool
SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName,
MutableHandleSavedFrame frame)
/* static */ SavedFrame *
SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName)
{
const Value &thisValue = args.thisv();
if (!thisValue.isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
return false;
return nullptr;
}
JSObject *thisObject = CheckedUnwrap(&thisValue.toObject());
if (!thisObject || !thisObject->is<SavedFrame>()) {
JSObject &thisObject = thisValue.toObject();
if (!thisObject.is<SavedFrame>()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
SavedFrame::class_.name, fnName,
thisObject ? thisObject->getClass()->name : "object");
return false;
SavedFrame::class_.name, fnName, thisObject.getClass()->name);
return nullptr;
}
// Check for SavedFrame.prototype, which has the same class as SavedFrame
// instances, however doesn't actually represent a captured stack frame. It
// is the only object that is<SavedFrame>() but doesn't have a source.
if (thisObject->as<SavedFrame>().getReservedSlot(JSSLOT_SOURCE).isNull()) {
if (thisObject.as<SavedFrame>().getReservedSlot(JSSLOT_SOURCE).isNull()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
SavedFrame::class_.name, fnName, "prototype object");
return false;
return nullptr;
}
// The caller might not have the principals to see this frame's data, so get
// the first one they _do_ have access to.
frame.set(GetFirstSubsumedFrame(cx, &thisObject->as<SavedFrame>()));
return true;
return &thisObject.as<SavedFrame>();
}
// Get the SavedFrame * from the current this value and handle any errors that
@ -369,24 +296,19 @@ SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName,
// - unsigned argc
// - Value *vp
// - const char *fnName
// - Value defaultVal
// These parameters will be defined after calling this macro:
// - CallArgs args
// - Rooted<SavedFrame *> frame (will be non-null)
#define THIS_SAVEDFRAME(cx, argc, vp, fnName, defaultVal, args, frame) \
CallArgs args = CallArgsFromVp(argc, vp); \
RootedSavedFrame frame(cx); \
if (!checkThis(cx, args, fnName, &frame)) \
return false; \
if (!frame) { \
args.rval().set(defaultVal); \
return true; \
}
#define THIS_SAVEDFRAME(cx, argc, vp, fnName, args, frame) \
CallArgs args = CallArgsFromVp(argc, vp); \
RootedSavedFrame frame(cx, checkThis(cx, args, fnName)); \
if (!frame) \
return false
/* static */ bool
SavedFrame::sourceProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get source)", NullValue(), args, frame);
THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame);
args.rval().setString(frame->getSource());
return true;
}
@ -394,7 +316,7 @@ SavedFrame::sourceProperty(JSContext *cx, unsigned argc, Value *vp)
/* static */ bool
SavedFrame::lineProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get line)", NullValue(), args, frame);
THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame);
uint32_t line = frame->getLine();
args.rval().setNumber(line);
return true;
@ -403,7 +325,7 @@ SavedFrame::lineProperty(JSContext *cx, unsigned argc, Value *vp)
/* static */ bool
SavedFrame::columnProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get column)", NullValue(), args, frame);
THIS_SAVEDFRAME(cx, argc, vp, "(get column)", args, frame);
uint32_t column = frame->getColumn();
args.rval().setNumber(column);
return true;
@ -412,7 +334,7 @@ SavedFrame::columnProperty(JSContext *cx, unsigned argc, Value *vp)
/* static */ bool
SavedFrame::functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", NullValue(), args, frame);
THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", args, frame);
RootedAtom name(cx, frame->getFunctionDisplayName());
if (name)
args.rval().setString(name);
@ -424,21 +346,39 @@ SavedFrame::functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp)
/* static */ bool
SavedFrame::parentProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", NullValue(), args, frame);
args.rval().setObjectOrNull(GetFirstSubsumedFrame(cx, frame->getParent()));
THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", args, frame);
JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes;
JSPrincipals *principals = cx->compartment()->principals;
do
frame = frame->getParent();
while (frame && principals && subsumes &&
!subsumes(principals, frame->getPrincipals()));
args.rval().setObjectOrNull(frame);
return true;
}
/* static */ const JSPropertySpec SavedFrame::properties[] = {
JS_PSG("source", SavedFrame::sourceProperty, 0),
JS_PSG("line", SavedFrame::lineProperty, 0),
JS_PSG("column", SavedFrame::columnProperty, 0),
JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0),
JS_PSG("parent", SavedFrame::parentProperty, 0),
JS_PS_END
};
/* static */ bool
SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "toString", StringValue(cx->runtime()->emptyString), args, frame);
THIS_SAVEDFRAME(cx, argc, vp, "toString", args, frame);
StringBuffer sb(cx);
DebugOnly<JSSubsumesOp> subsumes = cx->runtime()->securityCallbacks->subsumes;
DebugOnly<JSPrincipals *> principals = cx->compartment()->principals;
JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes;
JSPrincipals *principals = cx->compartment()->principals;
do {
MOZ_ASSERT_IF(subsumes, (*subsumes)(principals, frame->getPrincipals()));
if (principals && subsumes && !subsumes(principals, frame->getPrincipals()))
continue;
if (frame->isSelfHosted())
continue;
@ -454,7 +394,7 @@ SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp)
{
return false;
}
} while ((frame = GetFirstSubsumedFrame(cx, frame->getParent())));
} while ((frame = frame->getParent()));
JSString *str = sb.finishString();
if (!str)
@ -463,6 +403,12 @@ SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp)
return true;
}
/* static */ const JSFunctionSpec SavedFrame::methods[] = {
JS_FN("constructor", SavedFrame::construct, 0, 0),
JS_FN("toString", SavedFrame::toStringMethod, 0, 0),
JS_FS_END
};
bool
SavedStacks::init()
{
@ -514,6 +460,12 @@ SavedStacks::sweep(JSRuntime *rt)
}
sweepPCLocationMap();
if (savedFrameProto.unbarrieredGet() &&
IsObjectAboutToBeFinalizedFromAnyThread(savedFrameProto.unsafeGet()))
{
savedFrameProto.set(nullptr);
}
}
void
@ -635,17 +587,49 @@ SavedStacks::getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup looku
return frame;
}
JSObject *
SavedStacks::getOrCreateSavedFramePrototype(JSContext *cx)
{
if (savedFrameProto)
return savedFrameProto;
Rooted<GlobalObject *> global(cx, cx->compartment()->maybeGlobal());
if (!global)
return nullptr;
Rooted<SavedFrame *> proto(cx,
NewObjectWithGivenProto<SavedFrame>(cx, global->getOrCreateObjectPrototype(cx), global));
if (!proto
|| !JS_DefineProperties(cx, proto, SavedFrame::properties)
|| !JS_DefineFunctions(cx, proto, SavedFrame::methods)
|| !FreezeObject(cx, proto))
{
return nullptr;
}
// The only object with the SavedFrame::class_ that doesn't have a source
// should be the prototype.
proto->setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());
savedFrameProto.set(proto);
return savedFrameProto;
}
SavedFrame *
SavedStacks::createFrameFromLookup(JSContext *cx, SavedFrame::HandleLookup lookup)
{
RootedGlobalObject global(cx, cx->global());
assertSameCompartment(cx, global);
RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
RootedObject proto(cx, getOrCreateSavedFramePrototype(cx));
if (!proto)
return nullptr;
assertSameCompartment(cx, proto);
RootedObject global(cx, cx->compartment()->maybeGlobal());
if (!global)
return nullptr;
assertSameCompartment(cx, global);
RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto, global));
if (!frameObj)
return nullptr;

Просмотреть файл

@ -14,22 +14,16 @@
namespace js {
class SavedFrame;
typedef JS::Handle<SavedFrame*> HandleSavedFrame;
typedef JS::MutableHandle<SavedFrame*> MutableHandleSavedFrame;
typedef JS::Rooted<SavedFrame*> RootedSavedFrame;
class SavedFrame : public NativeObject {
friend class SavedStacks;
public:
static const Class class_;
static void finalize(FreeOp *fop, JSObject *obj);
static const JSPropertySpec protoAccessors[];
static const JSFunctionSpec protoFunctions[];
static const JSFunctionSpec staticFunctions[];
// Prototype methods and properties to be exposed to JS.
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static bool construct(JSContext *cx, unsigned argc, Value *vp);
static bool sourceProperty(JSContext *cx, unsigned argc, Value *vp);
static bool lineProperty(JSContext *cx, unsigned argc, Value *vp);
@ -59,7 +53,6 @@ class SavedFrame : public NativeObject {
class HandleLookup;
private:
static bool finishSavedFrameInit(JSContext *cx, HandleObject ctor, HandleObject proto);
void initFromLookup(HandleLookup lookup);
enum {
@ -84,13 +77,16 @@ class SavedFrame : public NativeObject {
// know that GC moved the parent and we need to update our private value and
// rekey the saved frame in its hash set. These two methods are helpers for
// this process.
bool parentMoved();
void updatePrivateParent();
bool parentMoved();
void updatePrivateParent();
static bool checkThis(JSContext *cx, CallArgs &args, const char *fnName,
MutableHandleSavedFrame frame);
static SavedFrame *checkThis(JSContext *cx, CallArgs &args, const char *fnName);
};
typedef JS::Handle<SavedFrame*> HandleSavedFrame;
typedef JS::MutableHandle<SavedFrame*> MutableHandleSavedFrame;
typedef JS::Rooted<SavedFrame*> RootedSavedFrame;
struct SavedFrame::HashPolicy
{
typedef SavedFrame::Lookup Lookup;
@ -110,6 +106,7 @@ class SavedStacks {
public:
SavedStacks()
: frames(),
savedFrameProto(nullptr),
allocationSamplingProbability(1.0),
allocationSkipCount(0),
// XXX: Initialize the RNG state to 0 so that random_initSeed is lazily
@ -132,6 +129,7 @@ class SavedStacks {
private:
SavedFrame::Set frames;
ReadBarrieredObject savedFrameProto;
double allocationSamplingProbability;
uint32_t allocationSkipCount;
uint64_t rngState;
@ -139,6 +137,9 @@ class SavedStacks {
bool insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame,
unsigned maxFrameCount = 0);
SavedFrame *getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup lookup);
// |SavedFrame.prototype| is created lazily and held weakly. It should only
// be accessed through this method.
JSObject *getOrCreateSavedFramePrototype(JSContext *cx);
SavedFrame *createFrameFromLookup(JSContext *cx, SavedFrame::HandleLookup lookup);
void chooseSamplingProbability(JSContext* cx);

Просмотреть файл

@ -507,7 +507,7 @@ public:
// Mapping of often used strings to jsid atoms that live 'forever'.
//
// To add a new string: add to this list and to XPCJSRuntime::mStrings
// at the top of XPCJSRuntime.cpp
// at the top of xpcjsruntime.cpp
enum {
IDX_CONSTRUCTOR = 0 ,
IDX_TO_STRING ,

Просмотреть файл

@ -1,108 +0,0 @@
// Bug 1117242: Test calling SavedFrame getters from globals that don't subsume
// that frame's principals.
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);
const lowP = Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal);
const midP = [lowP, "http://other.com"];
const highP = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
const low = new Cu.Sandbox(lowP);
const mid = new Cu.Sandbox(midP);
const high = new Cu.Sandbox(highP);
function run_test() {
// Test that the priveleged view of a SavedFrame from a subsumed compartment
// is the same view that the subsumed compartment gets. Create the following
// chain of function calls (with some intermediate system-principaled frames
// due to implementation):
//
// low.lowF -> mid.midF -> high.highF -> high.saveStack
//
// Where high.saveStack gets monkey patched to create stacks in each of our
// sandboxes.
Cu.evalInSandbox("function highF() { return saveStack(); }", high);
mid.highF = () => high.highF();
Cu.evalInSandbox("function midF() { return highF(); }", mid);
low.midF = () => mid.midF();
Cu.evalInSandbox("function lowF() { return midF(); }", low);
const expected = [
{
sandbox: low,
frames: ["lowF"],
},
{
sandbox: mid,
frames: ["midF", "lowF"],
},
{
sandbox: high,
frames: ["getSavedFrameInstanceFromSandbox",
"saveStack",
"highF",
"run_test/mid.highF",
"midF",
"run_test/low.midF",
"lowF",
"run_test",
"_execute_test",
null],
}
];
for (let { sandbox, frames } of expected) {
high.saveStack = function saveStack() {
return getSavedFrameInstanceFromSandbox(sandbox);
};
const xrayStack = low.lowF();
equal(xrayStack.functionDisplayName, "getSavedFrameInstanceFromSandbox",
"Xrays should always be able to see everything.");
let waived = Cu.waiveXrays(xrayStack);
do {
ok(frames.length,
"There should still be more expected frames while we have actual frames.");
equal(waived.functionDisplayName, frames.shift(),
"The waived wrapper should give us the stack's compartment's view.");
waived = waived.parent;
} while (waived);
}
}
// Get a SavedFrame instance from inside the given sandbox.
//
// We can't use Cu.getJSTestingFunctions().saveStack() because Cu isn't
// available to sandboxes that don't have the system principal. The easiest way
// to get the SavedFrame is to use the Debugger API to track allocation sites
// and then do an allocation.
function getSavedFrameInstanceFromSandbox(sandbox) {
const dbg = new Debugger(sandbox);
dbg.memory.trackingAllocationSites = true;
Cu.evalInSandbox("new Object", sandbox);
const allocs = dbg.memory.drainAllocationsLog();
dbg.memory.trackingAllocationSites = false;
ok(allocs[0], "We should observe the allocation");
const { frame } = allocs[0];
if (sandbox !== high) {
ok(Cu.isXrayWrapper(frame), "`frame` should be an xray...");
equal(Object.prototype.toString.call(Cu.waiveXrays(frame)),
"[object SavedFrame]",
"...and that xray should wrap a SavedFrame");
}
return frame;
}

Просмотреть файл

@ -108,4 +108,3 @@ head = head_watchdog.js
head = head_watchdog.js
[test_writeToGlobalPrototype.js]
[test_xrayed_iterator.js]
[test_xray_SavedFrame.js]

Просмотреть файл

@ -83,7 +83,6 @@ IsJSXraySupported(JSProtoKey key)
case JSProto_Array:
case JSProto_Function:
case JSProto_TypedArray:
case JSProto_SavedFrame:
return true;
default:
return false;