Bug 1289050 - Part 10: Use Latin1 variant of JS_ReportErrorNumber for strerror. r=jwalden
authorTooru Fujisawa <arai_a@mac.com>
Tue, 16 Aug 2016 03:11:59 +0900
changeset 315965 ab961ef0ffd0b57e8a3bf7caafa7e9a1fa6302b2
parent 315964 b1428a6cabc5c470e505841d2306e5ca4c3576f7
child 315966 e35af31d7fd5ea2049d65da77bdd323c5fe7a759
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 10: Use Latin1 variant of JS_ReportErrorNumber for strerror. r=jwalden
js/src/shell/js.cpp
js/xpconnect/src/XPCShellImpl.cpp
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -962,18 +962,18 @@ ReadEvalPrintLoop(JSContext* cx, FILE* i
             ScheduleWatchdog(cx, -1);
             sc->serviceInterrupt = false;
             errno = 0;
 
             char* line = GetLine(in, startline == lineno ? "js> " : "");
             if (!line) {
                 if (errno) {
                     /*
-                     * Use Latin1 variant here because the encoding of the
-                     * return value of strerror function can be non-UTF-8.
+                     * Use Latin1 variant here because strerror(errno)'s
+                     * encoding depends on the user's C locale.
                      */
                     JS_ReportErrorLatin1(cx, "%s", strerror(errno));
                     return false;
                 }
                 hitEOF = true;
                 break;
             }
 
@@ -1019,27 +1019,43 @@ ReadEvalPrintLoop(JSContext* cx, FILE* i
 }
 
 enum FileKind
 {
     FileScript,
     FileModule
 };
 
+static void
+ReportCantOpenErrorUnknownEncoding(JSContext* cx, const char* filename)
+{
+    /*
+     * Filenames are in some random system encoding.  *Probably* it's UTF-8,
+     * but no guarantees.
+     *
+     * strerror(errno)'s encoding, in contrast, depends on the user's C locale.
+     *
+     * Latin-1 is possibly wrong for both of these -- but at least if it's
+     * wrong it'll produce mojibake *safely*.  Run with Latin-1 til someone
+     * complains.
+     */
+    JS_ReportErrorNumberLatin1(cx, my_GetErrorMessage, nullptr, JSSMSG_CANT_OPEN,
+                               filename, strerror(errno));
+}
+
 static MOZ_MUST_USE bool
 Process(JSContext* cx, const char* filename, bool forceTTY, FileKind kind = FileScript)
 {
     FILE* file;
     if (forceTTY || !filename || strcmp(filename, "-") == 0) {
         file = stdin;
     } else {
         file = fopen(filename, "r");
         if (!file) {
-            JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
-                                 JSSMSG_CANT_OPEN, filename, strerror(errno));
+            ReportCantOpenErrorUnknownEncoding(cx, filename);
             return false;
         }
     }
     AutoCloseFile autoClose(file);
 
     if (!forceTTY && !isatty(fileno(file))) {
         // It's not interactive - just execute it.
         if (kind == FileScript) {
@@ -1136,18 +1152,17 @@ CreateMappedArrayBuffer(JSContext* cx, u
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
                                       "2");
             return false;
         }
     }
 
     FILE* file = fopen(filename.ptr(), "r");
     if (!file) {
-        JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
-                             JSSMSG_CANT_OPEN, filename.ptr(), strerror(errno));
+        ReportCantOpenErrorUnknownEncoding(cx, filename.ptr());
         return false;
     }
     AutoCloseFile autoClose(file);
 
     if (!sizeGiven) {
         struct stat st;
         if (fstat(fileno(file), &st) < 0) {
             JS_ReportErrorASCII(cx, "Unable to stat file");
@@ -1736,21 +1751,17 @@ js::shell::FileAsString(JSContext* cx, J
 
     FILE* file;
     RootedString str(cx);
     size_t len, cc;
     char* buf;
 
     file = fopen(pathname.ptr(), "rb");
     if (!file) {
-        /*
-         * 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));
+        ReportCantOpenErrorUnknownEncoding(cx, pathname.ptr());
         return nullptr;
     }
     AutoCloseFile autoClose(file);
 
     if (fseek(file, 0, SEEK_END) != 0) {
         pathname.clear();
         if (!pathname.encodeUtf8(cx, pathnameStr))
             return nullptr;
@@ -1762,21 +1773,24 @@ js::shell::FileAsString(JSContext* cx, J
             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) {
-                    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");
+                    if (ptrdiff_t(cc) < 0) {
+                        ReportCantOpenErrorUnknownEncoding(cx, pathname.ptr());
+                    } else {
+                        pathname.clear();
+                        if (!pathname.encodeUtf8(cx, pathnameStr))
+                            return nullptr;
+                        JS_ReportErrorUTF8(cx, "can't read %s: short read", pathname.ptr());
+                    }
                 } else {
                     char16_t* ucbuf =
                         JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(buf, len), &len).get();
                     if (!ucbuf) {
                         pathname.clear();
                         if (!pathname.encodeUtf8(cx, pathnameStr))
                             return nullptr;
                         JS_ReportErrorUTF8(cx, "Invalid UTF-8 in file '%s'", pathname.ptr());
@@ -2844,19 +2858,18 @@ DisassWithSrc(JSContext* cx, unsigned ar
 
         if (!script->filename()) {
             JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_FILE_SCRIPTS_ONLY);
             return false;
         }
 
         FILE* file = fopen(script->filename(), "r");
         if (!file) {
-            JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
-                                 JSSMSG_CANT_OPEN, script->filename(),
-                                 strerror(errno));
+            /* FIXME: script->filename() should become UTF-8 (bug 987069). */
+            ReportCantOpenErrorUnknownEncoding(cx, script->filename());
             return false;
         }
         auto closeFile = MakeScopeExit([file]() { fclose(file); });
 
         jsbytecode* pc = script->code();
         jsbytecode* end = script->codeEnd();
 
         Sprinter sprinter(cx);
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -923,19 +923,23 @@ Process(AutoJSAPI& jsapi, const char* fi
 {
     FILE* file;
 
     if (forceTTY || !filename || strcmp(filename, "-") == 0) {
         file = stdin;
     } else {
         file = fopen(filename, "r");
         if (!file) {
-            JS_ReportErrorNumber(jsapi.cx(), my_GetErrorMessage, nullptr,
-                                 JSSMSG_CANT_OPEN,
-                                 filename, strerror(errno));
+            /*
+             * Use Latin1 variant here because the encoding of the return value
+             * of strerror function can be non-UTF-8.
+             */
+            JS_ReportErrorNumberLatin1(jsapi.cx(), my_GetErrorMessage, nullptr,
+                                       JSSMSG_CANT_OPEN,
+                                       filename, strerror(errno));
             gExitCode = EXITCODE_FILE_NOT_FOUND;
             return false;
         }
     }
 
     bool ok = ProcessFile(jsapi, filename, file, forceTTY);
     if (file != stdin)
         fclose(file);