Bug 1289050 - Part 4: Use Latin1 or UTF8 variants of JS_ReportError in js shell. r=sfink
authorTooru Fujisawa <arai_a@mac.com>
Mon, 15 Aug 2016 19:20:08 +0900
changeset 315952 2abf8aadd55680cec8955d41a7aa69caef0b67b0
parent 315951 125555035882e55c1abc8103be89e6ecf26c3ce1
child 315953 865b287375d7ef16ceb8092f18aa91ba625d1095
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)
reviewerssfink
bugs1289050
milestone52.0a1
Bug 1289050 - Part 4: Use Latin1 or UTF8 variants of JS_ReportError in js shell. r=sfink
js/src/shell/OSObject.cpp
js/src/shell/OSObject.h
js/src/shell/js.cpp
js/src/shell/jsshell.h
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -148,55 +148,82 @@ ResolvePath(JSContext* cx, HandleString 
     strncpy(buffer + len + 1, filename.ptr(), sizeof(buffer) - (len+1));
     if (buffer[PATH_MAX] != '\0')
         return nullptr;
 
     return JS_NewStringCopyZ(cx, buffer);
 }
 
 JSObject*
-FileAsTypedArray(JSContext* cx, const char* pathname)
+FileAsTypedArray(JSContext* cx, JS::HandleString pathnameStr)
 {
-    FILE* file = fopen(pathname, "rb");
+    JSAutoByteString pathname(cx, pathnameStr);
+    if (!pathname)
+        return nullptr;
+
+    FILE* file = fopen(pathname.ptr(), "rb");
     if (!file) {
-        JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
+        /*
+         * Use Latin1 variant here because the encoding of the return value of
+         * strerror function can be non-UTF-8.
+         */
+        JS_ReportErrorLatin1(cx, "can't open %s: %s", pathname.ptr(), strerror(errno));
         return nullptr;
     }
     AutoCloseFile autoClose(file);
 
     RootedObject obj(cx);
     if (fseek(file, 0, SEEK_END) != 0) {
-        JS_ReportError(cx, "can't seek end of %s", pathname);
+        pathname.clear();
+        if (!pathname.encodeUtf8(cx, pathnameStr))
+            return nullptr;
+        JS_ReportErrorUTF8(cx, "can't seek end of %s", pathname.ptr());
     } else {
         size_t len = ftell(file);
         if (fseek(file, 0, SEEK_SET) != 0) {
-            JS_ReportError(cx, "can't seek start of %s", pathname);
+            pathname.clear();
+            if (!pathname.encodeUtf8(cx, pathnameStr))
+                return nullptr;
+            JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.ptr());
         } else {
             obj = JS_NewUint8Array(cx, len);
             if (!obj)
                 return nullptr;
             js::TypedArrayObject& ta = obj->as<js::TypedArrayObject>();
             if (ta.isSharedMemory()) {
                 // Must opt in to use shared memory.  For now, don't.
                 //
                 // (It is incorrect to read into the buffer without
                 // synchronization since that can create a race.  A
                 // lock here won't fix it - both sides must
                 // participate.  So what one must do is to create a
                 // temporary buffer, read into that, and use a
                 // race-safe primitive to copy memory into the
                 // buffer.)
-                JS_ReportError(cx, "can't read %s: shared memory buffer", pathname);
+                pathname.clear();
+                if (!pathname.encodeUtf8(cx, pathnameStr))
+                    return nullptr;
+                JS_ReportErrorUTF8(cx, "can't read %s: shared memory buffer", pathname.ptr());
                 return nullptr;
             }
             char* buf = static_cast<char*>(ta.viewDataUnshared());
             size_t cc = fread(buf, 1, len, file);
             if (cc != len) {
-                JS_ReportError(cx, "can't read %s: %s", pathname,
-                               (ptrdiff_t(cc) < 0) ? strerror(errno) : "short read");
+                if (ptrdiff_t(cc) < 0) {
+                    /*
+                     * Use Latin1 variant here because the encoding of the return
+                     * value of strerror function can be non-UTF-8.
+                     */
+                    JS_ReportErrorLatin1(cx, "can't read %s: %s", pathname.ptr(), strerror(errno));
+                } else {
+                    pathname.clear();
+                    if (!pathname.encodeUtf8(cx, pathnameStr))
+                        return nullptr;
+                    JS_ReportErrorUTF8(cx, "can't read %s: short read", pathname.ptr());
+                }
                 obj = nullptr;
             }
         }
     }
     return obj;
 }
 
 static bool
@@ -216,37 +243,33 @@ ReadFile(JSContext* cx, unsigned argc, V
         return false;
     }
 
     RootedString givenPath(cx, args[0].toString());
     RootedString str(cx, js::shell::ResolvePath(cx, givenPath, scriptRelative ? ScriptRelative : RootRelative));
     if (!str)
         return false;
 
-    JSAutoByteString filename(cx, str);
-    if (!filename)
-        return false;
-
     if (args.length() > 1) {
         JSString* opt = JS::ToString(cx, args[1]);
         if (!opt)
             return false;
         bool match;
         if (!JS_StringEqualsAscii(cx, opt, "binary", &match))
             return false;
         if (match) {
             JSObject* obj;
-            if (!(obj = FileAsTypedArray(cx, filename.ptr())))
+            if (!(obj = FileAsTypedArray(cx, str)))
                 return false;
             args.rval().setObject(*obj);
             return true;
         }
     }
 
-    if (!(str = FileAsString(cx, filename.ptr())))
+    if (!(str = FileAsString(cx, str)))
         return false;
     args.rval().setString(str);
     return true;
 }
 
 static bool
 osfile_readFile(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -280,17 +303,21 @@ osfile_writeTypedArrayToFile(JSContext* 
         return false;
 
     JSAutoByteString filename(cx, str);
     if (!filename)
         return false;
 
     FILE* file = fopen(filename.ptr(), "wb");
     if (!file) {
-        JS_ReportError(cx, "can't open %s: %s", filename.ptr(), strerror(errno));
+        /*
+         * Use Latin1 variant here because the encoding of the return value of
+         * strerror function can be non-UTF-8.
+         */
+        JS_ReportErrorLatin1(cx, "can't open %s: %s", filename.ptr(), strerror(errno));
         return false;
     }
     AutoCloseFile autoClose(file);
 
     TypedArrayObject* obj = &args[1].toObject().as<TypedArrayObject>();
 
     if (obj->isSharedMemory()) {
         // Must opt in to use shared memory.  For now, don't.
@@ -429,17 +456,21 @@ redirect(JSContext* cx, HandleString rel
     RootedString filename(cx, ResolvePath(cx, relFilename, RootRelative));
     if (!filename)
         return nullptr;
     JSAutoByteString filenameABS(cx, filename);
     if (!filenameABS)
         return nullptr;
     RCFile* file = RCFile::create(cx, filenameABS.ptr(), "wb");
     if (!file) {
-        JS_ReportError(cx, "cannot redirect to %s: %s", filenameABS.ptr(), strerror(errno));
+        /*
+         * Use Latin1 variant here because the encoding of the return value of
+         * strerror function can be non-UTF-8.
+         */
+        JS_ReportErrorLatin1(cx, "cannot redirect to %s: %s", filenameABS.ptr(), strerror(errno));
         return nullptr;
     }
 
     // Grant the global gOutFile ownership of the new file, release ownership
     // of its old file, and return a FileObject owning the old file.
     file->acquire(); // Global owner of new file
 
     FileObject* fileObj = FileObject::create(cx, *globalFile); // Newly created owner of old file
@@ -726,17 +757,21 @@ ReportSysError(JSContext* cx, const char
     size_t nbytes = strlen(prefix) + strlen(errstr) + 3;
     char* final = (char*) js_malloc(nbytes);
     if (!final) {
         JS_ReportOutOfMemory(cx);
         return;
     }
 
     snprintf(final, nbytes, "%s: %s", prefix, errstr);
-    JS_ReportError(cx, final);
+    /*
+     * Use Latin1 variant here because the encoding of the return value of
+     * strerror_s and strerror_r function can be non-UTF-8.
+     */
+    JS_ReportErrorLatin1(cx, "%s", final);
     js_free(final);
 }
 
 static bool
 os_system(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
--- a/js/src/shell/OSObject.h
+++ b/js/src/shell/OSObject.h
@@ -26,14 +26,14 @@ enum PathResolutionMode {
     RootRelative,
     ScriptRelative
 };
 
 JSString*
 ResolvePath(JSContext* cx, JS::HandleString filenameStr, PathResolutionMode resolveMode);
 
 JSObject*
-FileAsTypedArray(JSContext* cx, const char* pathname);
+FileAsTypedArray(JSContext* cx, JS::HandleString pathnameStr);
 
 } // namespace shell
 } // namespace js
 
 #endif /* shell_OSObject_h */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -961,17 +961,21 @@ ReadEvalPrintLoop(JSContext* cx, FILE* i
         do {
             ScheduleWatchdog(cx, -1);
             sc->serviceInterrupt = false;
             errno = 0;
 
             char* line = GetLine(in, startline == lineno ? "js> " : "");
             if (!line) {
                 if (errno) {
-                    JS_ReportError(cx, strerror(errno));
+                    /*
+                     * Use Latin1 variant here because the encoding of the
+                     * return value of strerror function can be non-UTF-8.
+                     */
+                    JS_ReportErrorLatin1(cx, "%s", strerror(errno));
                     return false;
                 }
                 hitEOF = true;
                 break;
             }
 
             if (!buffer.append(line, strlen(line)) || !buffer.append('\n'))
                 return false;
@@ -1716,48 +1720,68 @@ Evaluate(JSContext* cx, unsigned argc, V
 
         saveBuffer.forget();
     }
 
     return JS_WrapValue(cx, args.rval());
 }
 
 JSString*
-js::shell::FileAsString(JSContext* cx, const char* pathname)
-{
+js::shell::FileAsString(JSContext* cx, JS::HandleString pathnameStr)
+{
+    JSAutoByteString pathname(cx, pathnameStr);
+    if (!pathname)
+        return nullptr;
+
     FILE* file;
     RootedString str(cx);
     size_t len, cc;
     char* buf;
 
-    file = fopen(pathname, "rb");
+    file = fopen(pathname.ptr(), "rb");
     if (!file) {
-        JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
+        /*
+         * Use Latin1 variant here because the encoding of the return value of
+         * strerror function can be non-UTF-8.
+         */
+        JS_ReportErrorLatin1(cx, "can't open %s: %s", pathname.ptr(), strerror(errno));
         return nullptr;
     }
     AutoCloseFile autoClose(file);
 
     if (fseek(file, 0, SEEK_END) != 0) {
-        JS_ReportError(cx, "can't seek end of %s", pathname);
+        pathname.clear();
+        if (!pathname.encodeUtf8(cx, pathnameStr))
+            return nullptr;
+        JS_ReportErrorUTF8(cx, "can't seek end of %s", pathname.ptr());
     } else {
         len = ftell(file);
         if (fseek(file, 0, SEEK_SET) != 0) {
-            JS_ReportError(cx, "can't seek start of %s", pathname);
+            pathname.clear();
+            if (!pathname.encodeUtf8(cx, pathnameStr))
+                return nullptr;
+            JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.ptr());
         } else {
             buf = (char*) JS_malloc(cx, len + 1);
             if (buf) {
                 cc = fread(buf, 1, len, file);
                 if (cc != len) {
-                    JS_ReportError(cx, "can't read %s: %s", pathname,
-                                   (ptrdiff_t(cc) < 0) ? strerror(errno) : "short read");
+                    pathname.clear();
+                    if (!pathname.encodeUtf8(cx, pathnameStr))
+                        return nullptr;
+                    JS_ReportErrorUTF8(cx, "can't read %s: %s", pathname.ptr(),
+                                       (ptrdiff_t(cc) < 0) ? strerror(errno) : "short read");
                 } else {
                     char16_t* ucbuf =
                         JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(buf, len), &len).get();
                     if (!ucbuf) {
-                        JS_ReportError(cx, "Invalid UTF-8 in file '%s'", pathname);
+                        pathname.clear();
+                        if (!pathname.encodeUtf8(cx, pathnameStr))
+                            return nullptr;
+                        JS_ReportErrorUTF8(cx, "Invalid UTF-8 in file '%s'", pathname.ptr());
                         return nullptr;
                     }
                     str = JS_NewUCStringCopyN(cx, ucbuf, len);
                     free(ucbuf);
                 }
                 JS_free(cx, buf);
             }
         }
@@ -1779,34 +1803,36 @@ Run(JSContext* cx, unsigned argc, Value*
         JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "run");
         return false;
     }
 
     RootedString str(cx, JS::ToString(cx, args[0]));
     if (!str)
         return false;
     args[0].setString(str);
-    JSAutoByteString filename(cx, str);
-    if (!filename)
-        return false;
-
-    str = FileAsString(cx, filename.ptr());
+
+    str = FileAsString(cx, str);
     if (!str)
         return false;
 
     AutoStableStringChars chars(cx);
     if (!chars.initTwoByte(cx, str))
         return false;
 
     const char16_t* ucbuf = chars.twoByteRange().start().get();
     size_t buflen = str->length();
 
     RootedScript script(cx);
     int64_t startClock = PRMJ_Now();
     {
+        /* FIXME: This should use UTF-8 (bug 987069). */
+        JSAutoByteString filename(cx, str);
+        if (!filename)
+            return false;
+
         JS::CompileOptions options(cx);
         options.setIntroductionType("js shell run")
                .setFileAndLine(filename.ptr(), 1)
                .setIsRunOnce(true)
                .setNoScriptRval(true);
         if (!JS_CompileUCScript(cx, ucbuf, buflen, options, &script))
             return false;
     }
@@ -2834,17 +2860,18 @@ DisassWithSrc(JSContext* cx, unsigned ar
         if (!sprinter.init())
             return false;
 
         /* burn the leading lines */
         line2 = PCToLineNumber(script, pc);
         for (line1 = 0; line1 < line2 - 1; line1++) {
             char* tmp = fgets(linebuf, lineBufLen, file);
             if (!tmp) {
-                JS_ReportError(cx, "failed to read %s fully", script->filename());
+                /* FIXME: This should use UTF-8 (bug 987069). */
+                JS_ReportErrorLatin1(cx, "failed to read %s fully", script->filename());
                 return false;
             }
         }
 
         bupline = 0;
         while (pc < end) {
             line2 = PCToLineNumber(script, pc);
 
--- a/js/src/shell/jsshell.h
+++ b/js/src/shell/jsshell.h
@@ -35,17 +35,17 @@ class MOZ_STACK_CLASS AutoReportExceptio
     {}
     ~AutoReportException();
 };
 
 bool
 GenerateInterfaceHelp(JSContext* cx, JS::HandleObject obj, const char* name);
 
 JSString*
-FileAsString(JSContext* cx, const char* pathname);
+FileAsString(JSContext* cx, JS::HandleString pathnameStr);
 
 class AutoCloseFile
 {
   private:
     FILE* f_;
   public:
     explicit AutoCloseFile(FILE* f) : f_(f) {}
     ~AutoCloseFile() {