Bug 1289050 - Part 3: Use UTF8 variant of JS_ReportError after re-encoding string. r=jwalden
authorTooru Fujisawa <arai_a@mac.com>
Mon, 15 Aug 2016 19:20:04 +0900
changeset 315950 fd72da5a490517502ec2eca4bd5eedb9400c997c
parent 315949 b353e488f0eb8a6295db6275273157016963e31c
child 315951 125555035882e55c1abc8103be89e6ecf26c3ce1
push id20634
push usercbook@mozilla.com
push dateFri, 30 Sep 2016 10:10:13 +0000
treeherderfx-team@afe79b010d13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1289050
milestone52.0a1
Bug 1289050 - Part 3: Use UTF8 variant of JS_ReportError after re-encoding string. r=jwalden
ipc/testshell/XPCShellEnvironment.cpp
js/src/builtin/TestingFunctions.cpp
js/src/ctypes/Library.cpp
js/src/jscntxt.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/shell/OSObject.cpp
js/src/shell/js.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCShellImpl.cpp
js/xpconnect/wrappers/AddonWrapper.cpp
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -145,17 +145,20 @@ Load(JSContext *cx,
         JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[i]));
         if (!str)
             return false;
         JSAutoByteString filename(cx, str);
         if (!filename)
             return false;
         FILE *file = fopen(filename.ptr(), "r");
         if (!file) {
-            JS_ReportError(cx, "cannot open file '%s' for reading", filename.ptr());
+            filename.clear();
+            if (!filename.encodeUtf8(cx, str))
+                return false;
+            JS_ReportErrorUTF8(cx, "cannot open file '%s' for reading", filename.ptr());
             return false;
         }
         JS::CompileOptions options(cx);
         options.setUTF8(true)
                .setFileAndLine(filename.ptr(), 1);
         JS::Rooted<JSScript*> script(cx);
         bool ok = JS::Compile(cx, options, file, &script);
         fclose(file);
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1542,24 +1542,27 @@ DumpHeap(JSContext* cx, unsigned argc, V
             }
         }
     }
 
     if (args.length() > i) {
         Value v = args[i];
         if (v.isString()) {
             if (!fuzzingSafe) {
-                JSString* str = v.toString();
+                RootedString str(cx, v.toString());
                 JSAutoByteString fileNameBytes;
                 if (!fileNameBytes.encodeLatin1(cx, str))
                     return false;
                 const char* fileName = fileNameBytes.ptr();
                 dumpFile = fopen(fileName, "w");
                 if (!dumpFile) {
-                    JS_ReportError(cx, "can't open %s", fileName);
+                    fileNameBytes.clear();
+                    if (!fileNameBytes.encodeUtf8(cx, str))
+                        return false;
+                    JS_ReportErrorUTF8(cx, "can't open %s", fileNameBytes.ptr());
                     return false;
                 }
             }
             ++i;
         }
     }
 
     if (i != args.length()) {
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -146,35 +146,32 @@ Library::Create(JSContext* cx, Value pat
   }
 
   libSpec.value.pathname = pathBytes;
   libSpec.type = PR_LibSpec_Pathname;
 #endif
 
   PRLibrary* library = PR_LoadLibraryWithFlags(libSpec, 0);
 
+#ifndef XP_WIN
+  JS_free(cx, pathBytes);
+#endif
+
   if (!library) {
     char* error = (char*) JS_malloc(cx, PR_GetErrorTextLength() + 1);
     if (error)
       PR_GetErrorText(error);
 
-#ifdef XP_WIN
-    JS_ReportError(cx, "couldn't open library %hs: %s", pathChars, error);
-#else
-    JS_ReportError(cx, "couldn't open library %s: %s", pathBytes, error);
-    JS_free(cx, pathBytes);
-#endif
+    JSAutoByteString pathCharsUTF8;
+    if (pathCharsUTF8.encodeUtf8(cx, pathStr))
+      JS_ReportErrorUTF8(cx, "couldn't open library %s: %s", pathCharsUTF8.ptr(), error);
     JS_free(cx, error);
     return nullptr;
   }
 
-#ifndef XP_WIN
-  JS_free(cx, pathBytes);
-#endif
-
   // stash the library
   JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PrivateValue(library));
 
   return libraryObj;
 }
 
 bool
 Library::IsLibrary(JSObject* obj)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -377,24 +377,21 @@ js::ReportUsageErrorASCII(JSContext* cx,
 
     RootedValue usage(cx);
     if (!JS_GetProperty(cx, callee, "usage", &usage))
         return;
 
     if (!usage.isString()) {
         JS_ReportErrorASCII(cx, "%s", msg);
     } else {
-        JSString* str = usage.toString();
-        if (!str->ensureFlat(cx))
+        RootedString usageStr(cx, usage.toString());
+        JSAutoByteString str;
+        if (!str.encodeUtf8(cx, usageStr))
             return;
-        AutoStableStringChars chars(cx);
-        if (!chars.initTwoByte(cx, str))
-            return;
-
-        JS_ReportError(cx, "%s. Usage: %hs", msg, chars.twoByteRange().start().get());
+        JS_ReportErrorUTF8(cx, "%s. Usage: %s", msg, str.ptr());
     }
 }
 
 bool
 js::PrintError(JSContext* cx, FILE* file, const char* message, JSErrorReport* report,
                bool reportWarnings)
 {
     if (!report) {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1331,28 +1331,28 @@ js::GetAllocationMetadata(JSObject* obj)
 
 JS_FRIEND_API(bool)
 js::ReportIsNotFunction(JSContext* cx, HandleValue v)
 {
     return ReportIsNotFunction(cx, v, -1);
 }
 
 JS_FRIEND_API(void)
-js::ReportErrorWithId(JSContext* cx, const char* msg, HandleId id)
+js::ReportASCIIErrorWithId(JSContext* cx, const char* msg, HandleId id)
 {
     RootedValue idv(cx);
     if (!JS_IdToValue(cx, id, &idv))
         return;
-    JSString* idstr = JS::ToString(cx, idv);
+    RootedString idstr(cx, JS::ToString(cx, idv));
     if (!idstr)
         return;
-    JSAutoByteString bytes(cx, idstr);
-    if (!bytes)
+    JSAutoByteString bytes;
+    if (!bytes.encodeUtf8(cx, idstr))
         return;
-    JS_ReportError(cx, msg, bytes.ptr());
+    JS_ReportErrorUTF8(cx, msg, bytes.ptr());
 }
 
 #ifdef DEBUG
 bool
 js::HasObjectMovedOp(JSObject* obj) {
     return !!GetObjectClass(obj)->extObjectMovedOp();
 }
 #endif
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2775,17 +2775,17 @@ ForwardToNative(JSContext* cx, JSNative 
  */
 JS_FRIEND_API(bool)
 SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
                                JS::HandleValue v, JS::HandleValue receiver,
                                JS::Handle<JS::PropertyDescriptor> ownDesc,
                                JS::ObjectOpResult& result);
 
 JS_FRIEND_API(void)
-ReportErrorWithId(JSContext* cx, const char* msg, JS::HandleId id);
+ReportASCIIErrorWithId(JSContext* cx, const char* msg, JS::HandleId id);
 
 // This function is for one specific use case, please don't use this for anything else!
 extern JS_FRIEND_API(bool)
 ExecuteInGlobalAndReturnScope(JSContext* cx, JS::HandleObject obj, JS::HandleScript script,
                               JS::MutableHandleObject scope);
 
 #if defined(XP_WIN) && defined(_WIN64)
 // Parameters use void* types to avoid #including windows.h. The return value of
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -291,24 +291,30 @@ osfile_writeTypedArrayToFile(JSContext* 
     AutoCloseFile autoClose(file);
 
     TypedArrayObject* obj = &args[1].toObject().as<TypedArrayObject>();
 
     if (obj->isSharedMemory()) {
         // Must opt in to use shared memory.  For now, don't.
         //
         // See further comments in FileAsTypedArray, above.
-        JS_ReportError(cx, "can't write %s: shared memory buffer", filename.ptr());
+        filename.clear();
+        if (!filename.encodeUtf8(cx, str))
+            return false;
+        JS_ReportErrorUTF8(cx, "can't write %s: shared memory buffer", filename.ptr());
         return false;
     }
     void* buf = obj->viewDataUnshared();
     if (fwrite(buf, obj->bytesPerElement(), obj->length(), file) != obj->length() ||
         !autoClose.release())
     {
-        JS_ReportError(cx, "can't write %s", filename.ptr());
+        filename.clear();
+        if (!filename.encodeUtf8(cx, str))
+            return false;
+        JS_ReportErrorUTF8(cx, "can't write %s", filename.ptr());
         return false;
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 /* static */ RCFile*
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1213,39 +1213,39 @@ AddPromiseReactions(JSContext* cx, unsig
 
 static bool
 Options(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JS::ContextOptions oldContextOptions = JS::ContextOptionsRef(cx);
     for (unsigned i = 0; i < args.length(); i++) {
-        JSString* str = JS::ToString(cx, args[i]);
+        RootedString str(cx, JS::ToString(cx, args[i]));
         if (!str)
             return false;
         args[i].setString(str);
 
-        JSAutoByteString opt(cx, str);
-        if (!opt)
+        JSAutoByteString opt;
+        if (!opt.encodeUtf8(cx, str))
             return false;
 
         if (strcmp(opt.ptr(), "strict") == 0)
             JS::ContextOptionsRef(cx).toggleExtraWarnings();
         else if (strcmp(opt.ptr(), "werror") == 0)
             JS::ContextOptionsRef(cx).toggleWerror();
         else if (strcmp(opt.ptr(), "throw_on_asmjs_validation_failure") == 0)
             JS::ContextOptionsRef(cx).toggleThrowOnAsmJSValidationFailure();
         else if (strcmp(opt.ptr(), "strict_mode") == 0)
             JS::ContextOptionsRef(cx).toggleStrictMode();
         else {
-            JS_ReportError(cx,
-                           "unknown option name '%s'."
-                           " The valid names are strict,"
-                           " werror, and strict_mode.",
-                           opt.ptr());
+            JS_ReportErrorUTF8(cx,
+                               "unknown option name '%s'."
+                               " The valid names are strict,"
+                               " werror, and strict_mode.",
+                               opt.ptr());
             return false;
         }
     }
 
     char* names = strdup("");
     bool found = false;
     if (names && oldContextOptions.extraWarnings()) {
         names = JS_sprintf_append(names, "%s%s", found ? "," : "", "strict");
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -885,18 +885,20 @@ xpc::GlobalProperties::Parse(JSContext* 
     for (uint32_t i = 0; i < length; i++) {
         RootedValue nameValue(cx);
         ok = JS_GetElement(cx, obj, i, &nameValue);
         NS_ENSURE_TRUE(ok, false);
         if (!nameValue.isString()) {
             JS_ReportErrorASCII(cx, "Property names must be strings");
             return false;
         }
-        JSAutoByteString name(cx, nameValue.toString());
-        NS_ENSURE_TRUE(name, false);
+        RootedString nameStr(cx, nameValue.toString());
+        JSAutoByteString name;
+        if (!name.encodeUtf8(cx, nameStr))
+            return false;
         if (!strcmp(name.ptr(), "CSS")) {
             CSS = true;
         } else if (!strcmp(name.ptr(), "indexedDB")) {
             indexedDB = true;
         } else if (!strcmp(name.ptr(), "XMLHttpRequest")) {
             XMLHttpRequest = true;
         } else if (!strcmp(name.ptr(), "TextEncoder")) {
             TextEncoder = true;
@@ -924,17 +926,17 @@ xpc::GlobalProperties::Parse(JSContext* 
 #endif
         } else if (!strcmp(name.ptr(), "fetch")) {
             fetch = true;
         } else if (!strcmp(name.ptr(), "caches")) {
             caches = true;
         } else if (!strcmp(name.ptr(), "FileReader")) {
             fileReader = true;
         } else {
-            JS_ReportError(cx, "Unknown property name: %s", name.ptr());
+            JS_ReportErrorUTF8(cx, "Unknown property name: %s", name.ptr());
             return false;
         }
     }
     return true;
 }
 
 bool
 xpc::GlobalProperties::Define(JSContext* cx, JS::HandleObject obj)
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -352,18 +352,21 @@ Load(JSContext* cx, unsigned argc, Value
         str = ToString(cx, args[i]);
         if (!str)
             return false;
         JSAutoByteString filename(cx, str);
         if (!filename)
             return false;
         FILE* file = fopen(filename.ptr(), "r");
         if (!file) {
-            JS_ReportError(cx, "cannot open file '%s' for reading",
-                           filename.ptr());
+            filename.clear();
+            if (!filename.encodeUtf8(cx, str))
+                return false;
+            JS_ReportErrorUTF8(cx, "cannot open file '%s' for reading",
+                               filename.ptr());
             return false;
         }
         JS::CompileOptions options(cx);
         options.setUTF8(true)
                .setFileAndLine(filename.ptr(), 1)
                .setIsRunOnce(true);
         JS::Rooted<JSScript*> script(cx);
         JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
@@ -482,34 +485,36 @@ SendCommand(JSContext* cx, unsigned argc
 }
 
 static bool
 Options(JSContext* cx, unsigned argc, Value* vp)
 {
     JS::CallArgs args = CallArgsFromVp(argc, vp);
     ContextOptions oldContextOptions = ContextOptionsRef(cx);
 
+    RootedString str(cx);
+    JSAutoByteString opt;
     for (unsigned i = 0; i < args.length(); ++i) {
-        JSString* str = ToString(cx, args[i]);
+        str = ToString(cx, args[i]);
         if (!str)
             return false;
 
-        JSAutoByteString opt(cx, str);
-        if (!opt)
+        opt.clear();
+        if (!opt.encodeUtf8(cx, str))
             return false;
 
         if (strcmp(opt.ptr(), "strict") == 0)
             ContextOptionsRef(cx).toggleExtraWarnings();
         else if (strcmp(opt.ptr(), "werror") == 0)
             ContextOptionsRef(cx).toggleWerror();
         else if (strcmp(opt.ptr(), "strict_mode") == 0)
             ContextOptionsRef(cx).toggleStrictMode();
         else {
-            JS_ReportError(cx, "unknown option name '%s'. The valid names are "
-                           "strict, werror, and strict_mode.", opt.ptr());
+            JS_ReportErrorUTF8(cx, "unknown option name '%s'. The valid names are "
+                               "strict, werror, and strict_mode.", opt.ptr());
             return false;
         }
     }
 
     char* names = nullptr;
     if (oldContextOptions.extraWarnings()) {
         names = JS_sprintf_append(names, "%s", "strict");
         if (!names) {
@@ -527,17 +532,17 @@ Options(JSContext* cx, unsigned argc, Va
     if (names && oldContextOptions.strictMode()) {
         names = JS_sprintf_append(names, "%s%s", names ? "," : "", "strict_mode");
         if (!names) {
             JS_ReportOutOfMemory(cx);
             return false;
         }
     }
 
-    JSString* str = JS_NewStringCopyZ(cx, names);
+    str = JS_NewStringCopyZ(cx, names);
     free(names);
     if (!str)
         return false;
 
     args.rval().setString(str);
     return true;
 }
 
@@ -660,18 +665,18 @@ static const JSFunctionSpec glob_functio
 };
 
 static bool
 env_setProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp,
                 ObjectOpResult& result)
 {
 /* XXX porting may be easy, but these don't seem to supply setenv by default */
 #if !defined SOLARIS
-    JSString* valstr;
-    JS::Rooted<JSString*> idstr(cx);
+    RootedString valstr(cx);
+    RootedString idstr(cx);
     int rv;
 
     RootedValue idval(cx);
     if (!JS_IdToValue(cx, id, &idval))
         return false;
 
     idstr = ToString(cx, idval);
     valstr = ToString(cx, vp);
@@ -701,17 +706,23 @@ env_setProperty(JSContext* cx, HandleObj
          */
         free(waste);
 #endif
     }
 #else
     rv = setenv(name.ptr(), value.ptr(), 1);
 #endif
     if (rv < 0) {
-        JS_ReportError(cx, "can't set envariable %s to %s", name.ptr(), value.ptr());
+        name.clear();
+        value.clear();
+        if (!name.encodeUtf8(cx, idstr))
+            return false;
+        if (!value.encodeUtf8(cx, valstr))
+            return false;
+        JS_ReportErrorUTF8(cx, "can't set envariable %s to %s", name.ptr(), value.ptr());
         return false;
     }
     vp.setString(valstr);
 #endif /* !defined SOLARIS */
     return result.succeed();
 }
 
 static bool
--- a/js/xpconnect/wrappers/AddonWrapper.cpp
+++ b/js/xpconnect/wrappers/AddonWrapper.cpp
@@ -226,33 +226,33 @@ AddonWrapper<Base>::defineProperty(JSCon
 {
     Rooted<PropertyDescriptor> interpDesc(cx);
     if (!InterposeProperty(cx, wrapper, nullptr, id, &interpDesc))
         return false;
 
     if (!interpDesc.object())
         return Base::defineProperty(cx, wrapper, id, desc, result);
 
-    js::ReportErrorWithId(cx, "unable to modify interposed property %s", id);
+    js::ReportASCIIErrorWithId(cx, "unable to modify interposed property %s", id);
     return false;
 }
 
 template<typename Base>
 bool
 AddonWrapper<Base>::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
                             ObjectOpResult& result) const
 {
     Rooted<PropertyDescriptor> desc(cx);
     if (!InterposeProperty(cx, wrapper, nullptr, id, &desc))
         return false;
 
     if (!desc.object())
         return Base::delete_(cx, wrapper, id, result);
 
-    js::ReportErrorWithId(cx, "unable to delete interposed property %s", id);
+    js::ReportASCIIErrorWithId(cx, "unable to delete interposed property %s", id);
     return false;
 }
 
 #define AddonWrapperCC AddonWrapper<CrossCompartmentWrapper>
 #define AddonWrapperXrayXPCWN AddonWrapper<PermissiveXrayXPCWN>
 #define AddonWrapperXrayDOM AddonWrapper<PermissiveXrayDOM>
 
 template<> const AddonWrapperCC AddonWrapperCC::singleton(0);