Bug 1181908. The CompileOptions constructor should properly copy the introducerFilename and isRunOnce state. r=luke

This commit is contained in:
Boris Zbarsky 2015-08-06 15:34:06 -07:00
parent 996744154e
commit 11d4b0065f
5 changed files with 104 additions and 41 deletions

View File

@ -99,6 +99,7 @@ using JS::NativeImpl;
using JS::OwningCompileOptions;
using JS::ReadOnlyCompileOptions;
using JS::SourceBufferHolder;
using JS::TransitiveCompileOptions;
using JS::Rooted;
using JS::RootedFunction;

View File

@ -5767,13 +5767,13 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
funbox->setMightAliasLocals(); // inherit mightAliasLocals from parent
MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript);
// Inherit most things (principals, version, etc) from the parent.
// Inherit most things (principals, version, etc) from the
// parent. Use default values for the rest.
Rooted<JSScript*> parent(cx, script);
CompileOptions options(cx, parser->options());
options.setMutedErrors(parent->mutedErrors())
.setNoScriptRval(false)
.setForEval(false)
.setVersion(parent->getVersion());
MOZ_ASSERT(parent->getVersion() == parser->options().version);
MOZ_ASSERT(parent->mutedErrors() == parser->options().mutedErrors());
const TransitiveCompileOptions& transitiveOptions = parser->options();
CompileOptions options(cx, transitiveOptions);
Rooted<JSObject*> enclosingScope(cx, enclosingStaticScope());
Rooted<JSObject*> sourceObject(cx, script->sourceObject());

View File

@ -3813,18 +3813,13 @@ AutoFile::open(JSContext* cx, const char* filename)
return true;
}
JSObject * const JS::ReadOnlyCompileOptions::nullObjectPtr = nullptr;
void
JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions& rhs)
JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOptions& rhs)
{
mutedErrors_ = rhs.mutedErrors_;
version = rhs.version;
versionSet = rhs.versionSet;
utf8 = rhs.utf8;
lineno = rhs.lineno;
column = rhs.column;
forEval = rhs.forEval;
noScriptRval = rhs.noScriptRval;
selfHostingMode = rhs.selfHostingMode;
canLazilyParse = rhs.canLazilyParse;
strictOption = rhs.strictOption;
@ -3838,6 +3833,17 @@ JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions& rhs)
introductionLineno = rhs.introductionLineno;
introductionOffset = rhs.introductionOffset;
hasIntroductionInfo = rhs.hasIntroductionInfo;
};
void
JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions& rhs)
{
copyPODTransitiveOptions(rhs);
lineno = rhs.lineno;
column = rhs.column;
isRunOnce = rhs.isRunOnce;
forEval = rhs.forEval;
noScriptRval = rhs.noScriptRval;
}
JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx)
@ -3862,7 +3868,6 @@ JS::OwningCompileOptions::copy(JSContext* cx, const ReadOnlyCompileOptions& rhs)
{
copyPODOptions(rhs);
setMutedErrors(rhs.mutedErrors());
setElement(rhs.element());
setElementAttributeName(rhs.elementAttributeName());
setIntroductionScript(rhs.introductionScript());
@ -4270,8 +4275,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
MOZ_ASSERT_IF(!enclosingDynamicScope->is<GlobalObject>(),
HasNonSyntacticStaticScopeChain(enclosingStaticScope));
CompileOptions options(cx, optionsArg);
if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingStaticScope))
if (!frontend::CompileFunctionBody(cx, fun, optionsArg, formals, srcBuf, enclosingStaticScope))
return false;
return true;

View File

@ -3384,10 +3384,20 @@ namespace JS {
* it doesn't care who owns them, or what's keeping them alive. It does its own
* addrefs/copies/tracing/etc.
*
* So, we have a class hierarchy that reflects these three use cases:
* Furthermore, in some cases compile options are propagated from one entity to
* another (e.g. from a scriipt to a function defined in that script). This
* involves copying over some, but not all, of the options.
*
* - ReadOnlyCompileOptions is the common base class. It can be used by code
* that simply needs to access options set elsewhere, like the compiler.
* So, we have a class hierarchy that reflects these four use cases:
*
* - TransitiveCompileOptions is the common base class, representing options
* that should get propagated from a script to functions defined in that
* script. This is never instantiated directly.
*
* - ReadOnlyCompileOptions is the only subclass of TransitiveCompileOptions,
* representing a full set of compile options. It can be used by code that
* simply needs to access options set elsewhere, like the compiler. This,
* again, is never instantiated directly.
*
* - The usual CompileOptions class must be stack-allocated, and holds
* non-owning references to the filename, element, and so on. It's derived
@ -3401,15 +3411,11 @@ namespace JS {
/*
* The common base class for the CompileOptions hierarchy.
*
* Use this in code that only needs to access compilation options created
* elsewhere, like the compiler. Don't instantiate this class (the constructor
* is protected anyway); instead, create instances only of the derived classes:
* CompileOptions and OwningCompileOptions.
* Use this in code that needs to propagate compile options from one compilation
* unit to another.
*/
class JS_FRIEND_API(ReadOnlyCompileOptions)
class JS_FRIEND_API(TransitiveCompileOptions)
{
friend class CompileOptions;
protected:
// The Web Platform allows scripts to be loaded from arbitrary cross-origin
// sources. This allows an attack by which a malicious website loads a
@ -3431,7 +3437,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
// is unusable until that's set to something more specific; the derived
// classes' constructors take care of that, in ways appropriate to their
// purpose.
ReadOnlyCompileOptions()
TransitiveCompileOptions()
: mutedErrors_(false),
filename_(nullptr),
introducerFilename_(nullptr),
@ -3439,11 +3445,6 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
version(JSVERSION_UNKNOWN),
versionSet(false),
utf8(false),
lineno(1),
column(0),
isRunOnce(false),
forEval(false),
noScriptRval(false),
selfHostingMode(false),
canLazilyParse(true),
strictOption(false),
@ -3461,7 +3462,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
// Set all POD options (those not requiring reference counts, copies,
// rooting, or other hand-holding) to their values in |rhs|.
void copyPODOptions(const ReadOnlyCompileOptions& rhs);
void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs);
public:
// Read-only accessors for non-POD options. The proper way to set these
@ -3478,12 +3479,6 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
JSVersion version;
bool versionSet;
bool utf8;
unsigned lineno;
unsigned column;
// isRunOnce only applies to non-function scripts.
bool isRunOnce;
bool forEval;
bool noScriptRval;
bool selfHostingMode;
bool canLazilyParse;
bool strictOption;
@ -3502,7 +3497,55 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
bool hasIntroductionInfo;
private:
static JSObject * const nullObjectPtr;
void operator=(const TransitiveCompileOptions&) = delete;
};
/*
* The class representing a full set of compile options.
*
* Use this in code that only needs to access compilation options created
* elsewhere, like the compiler. Don't instantiate this class (the constructor
* is protected anyway); instead, create instances only of the derived classes:
* CompileOptions and OwningCompileOptions.
*/
class JS_FRIEND_API(ReadOnlyCompileOptions) : public TransitiveCompileOptions
{
friend class CompileOptions;
protected:
ReadOnlyCompileOptions()
: TransitiveCompileOptions(),
lineno(1),
column(0),
isRunOnce(false),
forEval(false),
noScriptRval(false)
{ }
// Set all POD options (those not requiring reference counts, copies,
// rooting, or other hand-holding) to their values in |rhs|.
void copyPODOptions(const ReadOnlyCompileOptions& rhs);
public:
// Read-only accessors for non-POD options. The proper way to set these
// depends on the derived type.
bool mutedErrors() const { return mutedErrors_; }
const char* filename() const { return filename_; }
const char* introducerFilename() const { return introducerFilename_; }
const char16_t* sourceMapURL() const { return sourceMapURL_; }
virtual JSObject* element() const = 0;
virtual JSString* elementAttributeName() const = 0;
virtual JSScript* introductionScript() const = 0;
// POD options.
unsigned lineno;
unsigned column;
// isRunOnce only applies to non-function scripts.
bool isRunOnce;
bool forEval;
bool noScriptRval;
private:
void operator=(const ReadOnlyCompileOptions&) = delete;
};
@ -3617,8 +3660,22 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti
{
copyPODOptions(rhs);
mutedErrors_ = rhs.mutedErrors_;
filename_ = rhs.filename();
introducerFilename_ = rhs.introducerFilename();
sourceMapURL_ = rhs.sourceMapURL();
elementRoot = rhs.element();
elementAttributeNameRoot = rhs.elementAttributeName();
introductionScriptRoot = rhs.introductionScript();
}
CompileOptions(js::ContextFriendFields* cx, const TransitiveCompileOptions& rhs)
: ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx),
introductionScriptRoot(cx)
{
copyPODTransitiveOptions(rhs);
filename_ = rhs.filename();
introducerFilename_ = rhs.introducerFilename();
sourceMapURL_ = rhs.sourceMapURL();
elementRoot = rhs.element();
elementAttributeNameRoot = rhs.elementAttributeName();

View File

@ -37,6 +37,7 @@ class Rooted;
class JS_FRIEND_API(CompileOptions);
class JS_FRIEND_API(ReadOnlyCompileOptions);
class JS_FRIEND_API(OwningCompileOptions);
class JS_FRIEND_API(TransitiveCompileOptions);
class JS_PUBLIC_API(CompartmentOptions);
class Value;