Bug 736591 - Ensure that StringBuffer never allocates more memory than is needed to represent a maximum-sized string. Thanks for the technique/idea go to Luke. r=luke
☠☠ backed out by d0a19172c707 ☠ ☠
authorJeff Walden <jwalden@mit.edu>
Tue, 03 Apr 2012 17:18:46 -0700
changeset 94273 6c435c96f10af053ac2e3f2b15f2913dcd1d0808
parent 94272 308440acc7b70223e7ab25aed3305da7e65a762a
child 94274 031f54b058189648760495d4d23a6ad0760eb541
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs736591
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 736591 - Ensure that StringBuffer never allocates more memory than is needed to represent a maximum-sized string. Thanks for the technique/idea go to Luke. r=luke
js/src/jscntxt.h
js/src/vm/StringBuffer.cpp
js/src/vm/StringBuffer.h
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1683,32 +1683,16 @@ class RuntimeAllocPolicy
     RuntimeAllocPolicy(JSRuntime *rt) : runtime(rt) {}
     RuntimeAllocPolicy(JSContext *cx) : runtime(cx->runtime) {}
     void *malloc_(size_t bytes) { return runtime->malloc_(bytes); }
     void *realloc_(void *p, size_t bytes) { return runtime->realloc_(p, bytes); }
     void free_(void *p) { runtime->free_(p); }
     void reportAllocOverflow() const {}
 };
 
-/*
- * FIXME bug 647103 - replace these *AllocPolicy names.
- */
-class ContextAllocPolicy
-{
-    JSContext *const cx;
-
-  public:
-    ContextAllocPolicy(JSContext *cx) : cx(cx) {}
-    JSContext *context() const { return cx; }
-    void *malloc_(size_t bytes) { return cx->malloc_(bytes); }
-    void *realloc_(void *p, size_t oldBytes, size_t bytes) { return cx->realloc_(p, oldBytes, bytes); }
-    void free_(void *p) { cx->free_(p); }
-    void reportAllocOverflow() const { js_ReportAllocationOverflow(cx); }
-};
-
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
 #endif
 
 #endif /* jscntxt_h___ */
--- a/js/src/vm/StringBuffer.cpp
+++ b/js/src/vm/StringBuffer.cpp
@@ -12,16 +12,17 @@
 
 using namespace js;
 
 jschar *
 StringBuffer::extractWellSized()
 {
     size_t capacity = cb.capacity();
     size_t length = cb.length();
+    JS_ASSERT(JSString::validateLength(context(), length));
 
     jschar *buf = cb.extractRawBuffer();
     if (!buf)
         return NULL;
 
     /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
     JS_ASSERT(capacity >= length);
     if (length > CharBuffer::sMaxInlineStorage && capacity - length > length / 4) {
@@ -41,18 +42,17 @@ StringBuffer::extractWellSized()
 JSFixedString *
 StringBuffer::finishString()
 {
     JSContext *cx = context();
     if (cb.empty())
         return cx->runtime->atomState.emptyAtom;
 
     size_t length = cb.length();
-    if (!JSString::validateLength(cx, length))
-        return NULL;
+    JS_ASSERT(JSString::validateLength(cx, length));
 
     JS_STATIC_ASSERT(JSShortString::MAX_SHORT_LENGTH < CharBuffer::InlineLength);
     if (JSShortString::lengthFits(length))
         return NewShortString(cx, cb.begin(), length);
 
     if (!cb.append('\0'))
         return NULL;
 
@@ -67,16 +67,18 @@ StringBuffer::finishString()
 }
 
 JSAtom *
 StringBuffer::finishAtom()
 {
     JSContext *cx = context();
 
     size_t length = cb.length();
+    JS_ASSERT(JSString::validateLength(cx, length));
+
     if (length == 0)
         return cx->runtime->atomState.emptyAtom;
 
     JSAtom *atom = js_AtomizeChars(cx, cb.begin(), length);
     cb.clear();
     return atom;
 }
 
--- a/js/src/vm/StringBuffer.h
+++ b/js/src/vm/StringBuffer.h
@@ -24,18 +24,38 @@ namespace js {
  * exception report on the context and results in a failed return value.
  *
  * Well-sized extractions (which waste no more than 1/4 of their char
  * buffer space) are guaranteed for strings built by this interface.
  * See |extractWellSized|.
  */
 class StringBuffer
 {
-    /* cb's buffer is taken by the new string so use ContextAllocPolicy. */
-    typedef Vector<jschar, 32, ContextAllocPolicy> CharBuffer;
+    class AllocPolicy
+    {
+        JSContext *const cx;
+
+      public:
+        AllocPolicy(JSContext *cx) : cx(cx) {}
+        JSContext *context() const { return cx; }
+        void *malloc_(size_t bytes) {
+            if (!JSString::validateLength(cx, bytes / sizeof(jschar)))
+                return NULL;
+            return cx->malloc_(bytes);
+        }
+        void *realloc_(void *p, size_t oldBytes, size_t bytes) {
+            if (!JSString::validateLength(cx, bytes / sizeof(jschar)))
+                return NULL;
+            return cx->realloc_(p, oldBytes, bytes);
+        }
+        void free_(void *p) { cx->free_(p); }
+        void reportAllocOverflow() const { js_ReportAllocationOverflow(cx); }
+    };
+
+    typedef Vector<jschar, 32, AllocPolicy> CharBuffer;
 
     CharBuffer cb;
 
     JSContext *context() const { return cb.allocPolicy().context(); }
     jschar *extractWellSized();
 
     StringBuffer(const StringBuffer &other) MOZ_DELETE;
     void operator=(const StringBuffer &other) MOZ_DELETE;