Bug 976348 - Change DescribeScriptedCaller to not return a JSScript (r=bholley)

--HG--
extra : rebase_source : 58387ce3e4c49d3140b92b84bf3577fc6584820e
This commit is contained in:
Luke Wagner 2014-02-25 09:43:14 -06:00
parent 84ae283792
commit dfb0b68df3
16 changed files with 161 additions and 103 deletions

View File

@ -395,9 +395,9 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
unsigned lineNum = 0;
NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
JS::RootedScript script(cx);
if (JS_DescribeScriptedCaller(cx, &script, &lineNum)) {
if (const char *file = JS_GetScriptFilename(cx, script)) {
JS::AutoFilename scriptFilename;
if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) {
if (const char *file = scriptFilename.get()) {
CopyUTF8toUTF16(nsDependentCString(file), fileName);
}
}

View File

@ -667,9 +667,9 @@ WebSocket::Init(JSContext* aCx,
NS_ENSURE_SUCCESS(rv, rv);
unsigned lineno;
JS::Rooted<JSScript*> script(aCx);
if (JS_DescribeScriptedCaller(aCx, &script, &lineno)) {
mScriptFile = JS_GetScriptFilename(aCx, script);
JS::AutoFilename file;
if (JS::DescribeScriptedCaller(aCx, &file, &lineno)) {
mScriptFile = file.get();
mScriptLine = lineno;
}

View File

@ -143,10 +143,7 @@ GetIncumbentGlobal()
// override in place, the JS engine will lie to us and pretend that
// there's nothing on the JS stack, which will cause us to check the
// incumbent script stack below.
JS::RootedScript script(cx);
if (JS_DescribeScriptedCaller(cx, &script, nullptr)) {
JS::RootedObject global(cx, JS_GetGlobalFromScript(script));
MOZ_ASSERT(global);
if (JSObject *global = JS::GetScriptedCallerGlobal(cx)) {
return xpc::GetNativeForGlobal(global);
}

View File

@ -10536,9 +10536,9 @@ nsGlobalWindow::ShowSlowScriptDialog()
NS_ENSURE_TRUE(prompt, KillSlowScript);
// Check if we should offer the option to debug
JS::Rooted<JSScript*> script(cx);
JS::AutoFilename filename;
unsigned lineno;
bool hasFrame = JS_DescribeScriptedCaller(cx, &script, &lineno);
bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
bool debugPossible = hasFrame && js::CanCallContextDebugHandler(cx);
#ifdef MOZ_JSDEBUGGER
@ -10623,23 +10623,20 @@ nsGlobalWindow::ShowSlowScriptDialog()
}
// Append file and line number information, if available
if (script) {
const char *filename = JS_GetScriptFilename(cx, script);
if (filename) {
nsXPIDLString scriptLocation;
NS_ConvertUTF8toUTF16 filenameUTF16(filename);
const char16_t *formatParams[] = { filenameUTF16.get() };
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
"KillScriptLocation",
formatParams,
scriptLocation);
if (filename.get()) {
nsXPIDLString scriptLocation;
NS_ConvertUTF8toUTF16 filenameUTF16(filename.get());
const char16_t *formatParams[] = { filenameUTF16.get() };
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
"KillScriptLocation",
formatParams,
scriptLocation);
if (NS_SUCCEEDED(rv) && scriptLocation) {
msg.AppendLiteral("\n\n");
msg.Append(scriptLocation);
msg.Append(':');
msg.AppendInt(lineno);
}
if (NS_SUCCEEDED(rv) && scriptLocation) {
msg.AppendLiteral("\n\n");
msg.Append(scriptLocation);
msg.Append(':');
msg.AppendInt(lineno);
}
}

View File

@ -526,8 +526,7 @@ NS_ScriptErrorReporter(JSContext *cx,
// absence of werror are swallowed whole, so report those now.
if (!JSREPORT_IS_WARNING(report->flags)) {
nsIXPConnect* xpc = nsContentUtils::XPConnect();
JS::Rooted<JSScript*> script(cx);
if (JS_DescribeScriptedCaller(cx, &script, nullptr)) {
if (JS::DescribeScriptedCaller(cx)) {
xpc->MarkErrorUnreported(cx);
return;
}

View File

@ -32,14 +32,14 @@ bool
nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
uint32_t* aLineno)
{
JS::Rooted<JSScript*> script(aContext);
JS::AutoFilename filename;
unsigned lineno = 0;
if (!JS_DescribeScriptedCaller(aContext, &script, &lineno)) {
if (!JS::DescribeScriptedCaller(aContext, &filename, &lineno)) {
return false;
}
*aFilename = ::JS_GetScriptFilename(aContext, script);
*aFilename = filename.get();
*aLineno = lineno;
return true;

View File

@ -663,11 +663,9 @@ ContentSecurityPolicyAllows(JSContext* aCx)
nsString fileName;
uint32_t lineNum = 0;
JS::Rooted<JSScript*> script(aCx);
const char* file;
if (JS_DescribeScriptedCaller(aCx, &script, &lineNum) &&
(file = JS_GetScriptFilename(aCx, script))) {
fileName = NS_ConvertUTF8toUTF16(file);
JS::AutoFilename file;
if (JS::DescribeScriptedCaller(aCx, &file, &lineNum) && file.get()) {
fileName = NS_ConvertUTF8toUTF16(file.get());
} else {
JS_ReportPendingException(aCx);
}

View File

@ -3853,10 +3853,8 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
// We're being created outside of a window. Need to figure out the script
// that is creating us in order for us to use relative URIs later on.
JS::Rooted<JSScript*> script(aCx);
if (JS_DescribeScriptedCaller(aCx, &script, nullptr)) {
const char* fileName = JS_GetScriptFilename(aCx, script);
JS::AutoFilename fileName;
if (JS::DescribeScriptedCaller(aCx, &fileName)) {
// In most cases, fileName is URI. In a few other cases
// (e.g. xpcshell), fileName is a file path. Ideally, we would
// prefer testing whether fileName parses as an URI and fallback
@ -3871,7 +3869,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
return rv;
}
rv = scriptFile->InitWithPath(NS_ConvertUTF8toUTF16(fileName));
rv = scriptFile->InitWithPath(NS_ConvertUTF8toUTF16(fileName.get()));
if (NS_SUCCEEDED(rv)) {
rv = NS_NewFileURI(getter_AddRefs(loadInfo.mBaseURI),
scriptFile);
@ -3880,7 +3878,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
// As expected, fileName is not a path, so proceed with
// a uri.
rv = NS_NewURI(getter_AddRefs(loadInfo.mBaseURI),
fileName);
fileName.get());
}
if (NS_FAILED(rv)) {
return rv;

View File

@ -10,6 +10,8 @@
#include "js/OldDebugAPI.h"
#include "jsapi-tests/tests.h"
using namespace js;
static int callCounts[2] = {0, 0};
static void *
@ -253,13 +255,13 @@ BEGIN_TEST(testDebugger_singleStepThrow)
static bool
setStepMode(JSContext *cx, unsigned argc, jsval *vp)
{
JS::RootedScript script(cx);
JS_DescribeScriptedCaller(cx, &script, nullptr);
JS_ASSERT(script);
CallArgs args = CallArgsFromVp(argc, vp);
if (!JS_SetSingleStepMode(cx, script, true))
NonBuiltinScriptFrameIter iter(cx);
if (!JS_SetSingleStepMode(cx, iter.script(), true))
return false;
JS_SET_RVAL(cx, vp, JSVAL_VOID);
args.rval().set(UndefinedValue());
return true;
}

View File

@ -6112,10 +6112,28 @@ JS_IsIdentifier(JSContext *cx, HandleString str, bool *isIdentifier)
return true;
}
JS_PUBLIC_API(bool)
JS_DescribeScriptedCaller(JSContext *cx, MutableHandleScript script, unsigned *lineno)
namespace JS {
void
AutoFilename::reset(void *newScriptSource)
{
if (newScriptSource)
reinterpret_cast<ScriptSource*>(newScriptSource)->incref();
if (scriptSource_)
reinterpret_cast<ScriptSource*>(scriptSource_)->decref();
scriptSource_ = newScriptSource;
}
const char *
AutoFilename::get() const
{
JS_ASSERT(scriptSource_);
return reinterpret_cast<ScriptSource*>(scriptSource_)->filename();
}
JS_PUBLIC_API(bool)
DescribeScriptedCaller(JSContext *cx, AutoFilename *filename, unsigned *lineno)
{
script.set(nullptr);
if (lineno)
*lineno = 0;
@ -6123,18 +6141,39 @@ JS_DescribeScriptedCaller(JSContext *cx, MutableHandleScript script, unsigned *l
if (i.done())
return false;
// If the caller is hidden, the embedding wants us to return null here so
// that it can check its own stack.
// If the caller is hidden, the embedding wants us to return false here so
// that it can check its own stack (see HideScriptedCaller).
if (i.activation()->scriptedCallerIsHidden())
return false;
script.set(i.script());
if (filename)
filename->reset(i.script()->scriptSource());
if (lineno)
*lineno = js::PCToLineNumber(i.script(), i.pc());
return true;
}
namespace JS {
JS_PUBLIC_API(JSObject *)
GetScriptedCallerGlobal(JSContext *cx)
{
NonBuiltinScriptFrameIter i(cx);
if (i.done())
return nullptr;
// If the caller is hidden, the embedding wants us to return null here so
// that it can check its own stack (see HideScriptedCaller).
if (i.activation()->scriptedCallerIsHidden())
return nullptr;
GlobalObject *global = i.activation()->compartment()->maybeGlobal();
// Noone should be running code in the atoms compartment or running code in
// a compartment without any live objects, so there should definitely be a
// live global.
JS_ASSERT(global);
return global;
}
JS_PUBLIC_API(void)
HideScriptedCaller(JSContext *cx)

View File

@ -4704,17 +4704,41 @@ JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, JS::MutableHandleId);
extern JS_PUBLIC_API(bool)
JS_IsIdentifier(JSContext *cx, JS::HandleString str, bool *isIdentifier);
namespace JS {
/*
* Return the current script and line number of the most currently running
* AutoFilename encapsulates a pointer to a C-string and keeps the C-string
* alive for as long as the associated AutoFilename object is alive.
*/
class MOZ_STACK_CLASS JS_PUBLIC_API(AutoFilename)
{
void *scriptSource_;
AutoFilename(const AutoFilename &) MOZ_DELETE;
void operator=(const AutoFilename &) MOZ_DELETE;
public:
AutoFilename() : scriptSource_(nullptr) {}
~AutoFilename() { reset(nullptr); }
const char *get() const;
void reset(void *newScriptSource);
};
/*
* Return the current filename and line number of the most currently running
* frame. Returns true if a scripted frame was found, false otherwise.
*
* If a the embedding has hidden the scripted caller for the topmost activation
* record, this will also return false.
*/
extern JS_PUBLIC_API(bool)
JS_DescribeScriptedCaller(JSContext *cx, JS::MutableHandleScript script, unsigned *lineno);
DescribeScriptedCaller(JSContext *cx, AutoFilename *filename = nullptr,
unsigned *lineno = nullptr);
namespace JS {
extern JS_PUBLIC_API(JSObject *)
GetScriptedCallerGlobal(JSContext *cx);
/*
* Informs the JS engine that the scripted caller should be hidden. This can be

View File

@ -577,14 +577,6 @@ Version(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
static JSScript *
GetTopScript(JSContext *cx)
{
RootedScript script(cx);
JS_DescribeScriptedCaller(cx, &script, nullptr);
return script;
}
/*
* Resolve a (possibly) relative filename to an absolute path. If
* |scriptRelative| is true, then the result will be relative to the directory
@ -617,19 +609,23 @@ ResolvePath(JSContext *cx, HandleString filenameStr, bool scriptRelative)
#endif
/* Get the currently executing script's name. */
RootedScript script(cx, GetTopScript(cx));
if (!script->filename())
JS::AutoFilename scriptFilename;
if (!DescribeScriptedCaller(cx, &scriptFilename))
return nullptr;
if (strcmp(script->filename(), "-e") == 0 || strcmp(script->filename(), "typein") == 0)
if (!scriptFilename.get())
return nullptr;
if (strcmp(scriptFilename.get(), "-e") == 0 || strcmp(scriptFilename.get(), "typein") == 0)
scriptRelative = false;
static char buffer[PATH_MAX+1];
if (scriptRelative) {
#ifdef XP_WIN
// The docs say it can return EINVAL, but the compiler says it's void
_splitpath(script->filename(), nullptr, buffer, nullptr, nullptr);
_splitpath(scriptFilename.get(), nullptr, buffer, nullptr, nullptr);
#else
strncpy(buffer, script->filename(), PATH_MAX+1);
strncpy(buffer, scriptFilename.get(), PATH_MAX+1);
if (buffer[PATH_MAX] != '\0')
return nullptr;
@ -1657,6 +1653,13 @@ SetDebug(JSContext *cx, unsigned argc, jsval *vp)
return ok;
}
static JSScript *
GetTopScript(JSContext *cx)
{
NonBuiltinScriptFrameIter iter(cx);
return iter.done() ? nullptr : iter.script();
}
static bool
GetScriptAndPCArgs(JSContext *cx, unsigned argc, jsval *argv, MutableHandleScript scriptp,
int32_t *ip)
@ -2695,10 +2698,10 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
RootedScript script(cx);
JS::AutoFilename filename;
unsigned lineno;
JS_DescribeScriptedCaller(cx, &script, &lineno);
DescribeScriptedCaller(cx, &filename, &lineno);
{
Maybe<JSAutoCompartment> ac;
unsigned flags;
@ -2716,7 +2719,7 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
script->filename(),
filename.get(),
lineno,
args.rval())) {
return false;
@ -4014,17 +4017,21 @@ static bool
DecompileThisScript(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedScript script (cx);
if (!JS_DescribeScriptedCaller(cx, &script, nullptr)) {
NonBuiltinScriptFrameIter iter(cx);
if (iter.done()) {
args.rval().setString(cx->runtime()->emptyString);
return true;
}
{
JSAutoCompartment ac(cx, script);
JSAutoCompartment ac(cx, iter.script());
RootedScript script(cx, iter.script());
JSString *result = JS_DecompileScript(cx, script, "test", 0);
if (!result)
return false;
args.rval().setString(result);
}
@ -4035,15 +4042,18 @@ static bool
ThisFilename(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedScript script (cx);
if (!JS_DescribeScriptedCaller(cx, &script, nullptr) || !script->filename()) {
JS::AutoFilename filename;
if (!DescribeScriptedCaller(cx, &filename) || !filename.get()) {
args.rval().setString(cx->runtime()->emptyString);
return true;
}
JSString *filename = JS_NewStringCopyZ(cx, script->filename());
if (!filename)
JSString *str = JS_NewStringCopyZ(cx, filename.get());
if (!str)
return false;
args.rval().setString(filename);
args.rval().setString(str);
return true;
}

View File

@ -269,10 +269,9 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString &url,
nsAutoCString uriStr;
nsAutoCString scheme;
RootedScript script(cx);
// Figure out who's calling us
if (!JS_DescribeScriptedCaller(cx, &script, nullptr)) {
JS::AutoFilename filename;
if (!JS::DescribeScriptedCaller(cx, &filename)) {
// No scripted frame means we don't know who's calling, bail.
return NS_ERROR_FAILURE;
}
@ -313,7 +312,7 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString &url,
// For file URIs prepend the filename with the filename of the
// calling script, and " -> ". See bug 418356.
nsAutoCString tmp(JS_GetScriptFilename(cx, script));
nsAutoCString tmp(filename.get());
tmp.AppendLiteral(" -> ");
tmp.Append(uriStr);
@ -327,7 +326,7 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString &url,
PathifyURI(uri, cachePath);
RootedFunction function(cx);
script = nullptr;
RootedScript script(cx);
if (cache && !options.ignoreCache)
rv = ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script);
if (!script) {

View File

@ -354,9 +354,9 @@ ExportFunction(JSContext *cx, unsigned argc, jsval *vp)
static bool
GetFilenameAndLineNumber(JSContext *cx, nsACString &filename, unsigned &lineno)
{
JS::RootedScript script(cx);
if (JS_DescribeScriptedCaller(cx, &script, &lineno)) {
if (const char *cfilename = JS_GetScriptFilename(cx, script)) {
JS::AutoFilename scriptFilename;
if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineno)) {
if (const char *cfilename = scriptFilename.get()) {
filename.Assign(nsDependentCString(cfilename));
return true;
}

View File

@ -121,22 +121,19 @@ GetLocationProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleV
//XXX: your platform should really implement this
return false;
#else
JS::RootedScript script(cx);
JS_DescribeScriptedCaller(cx, &script, nullptr);
const char *filename = JS_GetScriptFilename(cx, script);
if (filename) {
JS::AutoFilename filename;
if (JS::DescribeScriptedCaller(cx, &filename) && filename.get()) {
nsresult rv;
nsCOMPtr<nsIXPConnect> xpc =
do_GetService(kXPConnectServiceContractID, &rv);
#if defined(XP_WIN)
// convert from the system codepage to UTF-16
int bufferSize = MultiByteToWideChar(CP_ACP, 0, filename,
int bufferSize = MultiByteToWideChar(CP_ACP, 0, filename.get(),
-1, nullptr, 0);
nsAutoString filenameString;
filenameString.SetLength(bufferSize);
MultiByteToWideChar(CP_ACP, 0, filename,
MultiByteToWideChar(CP_ACP, 0, filename.get(),
-1, (LPWSTR)filenameString.BeginWriting(),
filenameString.Length());
// remove the null terminator
@ -153,7 +150,7 @@ GetLocationProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleV
start++;
}
#elif defined(XP_UNIX)
NS_ConvertUTF8toUTF16 filenameString(filename);
NS_ConvertUTF8toUTF16 filenameString(filename.get());
#endif
nsCOMPtr<nsIFile> location;

View File

@ -845,10 +845,8 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
// Finally, check to see if this is the last JS frame on the
// stack. If so then we always want to report it.
if (!reportable) {
RootedScript ignored(cx);
reportable = !JS_DescribeScriptedCaller(cx, &ignored, nullptr);
}
if (!reportable)
reportable = !JS::DescribeScriptedCaller(cx);
// Ugly special case for GetInterface. It's "special" in the
// same way as QueryInterface in that a failure is not