From 98c2be829a32a157e95e97d232bebf6075092fb3 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 10 Mar 2015 19:34:00 +0100 Subject: [PATCH] Bug 1140317: Make sure chars created by DecompileValueGenerator won't ever leak; r=Waldo --HG-- extra : rebase_source : 826d3b85b3b0b094f9d4d570a13915a99e985598 --- js/src/builtin/Object.cpp | 6 +++--- js/src/builtin/WeakSetObject.cpp | 5 +++-- js/src/jsarray.cpp | 10 +++++----- js/src/jscntxt.cpp | 29 ++++++++++++----------------- js/src/jsobj.cpp | 16 +++++++++------- js/src/jsopcode.cpp | 12 +++++++----- js/src/jsopcode.h | 4 +++- js/src/jsweakmap.cpp | 10 ++++++---- js/src/perf/jsperf.cpp | 5 +++-- js/src/vm/ForOfIterator.cpp | 8 +++++--- js/src/vm/SelfHosting.cpp | 2 +- 11 files changed, 57 insertions(+), 50 deletions(-) diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 3009c84ea5f9..ff423cf4482f 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -661,12 +661,12 @@ js::obj_create(JSContext *cx, unsigned argc, Value *vp) if (!args[0].isObjectOrNull()) { RootedValue v(cx, args[0]); - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr()); if (!bytes) return false; JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE, - bytes, "not an object or null"); - js_free(bytes); + bytes.get(), "not an object or null"); return false; } diff --git a/js/src/builtin/WeakSetObject.cpp b/js/src/builtin/WeakSetObject.cpp index b2127d2ad37d..b568c5af2a4d 100644 --- a/js/src/builtin/WeakSetObject.cpp +++ b/js/src/builtin/WeakSetObject.cpp @@ -123,10 +123,11 @@ WeakSetObject::construct(JSContext *cx, unsigned argc, Value *vp) if (isOriginalAdder) { if (keyVal.isPrimitive()) { - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, NullPtr()); if (!bytes) return false; - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get()); return false; } diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index c7eb37aadef2..e9b3457c41e6 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -52,6 +52,7 @@ using mozilla::CeilingLog2; using mozilla::CheckedInt; using mozilla::DebugOnly; using mozilla::IsNaN; +using mozilla::UniquePtr; using JS::AutoCheckCannotGC; using JS::ToUint32; @@ -3546,19 +3547,18 @@ js::ArrayInfo(JSContext *cx, unsigned argc, Value *vp) for (unsigned i = 0; i < args.length(); i++) { RootedValue arg(cx, args[i]); - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NullPtr()); if (!bytes) return false; if (arg.isPrimitive() || !(obj = arg.toObjectOrNull())->is()) { - fprintf(stderr, "%s: not array\n", bytes); - js_free(bytes); + fprintf(stderr, "%s: not array\n", bytes.get()); continue; } - fprintf(stderr, "%s: (len %u", bytes, obj->as().length()); + fprintf(stderr, "%s: (len %u", bytes.get(), obj->as().length()); fprintf(stderr, ", capacity %u", obj->as().getDenseCapacity()); fputs(")\n", stderr); - js_free(bytes); } args.rval().setUndefined(); diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 63ac3cc26a1a..5b3542517bcf 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -803,33 +803,32 @@ bool js::ReportIsNullOrUndefined(JSContext *cx, int spindex, HandleValue v, HandleString fallback) { - char *bytes; bool ok; - bytes = DecompileValueGenerator(cx, spindex, v, fallback); + UniquePtr bytes = + DecompileValueGenerator(cx, spindex, v, fallback); if (!bytes) return false; - if (strcmp(bytes, js_undefined_str) == 0 || - strcmp(bytes, js_null_str) == 0) { + if (strcmp(bytes.get(), js_undefined_str) == 0 || + strcmp(bytes.get(), js_null_str) == 0) { ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, GetErrorMessage, nullptr, - JSMSG_NO_PROPERTIES, bytes, + JSMSG_NO_PROPERTIES, bytes.get(), nullptr, nullptr); } else if (v.isUndefined()) { ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, GetErrorMessage, nullptr, - JSMSG_UNEXPECTED_TYPE, bytes, + JSMSG_UNEXPECTED_TYPE, bytes.get(), js_undefined_str, nullptr); } else { MOZ_ASSERT(v.isNull()); ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, GetErrorMessage, nullptr, - JSMSG_UNEXPECTED_TYPE, bytes, + JSMSG_UNEXPECTED_TYPE, bytes.get(), js_null_str, nullptr); } - js_free(bytes); return ok; } @@ -837,22 +836,19 @@ void js::ReportMissingArg(JSContext *cx, HandleValue v, unsigned arg) { char argbuf[11]; - char *bytes; + UniquePtr bytes; RootedAtom atom(cx); JS_snprintf(argbuf, sizeof argbuf, "%u", arg); - bytes = nullptr; if (IsFunctionObject(v)) { atom = v.toObject().as().atom(); - bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, - v, atom); + bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, atom); if (!bytes) return; } JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MISSING_FUN_ARG, argbuf, - bytes ? bytes : ""); - js_free(bytes); + bytes ? bytes.get() : ""); } bool @@ -860,7 +856,7 @@ js::ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNum int spindex, HandleValue v, HandleString fallback, const char *arg1, const char *arg2) { - char *bytes; + UniquePtr bytes; bool ok; MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1); @@ -870,8 +866,7 @@ js::ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNum return false; ok = JS_ReportErrorFlagsAndNumber(cx, flags, GetErrorMessage, - nullptr, errorNumber, bytes, arg1, arg2); - js_free(bytes); + nullptr, errorNumber, bytes.get(), arg1, arg2); return ok; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 33be6dbbea17..c59229e86588 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -94,10 +94,11 @@ js::NonNullObject(JSContext *cx, const Value &v) { if (v.isPrimitive()) { RootedValue value(cx, v); - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, NullPtr()); if (!bytes) return nullptr; - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get()); return nullptr; } return &v.toObject(); @@ -249,12 +250,12 @@ js::GetFirstArgumentAsObject(JSContext *cx, const CallArgs &args, const char *me HandleValue v = args[0]; if (!v.isObject()) { - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr()); if (!bytes) return false; JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE, - bytes, "not an object"); - js_free(bytes); + bytes.get(), "not an object"); return false; } @@ -285,10 +286,11 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) /* 8.10.5 step 1 */ if (v.isPrimitive()) { - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr()); if (!bytes) return false; - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get()); return false; } RootedObject desc(cx, &v.toObject()); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 827933285818..5df657c05957 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1819,7 +1819,9 @@ DecompileExpressionFromStack(JSContext *cx, int spindex, int skipStackHits, Hand return ed.getOutput(res); } -char * +typedef mozilla::UniquePtr UniquePtrChars; + +UniquePtrChars js::DecompileValueGenerator(JSContext *cx, int spindex, HandleValue v, HandleString fallbackArg, int skipStackHits) { @@ -1830,19 +1832,19 @@ js::DecompileValueGenerator(JSContext *cx, int spindex, HandleValue v, return nullptr; if (result) { if (strcmp(result, "(intermediate value)")) - return result; + return UniquePtrChars(result); js_free(result); } } if (!fallback) { if (v.isUndefined()) - return JS_strdup(cx, js_undefined_str); // Prevent users from seeing "(void 0)" + return UniquePtrChars(JS_strdup(cx, js_undefined_str)); // Prevent users from seeing "(void 0)" fallback = ValueToSource(cx, v); if (!fallback) - return nullptr; + return UniquePtrChars(nullptr); } - return JS_EncodeString(cx, fallback); + return UniquePtrChars(JS_EncodeString(cx, fallback)); } static bool diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index 8def46aad5e2..10032393b911 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -11,6 +11,8 @@ * JS bytecode definitions. */ +#include "mozilla/UniquePtr.h" + #include "jsbytecode.h" #include "jstypes.h" #include "NamespaceImports.h" @@ -560,7 +562,7 @@ GetVariableBytecodeLength(jsbytecode *pc); * * The caller must call JS_free on the result after a successful call. */ -char * +mozilla::UniquePtr DecompileValueGenerator(JSContext *cx, int spindex, HandleValue v, HandleString fallback, int skipStackHits = 0); diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index c5cc7c8a3245..f3075720eebf 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -388,10 +388,11 @@ WeakMap_set_impl(JSContext *cx, CallArgs args) MOZ_ASSERT(IsWeakMap(args.thisv())); if (!args.get(0).isObject()) { - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), NullPtr()); if (!bytes) return false; - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get()); return false; } @@ -572,10 +573,11 @@ WeakMap_construct(JSContext *cx, unsigned argc, Value *vp) // Steps 12k-l. if (isOriginalAdder) { if (keyVal.isPrimitive()) { - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, NullPtr()); if (!bytes) return false; - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get()); return false; } diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp index c082573cbb5e..8ae2b7eb8730 100644 --- a/js/src/perf/jsperf.cpp +++ b/js/src/perf/jsperf.cpp @@ -210,10 +210,11 @@ static PerfMeasurement* GetPM(JSContext* cx, JS::HandleValue value, const char* fname) { if (!value.isObject()) { - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, NullPtr()); + UniquePtr bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, NullPtr()); if (!bytes) return nullptr; - JS_ReportErrorNumber(cx, GetErrorMessage, 0, JSMSG_NOT_NONNULL_OBJECT, bytes); + JS_ReportErrorNumber(cx, GetErrorMessage, 0, JSMSG_NOT_NONNULL_OBJECT, bytes.get()); return nullptr; } RootedObject obj(cx, &value.toObject()); diff --git a/js/src/vm/ForOfIterator.cpp b/js/src/vm/ForOfIterator.cpp index 418650c406dc..65496230a7bd 100644 --- a/js/src/vm/ForOfIterator.cpp +++ b/js/src/vm/ForOfIterator.cpp @@ -17,6 +17,8 @@ using namespace js; using JS::ForOfIterator; +using mozilla::UniquePtr; + bool ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavior) { @@ -69,11 +71,11 @@ ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavio // throw an inscrutable error message about |method| rather than this nice // one about |obj|. if (!callee.isObject() || !callee.toObject().isCallable()) { - char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr()); + UniquePtr bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, + iterable, NullPtr()); if (!bytes) return false; - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes); - js_free(bytes); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes.get()); return false; } diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 0492fe186e16..166a3861de6a 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -173,7 +173,7 @@ js::intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp) } else if (val.isString()) { errorArgs[i - 1].encodeLatin1(cx, val.toString()); } else { - errorArgs[i - 1].initBytes(DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr())); + errorArgs[i - 1].initBytes(DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr()).release()); } if (!errorArgs[i - 1]) return false;