Bug 1289050 - Part 2.2: Use ASCII variant of JS_ReportError when formatting JSClass::name, and assert it is ASCII. r=jwalden
authorTooru Fujisawa <arai_a@mac.com>
Fri, 30 Sep 2016 12:34:43 +0900
changeset 315949 b353e488f0eb8a6295db6275273157016963e31c
parent 315948 968d21d7f16d1790dd70365f81aa5ba18a4cf95b
child 315950 fd72da5a490517502ec2eca4bd5eedb9400c997c
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 2.2: Use ASCII variant of JS_ReportError when formatting JSClass::name, and assert it is ASCII. r=jwalden
js/public/CharacterEncoding.h
js/src/jscntxt.cpp
js/src/shell/js.cpp
js/src/vm/CharacterEncoding.cpp
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
--- a/js/public/CharacterEncoding.h
+++ b/js/public/CharacterEncoding.h
@@ -318,14 +318,21 @@ UTF8CharsToNewLatin1CharsZ(JSContext* cx
 /*
  * Return a null-terminated Latin-1 string copied from the input string,
  * storing its length (excluding null terminator) in |*outlen|.  Non-Latin-1
  * codepoints are replaced by '?'.  Returns Latin1CharsZ() on failure.
  */
 extern Latin1CharsZ
 LossyUTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
 
+/*
+ * Returns true if all characters in the given null-terminated string are
+ * ASCII, i.e. < 0x80, false otherwise.
+ */
+extern bool
+StringIsASCII(const char* s);
+
 } // namespace JS
 
 inline void JS_free(JS::Latin1CharsZ& ptr) { js_free((void*)ptr.get()); }
 inline void JS_free(JS::UTF8CharsZ& ptr) { js_free((void*)ptr.get()); }
 
 #endif /* js_CharacterEncoding_h */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -312,27 +312,16 @@ checkReportFlags(JSContext* cx, unsigned
 
     /* Warnings become errors when JSOPTION_WERROR is set. */
     if (JSREPORT_IS_WARNING(*flags) && cx->options().werror())
         *flags &= ~JSREPORT_WARNING;
 
     return false;
 }
 
-#ifdef DEBUG
-static void
-AssertIsASCII(const char* s)
-{
-    while (*s) {
-        MOZ_ASSERT((*s & 0x80) == 0);
-        s++;
-    }
-}
-#endif
-
 bool
 js::ReportErrorVA(JSContext* cx, unsigned flags, const char* format,
                   ErrorArgumentsType argumentsType, va_list ap)
 {
     char* message;
     char16_t* ucmessage;
     size_t messagelen;
     JSErrorReport report;
@@ -343,20 +332,17 @@ js::ReportErrorVA(JSContext* cx, unsigne
 
     message = JS_vsmprintf(format, ap);
     if (!message) {
         ReportOutOfMemory(cx);
         return false;
     }
     messagelen = strlen(message);
 
-#ifdef DEBUG
-    if (argumentsType == ArgumentsAreASCII)
-        AssertIsASCII(message);
-#endif
+    MOZ_ASSERT_IF(argumentsType == ArgumentsAreASCII, JS::StringIsASCII(message));
 
     report.flags = flags;
     report.errorNumber = JSMSG_USER_DEFINED_ERROR;
     if (argumentsType == ArgumentsAreASCII || argumentsType == ArgumentsAreLatin1) {
         ucmessage = InflateString(cx, message, &messagelen);
     } else {
         JS::UTF8Chars utf8(message, messagelen);
         size_t unused;
@@ -565,20 +551,17 @@ class MOZ_RAII AutoMessageArgs
         }
         for (uint16_t i = 0; i < count_; i++) {
             if (passed_) {
                 lengths_[i] = js_strlen(args_[i]);
             } else if (typeArg == ArgumentsAreASCII || typeArg == ArgumentsAreLatin1) {
                 const char* charArg = va_arg(ap, char*);
                 size_t charArgLength = strlen(charArg);
 
-#ifdef DEBUG
-                if (typeArg == ArgumentsAreASCII)
-                    AssertIsASCII(charArg);
-#endif
+                MOZ_ASSERT_IF(typeArg == ArgumentsAreASCII, JS::StringIsASCII(charArg));
 
                 args_[i] = InflateString(cx, charArg, &charArgLength);
                 if (!args_[i])
                     return false;
                 allocatedElements_ = true;
                 MOZ_ASSERT(charArgLength == js_strlen(args_[i]));
                 lengths_[i] = charArgLength;
             } else if (typeArg == ArgumentsAreUTF8) {
@@ -626,20 +609,17 @@ js::ExpandErrorArgumentsVA(ExclusiveCont
     {
         AutoSuppressGC suppressGC(cx);
         efs = callback(userRef, errorNumber);
     }
 
     if (efs) {
         reportp->exnType = efs->exnType;
 
-#ifdef DEBUG
-        if (argumentsType == ArgumentsAreASCII)
-            AssertIsASCII(efs->format);
-#endif
+        MOZ_ASSERT_IF(argumentsType == ArgumentsAreASCII, JS::StringIsASCII(efs->format));
 
         uint16_t argCount = efs->argCount;
         MOZ_RELEASE_ASSERT(argCount <= JS::MaxNumErrorArguments);
         if (argCount > 0) {
             /*
              * Parse the error format, substituting the argument X
              * for {X} in the format.
              */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3785,17 +3785,17 @@ Compile(JSContext* cx, unsigned argc, Va
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "compile", "0", "s");
         return false;
     }
     if (!args[0].isString()) {
         const char* typeName = InformalValueTypeName(args[0]);
-        JS_ReportError(cx, "expected string to compile, got %s", typeName);
+        JS_ReportErrorASCII(cx, "expected string to compile, got %s", typeName);
         return false;
     }
 
     RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
     JSFlatString* scriptContents = args[0].toString()->ensureFlat(cx);
     if (!scriptContents)
         return false;
 
@@ -3822,30 +3822,30 @@ ParseModule(JSContext* cx, unsigned argc
     if (args.length() == 0) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_MORE_ARGS_NEEDED, "parseModule", "0", "s");
         return false;
     }
 
     if (!args[0].isString()) {
         const char* typeName = InformalValueTypeName(args[0]);
-        JS_ReportError(cx, "expected string to compile, got %s", typeName);
+        JS_ReportErrorASCII(cx, "expected string to compile, got %s", typeName);
         return false;
     }
 
     JSFlatString* scriptContents = args[0].toString()->ensureFlat(cx);
     if (!scriptContents)
         return false;
 
     UniqueChars filename;
     CompileOptions options(cx);
     if (args.length() > 1) {
         if (!args[1].isString()) {
             const char* typeName = InformalValueTypeName(args[1]);
-            JS_ReportError(cx, "expected filename string, got %s", typeName);
+            JS_ReportErrorASCII(cx, "expected filename string, got %s", typeName);
             return false;
         }
 
         RootedString str(cx, args[1].toString());
         filename.reset(JS_EncodeString(cx, str));
         if (!filename)
             return false;
 
@@ -3877,17 +3877,17 @@ SetModuleResolveHook(JSContext* cx, unsi
     if (args.length() != 1) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_MORE_ARGS_NEEDED, "setModuleResolveHook", "0", "s");
         return false;
     }
 
     if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         const char* typeName = InformalValueTypeName(args[0]);
-        JS_ReportError(cx, "expected hook function, got %s", typeName);
+        JS_ReportErrorASCII(cx, "expected hook function, got %s", typeName);
         return false;
     }
 
     RootedFunction hook(cx, &args[0].toObject().as<JSFunction>());
     Rooted<GlobalObject*> global(cx, cx->global());
     global->setModuleResolveHook(hook);
     args.rval().setUndefined();
     return true;
@@ -3910,17 +3910,17 @@ Parse(JSContext* cx, unsigned argc, Valu
 
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "parse", "0", "s");
         return false;
     }
     if (!args[0].isString()) {
         const char* typeName = InformalValueTypeName(args[0]);
-        JS_ReportError(cx, "expected string to parse, got %s", typeName);
+        JS_ReportErrorASCII(cx, "expected string to parse, got %s", typeName);
         return false;
     }
 
     JSFlatString* scriptContents = args[0].toString()->ensureFlat(cx);
     if (!scriptContents)
         return false;
 
     AutoStableStringChars stableChars(cx);
@@ -3961,17 +3961,17 @@ SyntaxParse(JSContext* cx, unsigned argc
 
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "parse", "0", "s");
         return false;
     }
     if (!args[0].isString()) {
         const char* typeName = InformalValueTypeName(args[0]);
-        JS_ReportError(cx, "expected string to parse, got %s", typeName);
+        JS_ReportErrorASCII(cx, "expected string to parse, got %s", typeName);
         return false;
     }
 
     JSFlatString* scriptContents = args[0].toString()->ensureFlat(cx);
     if (!scriptContents)
         return false;
     CompileOptions options(cx);
     options.setIntroductionType("js shell syntaxParse")
@@ -4026,17 +4026,17 @@ OffThreadCompileScript(JSContext* cx, un
 
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "offThreadCompileScript", "0", "s");
         return false;
     }
     if (!args[0].isString()) {
         const char* typeName = InformalValueTypeName(args[0]);
-        JS_ReportError(cx, "expected string to parse, got %s", typeName);
+        JS_ReportErrorASCII(cx, "expected string to parse, got %s", typeName);
         return false;
     }
 
     JSAutoByteString fileNameBytes;
     CompileOptions options(cx);
     options.setIntroductionType("js shell offThreadCompileScript")
            .setFileAndLine("<string>", 1);
 
--- a/js/src/vm/CharacterEncoding.cpp
+++ b/js/src/vm/CharacterEncoding.cpp
@@ -513,8 +513,19 @@ JS::ConstUTF8CharsZ::validate(size_t aLe
     InflateUTF8StringToBuffer<AssertNoInvalids, char16_t, JSContext>(
         /* cx = */ nullptr,
         chars,
         /* dst = */ nullptr,
         /* dstlen = */ nullptr,
         /* smallestEncoding = */ nullptr);
 }
 #endif
+
+bool
+JS::StringIsASCII(const char* s)
+{
+    while (*s) {
+        if (*s & 0x80)
+            return false;
+        s++;
+    }
+    return true;
+}
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -8,16 +8,17 @@
 
 #include "jshashutil.h"
 #include "jsobj.h"
 
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "gc/StoreBuffer.h"
 #include "gc/Zone.h"
+#include "js/CharacterEncoding.h"
 #include "vm/ArrayObject.h"
 #include "vm/TaggedProto.h"
 #include "vm/UnboxedObject.h"
 
 #include "jsobjinlines.h"
 
 #include "vm/UnboxedObject-inl.h"
 
@@ -32,16 +33,17 @@ using mozilla::PodZero;
 
 ObjectGroup::ObjectGroup(const Class* clasp, TaggedProto proto, JSCompartment* comp,
                          ObjectGroupFlags initialFlags)
 {
     PodZero(this);
 
     /* Windows may not appear on prototype chains. */
     MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject()));
+    MOZ_ASSERT(JS::StringIsASCII(clasp->name));
 
     this->clasp_ = clasp;
     this->proto_ = proto;
     this->compartment_ = comp;
     this->flags_ = initialFlags;
 
     setGeneration(zone()->types.generation);
 }
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -7,16 +7,17 @@
 #ifndef vm_ObjectGroup_h
 #define vm_ObjectGroup_h
 
 #include "jsbytecode.h"
 #include "jsfriendapi.h"
 
 #include "ds/IdValuePair.h"
 #include "gc/Barrier.h"
+#include "js/CharacterEncoding.h"
 #include "js/GCHashTable.h"
 #include "vm/TaggedProto.h"
 #include "vm/TypeInference.h"
 
 namespace js {
 
 class TypeDescr;
 class UnboxedLayout;
@@ -97,16 +98,17 @@ class ObjectGroup : public gc::TenuredCe
 
   public:
 
     const Class* clasp() const {
         return clasp_;
     }
 
     void setClasp(const Class* clasp) {
+        MOZ_ASSERT(JS::StringIsASCII(clasp->name));
         clasp_ = clasp;
     }
 
     bool hasDynamicPrototype() const {
         return proto_.isDynamic();
     }
 
     const GCPtr<TaggedProto>& proto() const {