Bug 1033113 - Fix a Latin1/TwoByte rope flattening edge case. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 03 Jul 2014 11:14:42 +0200
changeset 192176 055d2b0cec5785fdcb9972c7e487a7f410c2b622
parent 192175 4e28ce23f4e003d2115a761f111070e68064b720
child 192177 c76b804566e9663ee15b8b568f02180a2dbd43dd
push idunknown
push userunknown
push dateunknown
reviewersluke
bugs1033113
milestone33.0a1
Bug 1033113 - Fix a Latin1/TwoByte rope flattening edge case. r=luke
js/src/jit-test/tests/latin1/bug1033113.js
js/src/vm/String.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/latin1/bug1033113.js
@@ -0,0 +1,20 @@
+var s = "aaaaaaaaaaaaaaaaaa111aaaa";
+var latin1Rope1 = "foo" + s;
+var latin1Rope2 = "bar" + latin1Rope1;
+var twoByteRope = "\u1200--" + latin1Rope1;
+
+// Flatten twoByteRope.
+assertEq(twoByteRope.lastIndexOf("11"), 25);
+
+// latin1Rope1 is now a TwoByte dependent string.
+assertEq(isLatin1(latin1Rope1), false);
+assertEq(latin1Rope1, "fooaaaaaaaaaaaaaaaaaa111aaaa");
+
+// latin1Rope2 should still be Latin1, but now has a
+// TwoByte descendent (latin1Rope1).
+if (isLatin1(s))
+    assertEq(isLatin1(latin1Rope2), true);
+
+// Flatten latin1Rope2.
+assertEq(latin1Rope2.lastIndexOf("11"), 25);
+assertEq(latin1Rope2, "barfooaaaaaaaaaaaaaaaaaa111aaaa");
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -285,17 +285,34 @@ CopyChars(jschar *dest, const JSLinearSt
         CopyAndInflateChars(dest, str.latin1Chars(nogc), str.length());
 }
 
 template <>
 void
 CopyChars(Latin1Char *dest, const JSLinearString &str)
 {
     AutoCheckCannotGC nogc;
-    PodCopy(dest, str.latin1Chars(nogc), str.length());
+    if (str.hasLatin1Chars()) {
+        PodCopy(dest, str.latin1Chars(nogc), str.length());
+    } else {
+        /*
+         * When we flatten a TwoByte rope, we turn child ropes (including Latin1
+         * ropes) into TwoByte dependent strings. If one of these strings is
+         * also part of another Latin1 rope tree, we can have a Latin1 rope with
+         * a TwoByte descendent and we end up here when we flatten it. Although
+         * the chars are stored as TwoByte, we know they must be in the Latin1
+         * range, so we can safely deflate here.
+         */
+        size_t len = str.length();
+        const jschar *chars = str.twoByteChars(nogc);
+        for (size_t i = 0; i < len; i++) {
+            MOZ_ASSERT(chars[i] <= JSString::MAX_LATIN1_CHAR);
+            dest[i] = chars[i];
+        }
+    }
 }
 
 } /* namespace js */
 
 template<JSRope::UsingBarrier b, typename CharT>
 JSFlatString *
 JSRope::flattenInternal(ExclusiveContext *maybecx)
 {