mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 725576 - serialize principals only once per top-level script. r=luke
--HG-- extra : rebase_source : 92b82ff8a8d03d6176bf1e43329a59b77ca83de4
This commit is contained in:
parent
180e2b965e
commit
3b9873045c
@ -155,7 +155,7 @@ js::IsIdentifier(JSLinearString *str)
|
||||
/* Initialize members that aren't initialized in |init|. */
|
||||
TokenStream::TokenStream(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin)
|
||||
: tokens(), cursor(), lookahead(), flags(), listenerTSData(), tokenbuf(cx),
|
||||
cx(cx), originPrincipals(originPrin ? originPrin : prin)
|
||||
cx(cx), originPrincipals(JSScript::normalizeOriginPrincipals(prin, originPrin))
|
||||
{
|
||||
if (originPrincipals)
|
||||
JSPRINCIPALS_HOLD(cx, originPrincipals);
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "tests.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsxdrapi.h"
|
||||
|
||||
BEGIN_TEST(test_cloneScript)
|
||||
{
|
||||
@ -48,3 +50,122 @@ BEGIN_TEST(test_cloneScript)
|
||||
return true;
|
||||
}
|
||||
END_TEST(test_cloneScript)
|
||||
|
||||
void
|
||||
DestroyPrincipals(JSContext *cx, JSPrincipals *principals)
|
||||
{
|
||||
delete principals;
|
||||
}
|
||||
|
||||
struct Principals : public JSPrincipals
|
||||
{
|
||||
public:
|
||||
Principals(const char *name)
|
||||
{
|
||||
refcount = 0;
|
||||
codebase = const_cast<char *>(name);
|
||||
destroy = DestroyPrincipals;
|
||||
subsume = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
class AutoDropPrincipals
|
||||
{
|
||||
JSContext *cx;
|
||||
JSPrincipals *principals;
|
||||
|
||||
public:
|
||||
AutoDropPrincipals(JSContext *cx, JSPrincipals *principals)
|
||||
: cx(cx), principals(principals)
|
||||
{
|
||||
JSPRINCIPALS_HOLD(cx, principals);
|
||||
}
|
||||
|
||||
~AutoDropPrincipals()
|
||||
{
|
||||
JSPRINCIPALS_DROP(cx, principals);
|
||||
}
|
||||
};
|
||||
|
||||
JSBool
|
||||
TranscodePrincipals(JSXDRState *xdr, JSPrincipals **principalsp)
|
||||
{
|
||||
return JS_XDRBytes(xdr, reinterpret_cast<char *>(principalsp), sizeof(*principalsp));
|
||||
}
|
||||
|
||||
BEGIN_TEST(test_cloneScriptWithPrincipals)
|
||||
{
|
||||
JSSecurityCallbacks cbs = {
|
||||
NULL,
|
||||
TranscodePrincipals,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
JS_SetRuntimeSecurityCallbacks(rt, &cbs);
|
||||
|
||||
JSPrincipals *principalsA = new Principals("A");
|
||||
AutoDropPrincipals dropA(cx, principalsA);
|
||||
JSPrincipals *principalsB = new Principals("B");
|
||||
AutoDropPrincipals dropB(cx, principalsB);
|
||||
|
||||
JSObject *A, *B;
|
||||
|
||||
CHECK(A = createGlobal(principalsA));
|
||||
CHECK(B = createGlobal(principalsB));
|
||||
|
||||
const char *argnames[] = { "arg" };
|
||||
const char *source = "return function() { return arg; }";
|
||||
|
||||
JSObject *obj;
|
||||
|
||||
// Compile in A
|
||||
{
|
||||
JSAutoEnterCompartment a;
|
||||
if (!a.enter(cx, A))
|
||||
return false;
|
||||
|
||||
JSFunction *fun;
|
||||
CHECK(fun = JS_CompileFunctionForPrincipals(cx, A, principalsA, "f",
|
||||
mozilla::ArrayLength(argnames), argnames,
|
||||
source, strlen(source), __FILE__, 1));
|
||||
|
||||
JSScript *script;
|
||||
CHECK(script = JS_GetFunctionScript(cx, fun));
|
||||
|
||||
CHECK(JS_GetScriptPrincipals(cx, script) == principalsA);
|
||||
CHECK(obj = JS_GetFunctionObject(fun));
|
||||
}
|
||||
|
||||
// Clone into B
|
||||
{
|
||||
JSAutoEnterCompartment b;
|
||||
if (!b.enter(cx, B))
|
||||
return false;
|
||||
|
||||
JSObject *cloned;
|
||||
CHECK(cloned = JS_CloneFunctionObject(cx, obj, B));
|
||||
|
||||
JSFunction *fun;
|
||||
CHECK(fun = JS_ValueToFunction(cx, JS::ObjectValue(*cloned)));
|
||||
|
||||
JSScript *script;
|
||||
CHECK(script = JS_GetFunctionScript(cx, fun));
|
||||
|
||||
CHECK(JS_GetScriptPrincipals(cx, script) == principalsB);
|
||||
|
||||
JS::Value v;
|
||||
JS::Value args[] = { JS::Int32Value(1) };
|
||||
CHECK(JS_CallFunctionValue(cx, B, JS::ObjectValue(*cloned), 1, args, &v));
|
||||
CHECK(v.isObject());
|
||||
|
||||
JSObject *funobj = &v.toObject();
|
||||
CHECK(JS_ObjectIsFunction(cx, funobj));
|
||||
CHECK(fun = JS_ValueToFunction(cx, v));
|
||||
CHECK(script = JS_GetFunctionScript(cx, fun));
|
||||
CHECK(JS_GetScriptPrincipals(cx, script) == principalsB);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(test_cloneScriptWithPrincipals)
|
||||
|
@ -157,10 +157,40 @@ Error(JSContext *cx, const char (&input)[N])
|
||||
AutoInflatedString str(cx);
|
||||
jsval dummy;
|
||||
str = input;
|
||||
CHECK(!JS_ParseJSON(cx, str.chars(), str.length(), &dummy));
|
||||
JS_ClearPendingException(cx);
|
||||
|
||||
ContextPrivate p = {0, 0};
|
||||
CHECK(!JS_GetContextPrivate(cx));
|
||||
JS_SetContextPrivate(cx, &p);
|
||||
JSErrorReporter old = JS_SetErrorReporter(cx, reportJSONEror);
|
||||
JSBool ok = JS_ParseJSON(cx, str.chars(), str.length(), &dummy);
|
||||
JS_SetErrorReporter(cx, old);
|
||||
JS_SetContextPrivate(cx, NULL);
|
||||
|
||||
CHECK(!ok);
|
||||
CHECK(!p.unexpectedErrorCount);
|
||||
CHECK(p.expectedErrorCount == 1);
|
||||
|
||||
/* We do not execute JS, so there should be no exception thrown. */
|
||||
CHECK(!JS_IsExceptionPending(cx));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ContextPrivate {
|
||||
unsigned unexpectedErrorCount;
|
||||
unsigned expectedErrorCount;
|
||||
};
|
||||
|
||||
static void
|
||||
reportJSONEror(JSContext *cx, const char *message, JSErrorReport *report)
|
||||
{
|
||||
ContextPrivate *p = static_cast<ContextPrivate *>(JS_GetContextPrivate(cx));
|
||||
if (report->errorNumber == JSMSG_JSON_BAD_PARSE)
|
||||
p->expectedErrorCount++;
|
||||
else
|
||||
p->unexpectedErrorCount++;
|
||||
}
|
||||
|
||||
END_TEST(testParseJSON_error)
|
||||
|
||||
static JSBool
|
||||
|
@ -6,6 +6,236 @@
|
||||
#include "jsscript.h"
|
||||
#include "jsxdrapi.h"
|
||||
|
||||
static JSScript *
|
||||
CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
|
||||
JSPrincipals *principals, JSPrincipals *originPrincipals,
|
||||
const char *bytes, size_t nbytes,
|
||||
const char *filename, uintN lineno,
|
||||
JSVersion version)
|
||||
{
|
||||
size_t nchars;
|
||||
if (!JS_DecodeBytes(cx, bytes, nbytes, NULL, &nchars))
|
||||
return NULL;
|
||||
jschar *chars = static_cast<jschar *>(JS_malloc(cx, nchars * sizeof(jschar)));
|
||||
if (!chars)
|
||||
return NULL;
|
||||
JS_ALWAYS_TRUE(JS_DecodeBytes(cx, bytes, nbytes, chars, &nchars));
|
||||
JSScript *script = JS_CompileUCScriptForPrincipalsVersionOrigin(cx, obj,
|
||||
principals, originPrincipals,
|
||||
chars, nchars,
|
||||
filename, lineno, version);
|
||||
free(chars);
|
||||
return script;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *
|
||||
FreezeThawImpl(JSContext *cx, T *thing, JSBool (*xdrAction)(JSXDRState *xdr, T **))
|
||||
{
|
||||
// freeze
|
||||
JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
|
||||
if (!w)
|
||||
return NULL;
|
||||
|
||||
void *memory = NULL;
|
||||
uint32_t nbytes;
|
||||
if (xdrAction(w, &thing)) {
|
||||
void *p = JS_XDRMemGetData(w, &nbytes);
|
||||
if (p) {
|
||||
memory = JS_malloc(cx, nbytes);
|
||||
if (memory)
|
||||
memcpy(memory, p, nbytes);
|
||||
}
|
||||
}
|
||||
JS_XDRDestroy(w);
|
||||
if (!memory)
|
||||
return NULL;
|
||||
|
||||
// thaw
|
||||
JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
|
||||
JS_XDRMemSetData(r, memory, nbytes);
|
||||
if (!xdrAction(r, &thing))
|
||||
thing = NULL;
|
||||
JS_XDRDestroy(r); // this frees `memory
|
||||
return thing;
|
||||
}
|
||||
|
||||
static JSScript *
|
||||
FreezeThaw(JSContext *cx, JSScript *script)
|
||||
{
|
||||
return FreezeThawImpl(cx, script, JS_XDRScript);
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
FreezeThaw(JSContext *cx, JSObject *funobj)
|
||||
{
|
||||
return FreezeThawImpl(cx, funobj, JS_XDRFunctionObject);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
SubsumePrincipals(JSPrincipals *, JSPrincipals *)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSPrincipals testPrincipals[] = {
|
||||
{ const_cast<char *>("foo.bar"), 1, NULL, SubsumePrincipals },
|
||||
{ const_cast<char *>("dot.com"), 1, NULL, SubsumePrincipals },
|
||||
};
|
||||
|
||||
static JSBool
|
||||
CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
TranscodePrincipals(JSXDRState *xdr, JSPrincipals **principalsp)
|
||||
{
|
||||
uint32_t index;
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
JSPrincipals *p = *principalsp;
|
||||
for (index = 0; ; ++index) {
|
||||
if (index == mozilla::ArrayLength(testPrincipals))
|
||||
return false;
|
||||
if (p == &testPrincipals[index])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!JS_XDRUint32(xdr, &index))
|
||||
return false;
|
||||
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
if (index >= mozilla::ArrayLength(testPrincipals))
|
||||
return false;
|
||||
*principalsp = &testPrincipals[index];
|
||||
JSPRINCIPALS_HOLD(xdr->cx, *principalsp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BEGIN_TEST(testXDR_principals)
|
||||
{
|
||||
static JSSecurityCallbacks seccb = {
|
||||
CheckAccess,
|
||||
TranscodePrincipals,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
JS_SetRuntimeSecurityCallbacks(rt, &seccb);
|
||||
|
||||
JSScript *script;
|
||||
for (int i = TEST_FIRST; i != TEST_END; ++i) {
|
||||
script = createScriptViaXDR(NULL, NULL, i);
|
||||
CHECK(script);
|
||||
CHECK(!JS_GetScriptPrincipals(cx, script));
|
||||
CHECK(!JS_GetScriptOriginPrincipals(cx, script));
|
||||
|
||||
script = createScriptViaXDR(NULL, NULL, i);
|
||||
CHECK(script);
|
||||
CHECK(!JS_GetScriptPrincipals(cx, script));
|
||||
CHECK(!JS_GetScriptOriginPrincipals(cx, script));
|
||||
|
||||
script = createScriptViaXDR(&testPrincipals[0], NULL, i);
|
||||
CHECK(script);
|
||||
CHECK(JS_GetScriptPrincipals(cx, script) == &testPrincipals[0]);
|
||||
CHECK(JS_GetScriptOriginPrincipals(cx, script) == &testPrincipals[0]);
|
||||
|
||||
script = createScriptViaXDR(&testPrincipals[0], &testPrincipals[0], i);
|
||||
CHECK(script);
|
||||
CHECK(JS_GetScriptPrincipals(cx, script) == &testPrincipals[0]);
|
||||
CHECK(JS_GetScriptOriginPrincipals(cx, script) == &testPrincipals[0]);
|
||||
|
||||
script = createScriptViaXDR(&testPrincipals[0], &testPrincipals[1], i);
|
||||
CHECK(script);
|
||||
CHECK(JS_GetScriptPrincipals(cx, script) == &testPrincipals[0]);
|
||||
CHECK(JS_GetScriptOriginPrincipals(cx, script) == &testPrincipals[1]);
|
||||
|
||||
script = createScriptViaXDR(NULL, &testPrincipals[1], i);
|
||||
CHECK(script);
|
||||
CHECK(!JS_GetScriptPrincipals(cx, script));
|
||||
CHECK(JS_GetScriptOriginPrincipals(cx, script) == &testPrincipals[1]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum TestCase {
|
||||
TEST_FIRST,
|
||||
TEST_SCRIPT = TEST_FIRST,
|
||||
TEST_FUNCTION,
|
||||
TEST_SERIALIZED_FUNCTION,
|
||||
TEST_END
|
||||
};
|
||||
|
||||
JSScript *createScriptViaXDR(JSPrincipals *prin, JSPrincipals *orig, int testCase)
|
||||
{
|
||||
const char src[] =
|
||||
"function f() { return 1; }\n"
|
||||
"f;\n";
|
||||
|
||||
JSScript *script = CompileScriptForPrincipalsVersionOrigin(cx, global, prin, orig,
|
||||
src, strlen(src), "test", 1,
|
||||
JSVERSION_DEFAULT);
|
||||
if (!script)
|
||||
return NULL;
|
||||
|
||||
if (testCase == TEST_SCRIPT || testCase == TEST_SERIALIZED_FUNCTION) {
|
||||
script = FreezeThaw(cx, script);
|
||||
if (!script)
|
||||
return NULL;
|
||||
if (testCase == TEST_SCRIPT)
|
||||
return script;
|
||||
}
|
||||
|
||||
JS::Value v;
|
||||
JSBool ok = JS_ExecuteScript(cx, global, script, &v);
|
||||
if (!ok || !v.isObject())
|
||||
return NULL;
|
||||
JSObject *funobj = &v.toObject();
|
||||
if (testCase == TEST_FUNCTION) {
|
||||
funobj = FreezeThaw(cx, funobj);
|
||||
if (!funobj)
|
||||
return NULL;
|
||||
}
|
||||
return JS_GetFunctionScript(cx, JS_GetObjectFunction(funobj));
|
||||
}
|
||||
|
||||
END_TEST(testXDR_principals)
|
||||
|
||||
BEGIN_TEST(testXDR_atline)
|
||||
{
|
||||
JS_ToggleOptions(cx, JSOPTION_ATLINE);
|
||||
CHECK(JS_GetOptions(cx) & JSOPTION_ATLINE);
|
||||
|
||||
const char src[] =
|
||||
"//@line 100 \"foo\"\n"
|
||||
"function nested() { }\n"
|
||||
"//@line 200 \"bar\"\n"
|
||||
"nested;\n";
|
||||
|
||||
JSScript *script = JS_CompileScript(cx, global, src, strlen(src), "internal", 1);
|
||||
CHECK(script);
|
||||
CHECK(script = FreezeThaw(cx, script));
|
||||
CHECK(!strcmp("bar", JS_GetScriptFilename(cx, script)));
|
||||
|
||||
JS::Value v;
|
||||
JSBool ok = JS_ExecuteScript(cx, global, script, &v);
|
||||
CHECK(ok);
|
||||
CHECK(v.isObject());
|
||||
|
||||
JSObject *funobj = &v.toObject();
|
||||
script = JS_GetFunctionScript(cx, JS_GetObjectFunction(funobj));
|
||||
CHECK(!strcmp("foo", JS_GetScriptFilename(cx, script)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
END_TEST(testXDR_atline)
|
||||
|
||||
BEGIN_TEST(testXDR_bug506491)
|
||||
{
|
||||
const char *s =
|
||||
@ -19,24 +249,8 @@ BEGIN_TEST(testXDR_bug506491)
|
||||
JSScript *script = JS_CompileScript(cx, global, s, strlen(s), __FILE__, __LINE__);
|
||||
CHECK(script);
|
||||
|
||||
// freeze
|
||||
JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
|
||||
CHECK(w);
|
||||
CHECK(JS_XDRScript(w, &script));
|
||||
uint32_t nbytes;
|
||||
void *p = JS_XDRMemGetData(w, &nbytes);
|
||||
CHECK(p);
|
||||
void *frozen = JS_malloc(cx, nbytes);
|
||||
CHECK(frozen);
|
||||
js_memcpy(frozen, p, nbytes);
|
||||
JS_XDRDestroy(w);
|
||||
|
||||
// thaw
|
||||
script = NULL;
|
||||
JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
|
||||
JS_XDRMemSetData(r, frozen, nbytes);
|
||||
CHECK(JS_XDRScript(r, &script));
|
||||
JS_XDRDestroy(r); // this frees `frozen`
|
||||
script = FreezeThaw(cx, script);
|
||||
CHECK(script);
|
||||
|
||||
// execute
|
||||
jsvalRoot v2(cx);
|
||||
@ -59,24 +273,8 @@ BEGIN_TEST(testXDR_bug516827)
|
||||
JSScript *script = JS_CompileScript(cx, global, "", 0, __FILE__, __LINE__);
|
||||
CHECK(script);
|
||||
|
||||
// freeze
|
||||
JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
|
||||
CHECK(w);
|
||||
CHECK(JS_XDRScript(w, &script));
|
||||
uint32_t nbytes;
|
||||
void *p = JS_XDRMemGetData(w, &nbytes);
|
||||
CHECK(p);
|
||||
void *frozen = JS_malloc(cx, nbytes);
|
||||
CHECK(frozen);
|
||||
js_memcpy(frozen, p, nbytes);
|
||||
JS_XDRDestroy(w);
|
||||
|
||||
// thaw
|
||||
script = NULL;
|
||||
JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
|
||||
JS_XDRMemSetData(r, frozen, nbytes);
|
||||
CHECK(JS_XDRScript(r, &script));
|
||||
JS_XDRDestroy(r); // this frees `frozen`
|
||||
script = FreezeThaw(cx, script);
|
||||
CHECK(script);
|
||||
|
||||
// execute with null result meaning no result wanted
|
||||
CHECK(JS_ExecuteScript(cx, global, script, NULL));
|
||||
|
@ -4835,7 +4835,8 @@ JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
|
||||
}
|
||||
|
||||
static JSScript *
|
||||
CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||
CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
|
||||
JSPrincipals *principals, JSPrincipals *originPrincipals,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno, JSVersion version)
|
||||
{
|
||||
@ -4846,7 +4847,7 @@ CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *p
|
||||
AutoLastFrameCheck lfc(cx);
|
||||
|
||||
uint32_t tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_SCRIPT_GLOBAL;
|
||||
return frontend::CompileScript(cx, obj, NULL, principals, NULL, tcflags,
|
||||
return frontend::CompileScript(cx, obj, NULL, principals, originPrincipals, tcflags,
|
||||
chars, length, filename, lineno, version);
|
||||
}
|
||||
|
||||
@ -4858,8 +4859,21 @@ JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
|
||||
JSVersion version)
|
||||
{
|
||||
AutoVersionAPI avi(cx, version);
|
||||
return CompileUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, filename, lineno,
|
||||
avi.version());
|
||||
return CompileUCScriptForPrincipalsCommon(cx, obj, principals, NULL, chars, length,
|
||||
filename, lineno, avi.version());
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
JS_CompileUCScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
|
||||
JSPrincipals *principals,
|
||||
JSPrincipals *originPrincipals,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno,
|
||||
JSVersion version)
|
||||
{
|
||||
AutoVersionAPI avi(cx, version);
|
||||
return CompileUCScriptForPrincipalsCommon(cx, obj, principals, originPrincipals,
|
||||
chars, length, filename, lineno, avi.version());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSScript *)
|
||||
@ -4867,8 +4881,8 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *prin
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno)
|
||||
{
|
||||
return CompileUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, filename, lineno,
|
||||
cx->findVersion());
|
||||
return CompileUCScriptForPrincipalsCommon(cx, obj, principals, NULL, chars, length,
|
||||
filename, lineno, cx->findVersion());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSScript *)
|
||||
|
@ -4258,6 +4258,17 @@ JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno,
|
||||
JSVersion version);
|
||||
/*
|
||||
* If originPrincipals is null, then the value of principals is used as origin
|
||||
* principals for the compiled script.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
JS_CompileUCScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
|
||||
JSPrincipals *principals,
|
||||
JSPrincipals *originPrincipals,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno,
|
||||
JSVersion version);
|
||||
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
JS_CompileUTF8File(JSContext *cx, JSObject *obj, const char *filename);
|
||||
@ -4422,7 +4433,8 @@ JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
|
||||
* A script's originPrincipals may be retrieved through the debug API (via
|
||||
* JS_GetScriptOriginPrincipals) and the originPrincipals are transitively
|
||||
* assigned to any nested scripts (including scripts dynamically created via
|
||||
* eval and the Function constructor).
|
||||
* eval and the Function constructor). If originPrincipals is null, then the
|
||||
* value of principals is used as origin principals for the script.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_EvaluateUCScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
|
||||
|
@ -441,7 +441,9 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
SavedCallerFun,
|
||||
StrictModeCode,
|
||||
UsesEval,
|
||||
UsesArguments
|
||||
UsesArguments,
|
||||
OwnFilename,
|
||||
SharedFilename
|
||||
};
|
||||
|
||||
uint32_t length, lineno, nslots;
|
||||
@ -449,17 +451,12 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
uint32_t prologLength, version, encodedClosedCount;
|
||||
uint16_t nClosedArgs = 0, nClosedVars = 0;
|
||||
uint32_t nTypeSets = 0;
|
||||
uint32_t encodeable, sameOriginPrincipals;
|
||||
JSSecurityCallbacks *callbacks;
|
||||
uint32_t scriptBits = 0;
|
||||
|
||||
JSContext *cx = xdr->cx;
|
||||
JSScript *script;
|
||||
nsrcnotes = ntrynotes = natoms = nobjects = nregexps = nconsts = 0;
|
||||
jssrcnote *notes = NULL;
|
||||
XDRScriptState *state = xdr->state;
|
||||
|
||||
JS_ASSERT(state);
|
||||
|
||||
/* XDR arguments, local vars, and upvars. */
|
||||
uint16_t nargs, nvars, nupvars;
|
||||
@ -611,6 +608,12 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
scriptBits |= (1 << UsesEval);
|
||||
if (script->usesArguments)
|
||||
scriptBits |= (1 << UsesArguments);
|
||||
if (script->filename) {
|
||||
scriptBits |= (script->filename != xdr->sharedFilename)
|
||||
? (1 << OwnFilename)
|
||||
: (1 << SharedFilename);
|
||||
}
|
||||
|
||||
JS_ASSERT(!script->compileAndGo);
|
||||
JS_ASSERT(!script->hasSingletons);
|
||||
}
|
||||
@ -686,52 +689,39 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xdr->mode == JSXDR_DECODE && state->filename) {
|
||||
if (!state->filenameSaved) {
|
||||
const char *filename = state->filename;
|
||||
filename = SaveScriptFilename(xdr->cx, filename);
|
||||
xdr->cx->free_((void *) state->filename);
|
||||
state->filename = filename;
|
||||
state->filenameSaved = true;
|
||||
if (!filename)
|
||||
if (scriptBits & (1 << OwnFilename)) {
|
||||
char *filename;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
filename = const_cast<char *>(script->filename);
|
||||
if (!JS_XDRCString(xdr, &filename))
|
||||
return false;
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
script->filename = SaveScriptFilename(xdr->cx, filename);
|
||||
Foreground::free_(filename);
|
||||
if (!script->filename)
|
||||
return false;
|
||||
if (!xdr->sharedFilename)
|
||||
xdr->sharedFilename = script->filename;
|
||||
}
|
||||
script->filename = state->filename;
|
||||
} else if (scriptBits & (1 << SharedFilename)) {
|
||||
JS_ASSERT(xdr->sharedFilename);
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
script->filename = xdr->sharedFilename;
|
||||
}
|
||||
|
||||
JS_ASSERT_IF(xdr->mode == JSXDR_ENCODE, state->filename == script->filename);
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
JS_ASSERT(!script->principals);
|
||||
JS_ASSERT(!script->originPrincipals);
|
||||
|
||||
callbacks = JS_GetSecurityCallbacks(cx);
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
encodeable = script->principals && callbacks && callbacks->principalsTranscoder;
|
||||
|
||||
if (!JS_XDRUint32(xdr, &encodeable))
|
||||
return false;
|
||||
|
||||
if (encodeable) {
|
||||
if (!callbacks || !callbacks->principalsTranscoder) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_CANT_DECODE_PRINCIPALS);
|
||||
return false;
|
||||
/* The origin principals must be normalized at this point. */
|
||||
JS_ASSERT_IF(script->principals, script->originPrincipals);
|
||||
if (xdr->principals) {
|
||||
script->principals = xdr->principals;
|
||||
JSPRINCIPALS_HOLD(cx, xdr->principals);
|
||||
}
|
||||
|
||||
if (!callbacks->principalsTranscoder(xdr, &script->principals))
|
||||
return false;
|
||||
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
sameOriginPrincipals = script->principals == script->originPrincipals;
|
||||
|
||||
if (!JS_XDRUint32(xdr, &sameOriginPrincipals))
|
||||
return false;
|
||||
|
||||
if (sameOriginPrincipals) {
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
script->originPrincipals = script->principals;
|
||||
JSPRINCIPALS_HOLD(cx, script->originPrincipals);
|
||||
}
|
||||
} else {
|
||||
if (!callbacks->principalsTranscoder(xdr, &script->originPrincipals))
|
||||
return false;
|
||||
if (xdr->originPrincipals) {
|
||||
script->originPrincipals = xdr->originPrincipals;
|
||||
JSPRINCIPALS_HOLD(cx, xdr->originPrincipals);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1717,29 +1707,8 @@ CurrentScriptFileLineOriginSlow(JSContext *cx, const char **file, uintN *linenop
|
||||
*origin = script->originPrincipals;
|
||||
}
|
||||
|
||||
class DisablePrincipalsTranscoding {
|
||||
JSSecurityCallbacks *callbacks;
|
||||
JSPrincipalsTranscoder temp;
|
||||
|
||||
public:
|
||||
DisablePrincipalsTranscoding(JSContext *cx)
|
||||
: callbacks(JS_GetRuntimeSecurityCallbacks(cx->runtime)),
|
||||
temp(NULL)
|
||||
{
|
||||
if (callbacks) {
|
||||
temp = callbacks->principalsTranscoder;
|
||||
callbacks->principalsTranscoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~DisablePrincipalsTranscoding() {
|
||||
if (callbacks)
|
||||
callbacks->principalsTranscoder = temp;
|
||||
}
|
||||
};
|
||||
|
||||
class AutoJSXDRState {
|
||||
public:
|
||||
public:
|
||||
AutoJSXDRState(JSXDRState *x
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: xdr(x)
|
||||
@ -1756,7 +1725,12 @@ public:
|
||||
return xdr;
|
||||
}
|
||||
|
||||
private:
|
||||
JSXDRState* operator->() const
|
||||
{
|
||||
return xdr;
|
||||
}
|
||||
|
||||
private:
|
||||
JSXDRState *const xdr;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
@ -1766,18 +1740,11 @@ CloneScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(cx->compartment != script->compartment());
|
||||
|
||||
// serialize script
|
||||
/* Serialize script. */
|
||||
AutoJSXDRState w(JS_XDRNewMem(cx, JSXDR_ENCODE));
|
||||
if (!w)
|
||||
return NULL;
|
||||
|
||||
// we don't want gecko to transcribe our principals for us
|
||||
DisablePrincipalsTranscoding disable(cx);
|
||||
|
||||
XDRScriptState wstate(w);
|
||||
#ifdef DEBUG
|
||||
wstate.filename = script->filename;
|
||||
#endif
|
||||
if (!XDRScript(w, &script))
|
||||
return NULL;
|
||||
|
||||
@ -1786,35 +1753,25 @@ CloneScript(JSContext *cx, JSScript *script)
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
// de-serialize script
|
||||
/* De-serialize script. */
|
||||
AutoJSXDRState r(JS_XDRNewMem(cx, JSXDR_DECODE));
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
// Hand p off from w to r. Don't want them to share the data
|
||||
// mem, lest they both try to free it in JS_XDRDestroy
|
||||
/*
|
||||
* Hand p off from w to r. Don't want them to share the data mem, lest
|
||||
* they both try to free it in JS_XDRDestroy.
|
||||
*/
|
||||
JS_XDRMemSetData(r, p, nbytes);
|
||||
JS_XDRMemSetData(w, NULL, 0);
|
||||
|
||||
XDRScriptState rstate(r);
|
||||
rstate.filename = script->filename;
|
||||
rstate.filenameSaved = true;
|
||||
|
||||
r->principals = cx->compartment->principals;
|
||||
r->originPrincipals = JSScript::normalizeOriginPrincipals(cx->compartment->principals,
|
||||
script->originPrincipals);
|
||||
JSScript *newScript = NULL;
|
||||
if (!XDRScript(r, &newScript))
|
||||
return NULL;
|
||||
|
||||
// set the proper principals for the script's new compartment
|
||||
// the originPrincipals are not related to compartment, so just copy
|
||||
newScript->principals = newScript->compartment()->principals;
|
||||
newScript->originPrincipals = script->originPrincipals;
|
||||
if (!newScript->originPrincipals)
|
||||
newScript->originPrincipals = newScript->principals;
|
||||
if (newScript->principals) {
|
||||
JSPRINCIPALS_HOLD(cx, newScript->principals);
|
||||
JSPRINCIPALS_HOLD(cx, newScript->originPrincipals);
|
||||
}
|
||||
|
||||
return newScript;
|
||||
}
|
||||
|
||||
|
@ -672,7 +672,7 @@ struct JSScript : public js::gc::Cell {
|
||||
}
|
||||
|
||||
/*
|
||||
* computedSizeOfData() is the in-use size of all the data sections.
|
||||
* computedSizeOfData() is the in-use size of all the data sections.
|
||||
* sizeOfData() is the size of the block allocated to hold all the data sections
|
||||
* (which can be larger than the in-use size).
|
||||
*/
|
||||
@ -829,6 +829,11 @@ struct JSScript : public js::gc::Cell {
|
||||
static inline void writeBarrierPost(JSScript *script, void *addr);
|
||||
|
||||
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; }
|
||||
|
||||
static JSPrincipals *normalizeOriginPrincipals(JSPrincipals *principals,
|
||||
JSPrincipals *originPrincipals) {
|
||||
return originPrincipals ? originPrincipals : principals;
|
||||
}
|
||||
};
|
||||
|
||||
/* If this fails, padding_ can be removed. */
|
||||
@ -932,7 +937,7 @@ extern JSScript *
|
||||
CloneScript(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
* NB: after a successful JSXDR_DECODE, js_XDRScript callers must do any
|
||||
* NB: after a successful JSXDR_DECODE, XDRScript callers must do any
|
||||
* required subsequent set-up of owning function or script object and then call
|
||||
* js_CallNewScriptHook.
|
||||
*/
|
||||
|
@ -237,7 +237,9 @@ JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx)
|
||||
xdr->mode = mode;
|
||||
xdr->cx = cx;
|
||||
xdr->userdata = NULL;
|
||||
xdr->state = NULL;
|
||||
xdr->sharedFilename = NULL;
|
||||
xdr->principals = NULL;
|
||||
xdr->originPrincipals = NULL;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSXDRState *)
|
||||
@ -394,19 +396,6 @@ JS_XDRCString(JSXDRState *xdr, char **sp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRCStringOrNull(JSXDRState *xdr, char **sp)
|
||||
{
|
||||
uint32_t null = (*sp == NULL);
|
||||
if (!JS_XDRUint32(xdr, &null))
|
||||
return JS_FALSE;
|
||||
if (null) {
|
||||
*sp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
return JS_XDRCString(xdr, sp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
XDRChars(JSXDRState *xdr, jschar *chars, uint32_t nchars)
|
||||
{
|
||||
@ -543,44 +532,100 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
XDRScriptState::XDRScriptState(JSXDRState *x)
|
||||
: xdr(x)
|
||||
, filename(NULL)
|
||||
, filenameSaved(false)
|
||||
static bool
|
||||
XDRPrincipals(JSXDRState *xdr)
|
||||
{
|
||||
JS_ASSERT(!xdr->state);
|
||||
const uint8_t HAS_PRINCIPALS = 1;
|
||||
const uint8_t HAS_ORIGIN = 2;
|
||||
|
||||
xdr->state = this;
|
||||
uint8_t flags = 0;
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
if (xdr->principals)
|
||||
flags |= HAS_PRINCIPALS;
|
||||
|
||||
/*
|
||||
* For the common case when principals == originPrincipals we want to
|
||||
* avoid serializing the same principal twice. As originPrincipals are
|
||||
* normalized and principals imply originPrincipals we simply set
|
||||
* HAS_ORIGIN only if originPrincipals is set and different from
|
||||
* principals. During decoding we re-normalize originPrincipals.
|
||||
*/
|
||||
JS_ASSERT_IF(xdr->principals, xdr->originPrincipals);
|
||||
if (xdr->originPrincipals && xdr->originPrincipals != xdr->principals)
|
||||
flags |= HAS_ORIGIN;
|
||||
}
|
||||
|
||||
if (!JS_XDRUint8(xdr, &flags))
|
||||
return false;
|
||||
|
||||
if (flags & (HAS_PRINCIPALS | HAS_ORIGIN)) {
|
||||
JSSecurityCallbacks *scb = JS_GetSecurityCallbacks(xdr->cx);
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
if (!scb || !scb->principalsTranscoder) {
|
||||
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_CANT_DECODE_PRINCIPALS);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(scb);
|
||||
JS_ASSERT(scb->principalsTranscoder);
|
||||
}
|
||||
|
||||
if (flags & HAS_PRINCIPALS) {
|
||||
if (!scb->principalsTranscoder(xdr, &xdr->principals))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flags & HAS_ORIGIN) {
|
||||
if (!scb->principalsTranscoder(xdr, &xdr->originPrincipals))
|
||||
return false;
|
||||
} else if (xdr->mode == JSXDR_DECODE && xdr->principals) {
|
||||
xdr->originPrincipals = xdr->principals;
|
||||
JSPRINCIPALS_HOLD(xdr->cx, xdr->principals);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
XDRScriptState::~XDRScriptState()
|
||||
{
|
||||
xdr->state = NULL;
|
||||
if (xdr->mode == JSXDR_DECODE && filename && !filenameSaved)
|
||||
xdr->cx->free_((void *)filename);
|
||||
}
|
||||
namespace {
|
||||
|
||||
struct AutoDropXDRPrincipals {
|
||||
JSXDRState *const xdr;
|
||||
|
||||
AutoDropXDRPrincipals(JSXDRState *xdr)
|
||||
: xdr(xdr) { }
|
||||
|
||||
~AutoDropXDRPrincipals() {
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
if (xdr->principals)
|
||||
JSPRINCIPALS_DROP(xdr->cx, xdr->principals);
|
||||
if (xdr->originPrincipals)
|
||||
JSPRINCIPALS_DROP(xdr->cx, xdr->originPrincipals);
|
||||
}
|
||||
xdr->principals = NULL;
|
||||
xdr->originPrincipals = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace anonymous */
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
|
||||
{
|
||||
XDRScriptState fstate(xdr);
|
||||
|
||||
AutoDropXDRPrincipals drop(xdr);
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
JSFunction* fun = (*objp)->toFunction();
|
||||
fstate.filename = fun->script()->filename;
|
||||
JSScript *script = (*objp)->toFunction()->script();
|
||||
xdr->principals = script->principals;
|
||||
xdr->originPrincipals = script->originPrincipals;
|
||||
}
|
||||
|
||||
if (!JS_XDRCStringOrNull(xdr, (char **) &fstate.filename))
|
||||
return false;
|
||||
|
||||
return XDRFunctionObject(xdr, objp);
|
||||
return XDRPrincipals(xdr) && XDRFunctionObject(xdr, objp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
{
|
||||
JS_ASSERT(!xdr->state);
|
||||
|
||||
JSScript *script;
|
||||
uint32_t magic;
|
||||
uint32_t bytecodeVer;
|
||||
@ -605,17 +650,16 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
return false;
|
||||
}
|
||||
|
||||
XDRScriptState state(xdr);
|
||||
if (!xdr->state)
|
||||
return false;
|
||||
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
state.filename = script->filename;
|
||||
if (!JS_XDRCStringOrNull(xdr, (char **) &state.filename))
|
||||
return false;
|
||||
|
||||
if (!XDRScript(xdr, &script))
|
||||
return false;
|
||||
{
|
||||
AutoDropXDRPrincipals drop(xdr);
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
xdr->principals = script->principals;
|
||||
xdr->originPrincipals = script->originPrincipals;
|
||||
}
|
||||
|
||||
if (!XDRPrincipals(xdr) || !XDRScript(xdr, &script))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
JS_ASSERT(!script->compileAndGo);
|
||||
|
@ -105,28 +105,14 @@ typedef struct JSXDROps {
|
||||
void (*finalize)(JSXDRState *);
|
||||
} JSXDROps;
|
||||
|
||||
struct JSXDRState;
|
||||
|
||||
namespace js {
|
||||
|
||||
class XDRScriptState {
|
||||
public:
|
||||
XDRScriptState(JSXDRState *x);
|
||||
~XDRScriptState();
|
||||
|
||||
JSXDRState *xdr;
|
||||
const char *filename;
|
||||
bool filenameSaved;
|
||||
};
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
struct JSXDRState {
|
||||
JSXDRMode mode;
|
||||
JSXDROps *ops;
|
||||
JSContext *cx;
|
||||
void *userdata;
|
||||
js::XDRScriptState *state;
|
||||
const char *sharedFilename;
|
||||
JSPrincipals *principals;
|
||||
JSPrincipals *originPrincipals;
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
@ -165,9 +151,6 @@ JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32_t len);
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_XDRCString(JSXDRState *xdr, char **sp);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_XDRCStringOrNull(JSXDRState *xdr, char **sp);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_XDRString(JSXDRState *xdr, JSString **strp);
|
||||
|
||||
@ -209,7 +192,9 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp);
|
||||
* and saved versions. If deserialization fails, the data should be
|
||||
* invalidated if possible.
|
||||
*/
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 107)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 108)
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
@ -217,6 +202,14 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp);
|
||||
extern JSBool
|
||||
js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
/*
|
||||
* Set principals that should be assigned to decoded scripts and functions.
|
||||
* The principals is not held via JS_HoldPrincipals/JS_DropPrincipals unless
|
||||
* they are stored in a decoded script. Thus the caller must either ensure
|
||||
* that principal outlive the XDR instance or are explicitly set to NULL
|
||||
* before they release by the caller.
|
||||
*/
|
||||
extern void
|
||||
js_XDRSetPrincipals(JSXDRState *xdr, JSPrincipals *principals, JSPrincipals *originPrincipals);
|
||||
|
||||
#endif /* ! jsxdrapi_h___ */
|
||||
|
Loading…
Reference in New Issue
Block a user