From 70202e15a18654228ee1da487c8323d1eacb2b29 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Wed, 9 Mar 2016 11:20:11 +0100 Subject: [PATCH] Bug 1251308; r=luke MozReview-Commit-ID: AqsMX4m7Qh9 --HG-- extra : rebase_source : 519aef2cf8c0bb39771d4589069e8fd1a06970c3 --- caps/nsScriptSecurityManager.cpp | 2 +- dom/base/WebSocket.cpp | 4 +- dom/base/nsGlobalWindow.cpp | 2 +- dom/base/nsJSUtils.cpp | 4 +- dom/workers/RuntimeService.cpp | 2 +- dom/workers/WorkerPrivate.cpp | 2 +- dom/workers/WorkerScope.cpp | 2 +- js/src/asmjs/Wasm.cpp | 8 ++- js/src/builtin/TestingFunctions.cpp | 4 +- js/src/jit-test/tests/wasm/basic.js | 2 + js/src/jsapi.cpp | 62 ++++++++++++++++++-- js/src/jsapi.h | 32 +++++++++- js/src/shell/OSObject.cpp | 2 +- js/src/shell/js.cpp | 4 +- js/src/vm/Stack.cpp | 15 +++++ js/src/vm/Stack.h | 1 + js/xpconnect/loader/mozJSSubScriptLoader.cpp | 2 +- js/xpconnect/src/XPCShellImpl.cpp | 2 +- js/xpconnect/wrappers/XrayWrapper.cpp | 2 +- 19 files changed, 128 insertions(+), 26 deletions(-) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 72977a02a285..f0b342c27ba8 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -502,7 +502,7 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx) unsigned lineNum = 0; NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP"); - JS::UniqueChars scriptFilename; + JS::AutoFilename scriptFilename; if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) { if (const char *file = scriptFilename.get()) { CopyUTF8toUTF16(nsDependentCString(file), fileName); diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp index fbb7c837a579..3da1fb275ab9 100644 --- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -1237,7 +1237,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal, } unsigned lineno, column; - JS::UniqueChars file; + JS::AutoFilename file; if (!JS::DescribeScriptedCaller(aGlobal.Context(), &file, &lineno, &column)) { NS_WARNING("Failed to get line number and filename in workers."); @@ -1473,7 +1473,7 @@ WebSocketImpl::Init(JSContext* aCx, MOZ_ASSERT(aCx); unsigned lineno, column; - JS::UniqueChars file; + JS::AutoFilename file; if (JS::DescribeScriptedCaller(aCx, &file, &lineno, &column)) { mScriptFile = file.get(); mScriptLine = lineno; diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 49276d544405..353d2eb35b97 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -10659,7 +10659,7 @@ nsGlobalWindow::ShowSlowScriptDialog() } // Check if we should offer the option to debug - JS::UniqueChars filename; + JS::AutoFilename filename; unsigned lineno; bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno); diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index 9e3cea041958..5c914d880458 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -37,7 +37,7 @@ bool nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename, uint32_t* aLineno, uint32_t* aColumn) { - JS::UniqueChars filename; + JS::AutoFilename filename; if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) { return false; } @@ -50,7 +50,7 @@ bool nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename, uint32_t* aLineno, uint32_t* aColumn) { - JS::UniqueChars filename; + JS::AutoFilename filename; if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) { return false; } diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index d619cbbb00e6..783ed20098bd 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -621,7 +621,7 @@ ContentSecurityPolicyAllows(JSContext* aCx) nsString fileName; uint32_t lineNum = 0; - JS::UniqueChars file; + JS::AutoFilename file; if (JS::DescribeScriptedCaller(aCx, &file, &lineNum) && file.get()) { fileName = NS_ConvertUTF8toUTF16(file.get()); } else { diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 7a17fa198f63..7f79ee9a5ba6 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -4296,7 +4296,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* 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::UniqueChars fileName; + 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 diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index e09a2ad4f96d..8c98f3cc8152 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -907,7 +907,7 @@ void WorkerDebuggerGlobalScope::ReportError(JSContext* aCx, const nsAString& aMessage) { - JS::UniqueChars chars; + JS::AutoFilename chars; uint32_t lineno = 0; JS::DescribeScriptedCaller(aCx, &chars, &lineno); nsString filename(NS_ConvertUTF8toUTF16(chars.get())); diff --git a/js/src/asmjs/Wasm.cpp b/js/src/asmjs/Wasm.cpp index b740e123a5d5..17562a6fa96b 100644 --- a/js/src/asmjs/Wasm.cpp +++ b/js/src/asmjs/Wasm.cpp @@ -1581,8 +1581,12 @@ wasm::Eval(JSContext* cx, Handle code, HandleObject importObj bytes = copy.begin(); } - UniqueChars file; - if (!DescribeScriptedCaller(cx, &file)) + JS::AutoFilename filename; + if (!DescribeScriptedCaller(cx, &filename)) + return false; + + UniqueChars file = DuplicateString(filename.get()); + if (!file) return false; ImportNameVector importNames; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 4f93f93527c3..3e1c7e81879a 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2835,7 +2835,7 @@ EvalReturningScope(JSContext* cx, unsigned argc, Value* vp) size_t srclen = chars.length(); const char16_t* src = chars.start().get(); - JS::UniqueChars filename; + JS::AutoFilename filename; unsigned lineno; JS::DescribeScriptedCaller(cx, &filename, &lineno); @@ -2921,7 +2921,7 @@ ShellCloneAndExecuteScript(JSContext* cx, unsigned argc, Value* vp) size_t srclen = chars.length(); const char16_t* src = chars.start().get(); - JS::UniqueChars filename; + JS::AutoFilename filename; unsigned lineno; JS::DescribeScriptedCaller(cx, &filename, &lineno); diff --git a/js/src/jit-test/tests/wasm/basic.js b/js/src/jit-test/tests/wasm/basic.js index f4e6d8ea0186..0f4b48f2d557 100644 --- a/js/src/jit-test/tests/wasm/basic.js +++ b/js/src/jit-test/tests/wasm/basic.js @@ -343,6 +343,8 @@ assertEq(wasmEvalText(code.replace('BODY', '(call_import 1)'), imports)(), 2); assertEq(wasmEvalText(code.replace('BODY', '(call 0)'), imports)(), 3); assertEq(wasmEvalText(code.replace('BODY', '(call 1)'), imports)(), 4); +assertEq(wasmEvalText(`(module (import "evalcx" "" (param i32) (result i32)) (func (result i32) (call_import 0 (i32.const 0))) (export "" 0))`, {evalcx})(), 0); + var {v2i, i2i, i2v} = wasmEvalText(`(module (type (func (result i32))) (type (func (param i32) (result i32))) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 312d8746684e..3b9c6d47c4ac 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6030,8 +6030,51 @@ JS_IsIdentifier(const char16_t* chars, size_t length) namespace JS { +void AutoFilename::reset() +{ + if (ss_) { + reinterpret_cast(ss_)->decref(); + ss_ = nullptr; + } + if (filename_.is()) + filename_.as() = nullptr; + else + filename_.as().reset(); +} + +void AutoFilename::setScriptSource(void* p) +{ + MOZ_ASSERT(!ss_); + MOZ_ASSERT(!get()); + ss_ = p; + if (p) { + ScriptSource* ss = reinterpret_cast(p); + ss->incref(); + setUnowned(ss->filename()); + } +} + +void AutoFilename::setUnowned(const char* filename) +{ + MOZ_ASSERT(!get()); + filename_.as() = filename; +} + +void AutoFilename::setOwned(UniqueChars&& filename) +{ + MOZ_ASSERT(!get()); + filename_ = AsVariant(Move(filename)); +} + +const char* AutoFilename::get() const +{ + if (filename_.is()) + return filename_.as(); + return filename_.as().get(); +} + JS_PUBLIC_API(bool) -DescribeScriptedCaller(JSContext* cx, UniqueChars* filename, unsigned* lineno, +DescribeScriptedCaller(JSContext* cx, AutoFilename* filename, unsigned* lineno, unsigned* column) { if (filename) @@ -6050,11 +6093,18 @@ DescribeScriptedCaller(JSContext* cx, UniqueChars* filename, unsigned* lineno, if (i.activation()->scriptedCallerIsHidden()) return false; - if (filename && i.filename()) { - UniqueChars copy = DuplicateString(i.filename()); - if (!copy) - return false; - *filename = Move(copy); + if (filename) { + if (i.isWasm()) { + // For Wasm, copy out the filename, there is no script source. + UniqueChars copy = DuplicateString(i.filename()); + if (!copy) + filename->setUnowned("out of memory"); + else + filename->setOwned(Move(copy)); + } else { + // All other frames have a script source to read the filename from. + filename->setScriptSource(i.scriptSource()); + } } if (lineno) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index faf5b80d213f..ac532ba49fc0 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -15,6 +15,7 @@ #include "mozilla/Range.h" #include "mozilla/RangedPtr.h" #include "mozilla/RefPtr.h" +#include "mozilla/Variant.h" #include #include @@ -5408,6 +5409,35 @@ JS_IsIdentifier(const char16_t* chars, size_t length); namespace JS { +class MOZ_RAII JS_PUBLIC_API(AutoFilename) +{ + private: + // Actually a ScriptSource, not put here to avoid including the world. + void* ss_; + mozilla::Variant filename_; + + AutoFilename(const AutoFilename&) = delete; + AutoFilename& operator=(const AutoFilename&) = delete; + + public: + AutoFilename() + : ss_(nullptr), + filename_(mozilla::AsVariant(nullptr)) + {} + + ~AutoFilename() { + reset(); + } + + void reset(); + + void setOwned(UniqueChars&& filename); + void setUnowned(const char* filename); + void setScriptSource(void* ss); + + const char* get() const; +}; + /** * Return the current filename, line number and column number of the most * currently running frame. Returns true if a scripted frame was found, false @@ -5417,7 +5447,7 @@ namespace JS { * record, this will also return false. */ extern JS_PUBLIC_API(bool) -DescribeScriptedCaller(JSContext* cx, UniqueChars* filename = nullptr, +DescribeScriptedCaller(JSContext* cx, AutoFilename* filename = nullptr, unsigned* lineno = nullptr, unsigned* column = nullptr); extern JS_PUBLIC_API(JSObject*) diff --git a/js/src/shell/OSObject.cpp b/js/src/shell/OSObject.cpp index a9433193807e..586ff66ec13f 100644 --- a/js/src/shell/OSObject.cpp +++ b/js/src/shell/OSObject.cpp @@ -113,7 +113,7 @@ ResolvePath(JSContext* cx, HandleString filenameStr, PathResolutionMode resolveM return filenameStr; /* Get the currently executing script's name. */ - JS::UniqueChars scriptFilename; + JS::AutoFilename scriptFilename; if (!DescribeScriptedCaller(cx, &scriptFilename)) return nullptr; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index b9948744a1e3..5d3cd1cafbaa 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2737,7 +2737,7 @@ EvalInContext(JSContext* cx, unsigned argc, Value* vp) return true; } - JS::UniqueChars filename; + JS::AutoFilename filename; unsigned lineno; DescribeScriptedCaller(cx, &filename, &lineno); @@ -4166,7 +4166,7 @@ ThisFilename(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - JS::UniqueChars filename; + JS::AutoFilename filename; if (!DescribeScriptedCaller(cx, &filename) || !filename.get()) { args.rval().setString(cx->runtime()->emptyString); return true; diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index f61d5ab330b2..ba8baca0ba26 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -880,6 +880,21 @@ FrameIter::functionDisplayAtom() const MOZ_CRASH("Unexpected state"); } +ScriptSource* +FrameIter::scriptSource() const +{ + switch (data_.state_) { + case DONE: + case WASM: + break; + case INTERP: + case JIT: + return script()->scriptSource(); + } + + MOZ_CRASH("Unexpected state"); +} + const char* FrameIter::filename() const { diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 8e12fbf0687d..e2330fae3be1 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1754,6 +1754,7 @@ class FrameIter inline bool hasCachedSavedFrame() const; inline void setHasCachedSavedFrame(); + ScriptSource* scriptSource() const; const char* filename() const; const char16_t* displayURL() const; unsigned computeLine(uint32_t* column = nullptr) const; diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp index b93590f1d065..67b27dcac0e1 100644 --- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp @@ -600,7 +600,7 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url, nsAutoCString scheme; // Figure out who's calling us - JS::UniqueChars filename; + JS::AutoFilename filename; if (!JS::DescribeScriptedCaller(cx, &filename)) { // No scripted frame means we don't know who's calling, bail. return NS_ERROR_FAILURE; diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index c4598779d50f..86a93d04cb47 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -141,7 +141,7 @@ GetLocationProperty(JSContext* cx, unsigned argc, Value* vp) //XXX: your platform should really implement this return false; #else - JS::UniqueChars filename; + JS::AutoFilename filename; if (JS::DescribeScriptedCaller(cx, &filename) && filename.get()) { nsresult rv; nsCOMPtr xpc = diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index e9fac4f8112d..29fde57f2544 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -203,7 +203,7 @@ ReportWrapperDenial(JSContext* cx, HandleId id, WrapperDenialType type, const ch return false; if (!propertyName.init(cx, str)) return false; - UniqueChars filename; + AutoFilename filename; unsigned line = 0, column = 0; DescribeScriptedCaller(cx, &filename, &line, &column);