diff --git a/js/public/Utility.h b/js/public/Utility.h index 89c495e41116..7f750c636bf6 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -563,6 +563,16 @@ js_pod_calloc(size_t numElems) return (T *)js_calloc(numElems * sizeof(T)); } +template +static MOZ_ALWAYS_INLINE T * +js_pod_realloc(T *prior, size_t oldSize, size_t newSize) +{ + MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask::value)); + if (newSize & mozilla::tl::MulOverflowMask::value) + return nullptr; + return (T *)js_realloc(prior, newSize * sizeof(T)); +} + namespace js { template diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index 555d3b256442..50f7a4df3558 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -529,11 +529,14 @@ class LifoAllocPolicy memset(p, 0, numElems * sizeof(T)); return p; } - void *realloc_(void *p, size_t oldBytes, size_t bytes) { - void *n = malloc_(bytes); + template + T *pod_realloc(T *p, size_t oldSize, size_t newSize) { + if (newSize & mozilla::tl::MulOverflowMask::value) + return nullptr; + T *n = (T *)malloc_(newSize * sizeof(T)); if (fb == Fallible && !n) return nullptr; - memcpy(n, p, Min(oldBytes, bytes)); + memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T))); return n; } void free_(void *p) { diff --git a/js/src/gc/ForkJoinNursery.cpp b/js/src/gc/ForkJoinNursery.cpp index 2f474437d934..d715f753ad3a 100644 --- a/js/src/gc/ForkJoinNursery.cpp +++ b/js/src/gc/ForkJoinNursery.cpp @@ -585,16 +585,13 @@ ForkJoinNursery::reallocateSlots(JSObject *obj, HeapSlot *oldSlots, if (newCount & mozilla::tl::MulOverflowMask::value) return nullptr; - size_t oldSize = oldCount * sizeof(HeapSlot); - size_t newSize = newCount * sizeof(HeapSlot); - if (!isInsideNewspace(obj)) { JS_ASSERT_IF(oldSlots, !isInsideNewspace(oldSlots)); - return static_cast(cx_->realloc_(oldSlots, oldSize, newSize)); + return obj->zone()->pod_realloc(oldSlots, oldCount, newCount); } if (!isInsideNewspace(oldSlots)) - return reallocateHugeSlots(oldSlots, oldSize, newSize); + return reallocateHugeSlots(obj, oldSlots, oldCount, newCount); // No-op if we're shrinking, we can't make use of the freed portion. if (newCount < oldCount) @@ -604,6 +601,7 @@ ForkJoinNursery::reallocateSlots(JSObject *obj, HeapSlot *oldSlots, if (!newSlots) return nullptr; + size_t oldSize = oldCount * sizeof(HeapSlot); js_memcpy(newSlots, oldSlots, oldSize); return newSlots; } @@ -650,9 +648,10 @@ ForkJoinNursery::allocateHugeSlots(size_t nslots) } HeapSlot * -ForkJoinNursery::reallocateHugeSlots(HeapSlot *oldSlots, uint32_t oldSize, uint32_t newSize) +ForkJoinNursery::reallocateHugeSlots(JSObject *obj, HeapSlot *oldSlots, + uint32_t oldCount, uint32_t newCount) { - HeapSlot *newSlots = static_cast(cx_->realloc_(oldSlots, oldSize, newSize)); + HeapSlot *newSlots = obj->zone()->pod_realloc(oldSlots, oldCount, newCount); if (!newSlots) return newSlots; diff --git a/js/src/gc/ForkJoinNursery.h b/js/src/gc/ForkJoinNursery.h index f3bef28ed651..38100627b24f 100644 --- a/js/src/gc/ForkJoinNursery.h +++ b/js/src/gc/ForkJoinNursery.h @@ -210,7 +210,8 @@ class ForkJoinNursery // Reallocate an external slot array, unregister the old array and // register the new array. If the allocation fails then leave // everything unchanged. - HeapSlot *reallocateHugeSlots(HeapSlot *oldSlots, uint32_t oldSize, uint32_t newSize); + HeapSlot *reallocateHugeSlots(JSObject *obj, HeapSlot *oldSlots, + uint32_t oldCount, uint32_t newCount); // Walk the list of registered slot arrays and free them all. void sweepHugeSlots(); diff --git a/js/src/jit/IonAllocPolicy.h b/js/src/jit/IonAllocPolicy.h index 831851c1999e..373855bce519 100644 --- a/js/src/jit/IonAllocPolicy.h +++ b/js/src/jit/IonAllocPolicy.h @@ -112,11 +112,15 @@ class IonAllocPolicy memset(p, 0, numElems * sizeof(T)); return p; } - void *realloc_(void *p, size_t oldBytes, size_t bytes) { - void *n = malloc_(bytes); + template + T *pod_realloc(T *p, size_t oldSize, size_t newSize) { + MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask::value)); + if (newSize & mozilla::tl::MulOverflowMask::value) + return nullptr; + T *n = (T *)malloc_(newSize * sizeof(T)); if (!n) return n; - memcpy(n, p, Min(oldBytes, bytes)); + memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T))); return n; } void free_(void *p) { @@ -135,13 +139,6 @@ class OldIonAllocPolicy void *malloc_(size_t bytes) { return GetIonContext()->temp->allocate(bytes); } - void *realloc_(void *p, size_t oldBytes, size_t bytes) { - void *n = malloc_(bytes); - if (!n) - return n; - memcpy(n, p, Min(oldBytes, bytes)); - return n; - } void free_(void *p) { } void reportAllocOverflow() const { diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 6e79eec01910..2389f2cee65f 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1054,7 +1054,7 @@ MPhi::reserveLength(size_t length) { // Initializes a new MPhi to have an Operand vector of at least the given // capacity. This permits use of addInput() instead of addInputSlow(), the - // latter of which may call realloc_(). + // latter of which may call realloc(). JS_ASSERT(numOperands() == 0); #if DEBUG capacity_ = length; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 40d2fa10c8cc..f422afe17d04 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -5250,7 +5250,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode // Use only if capacity has been reserved by reserveLength void addInput(MDefinition *ins); - // Appends a new input to the input vector. May call realloc_(). + // Appends a new input to the input vector. May call realloc(). // Prefer reserveLength() and addInput() instead, where possible. bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr); diff --git a/js/src/jsalloc.h b/js/src/jsalloc.h index a026e7bd0393..8684ac570784 100644 --- a/js/src/jsalloc.h +++ b/js/src/jsalloc.h @@ -27,7 +27,9 @@ class SystemAllocPolicy public: void *malloc_(size_t bytes) { return js_malloc(bytes); } template T *pod_calloc(size_t numElems) { return js_pod_calloc(numElems); } - void *realloc_(void *p, size_t oldBytes, size_t bytes) { return js_realloc(p, bytes); } + template T *pod_realloc(T *p, size_t oldSize, size_t newSize) { + return js_pod_realloc(p, oldSize, newSize); + } void free_(void *p) { js_free(p); } void reportAllocOverflow() const {} }; @@ -70,10 +72,11 @@ class TempAllocPolicy return p; } - void *realloc_(void *p, size_t oldBytes, size_t bytes) { - void *p2 = js_realloc(p, bytes); + template + T *pod_realloc(T *prior, size_t oldSize, size_t newSize) { + T *p2 = js_pod_realloc(prior, oldSize, newSize); if (MOZ_UNLIKELY(!p2)) - p2 = onOutOfMemory(p2, bytes); + p2 = (T *)onOutOfMemory(p2, newSize * sizeof(T)); return p2; } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d667390dd728..67787419ee58 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1439,11 +1439,12 @@ JS_malloc(JSContext *cx, size_t nbytes) } JS_PUBLIC_API(void *) -JS_realloc(JSContext *cx, void *p, size_t nbytes) +JS_realloc(JSContext *cx, void *p, size_t oldBytes, size_t newBytes) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - return cx->realloc_(p, nbytes); + return static_cast(cx->zone()->pod_realloc(static_cast(p), oldBytes, + newBytes)); } JS_PUBLIC_API(void) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 14e8e54d3407..ec5d85ada0c2 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1861,7 +1861,7 @@ extern JS_PUBLIC_API(void *) JS_malloc(JSContext *cx, size_t nbytes); extern JS_PUBLIC_API(void *) -JS_realloc(JSContext *cx, void *p, size_t nbytes); +JS_realloc(JSContext *cx, void *p, size_t oldBytes, size_t newBytes); /* * A wrapper for js_free(p) that may delay js_free(p) invocation as a diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 7f7a8add373d..a55af4ded3bc 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -982,7 +982,6 @@ class ContextAllocPolicy MOZ_IMPLICIT ContextAllocPolicy(ThreadSafeContext *cx) : cx_(cx) {} ThreadSafeContext *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) { js_free(p); } void reportAllocOverflow() const { js_ReportAllocationOverflow(cx_); } }; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 827009af6696..024456acae5c 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -499,7 +499,7 @@ ReadEvalPrintLoop(JSContext *cx, Handle global, FILE *in, FILE *out, * coincides with the end of a line. */ int startline = lineno; - typedef Vector CharBuffer; + typedef Vector CharBuffer; CharBuffer buffer(cx); do { ScheduleWatchdog(cx->runtime(), -1); @@ -1507,7 +1507,7 @@ ReadLine(JSContext *cx, unsigned argc, jsval *vp) char *tmp; bufsize *= 2; if (bufsize > buflength) { - tmp = (char *) JS_realloc(cx, buf, bufsize); + tmp = static_cast(JS_realloc(cx, buf, bufsize / 2, bufsize)); } else { JS_ReportOutOfMemory(cx); tmp = nullptr; @@ -1529,7 +1529,7 @@ ReadLine(JSContext *cx, unsigned argc, jsval *vp) } /* Shrink the buffer to the real size. */ - char *tmp = static_cast(JS_realloc(cx, buf, buflength)); + char *tmp = static_cast(JS_realloc(cx, buf, bufsize, buflength)); if (!tmp) { JS_free(cx, buf); return false; diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index b30cd5e7c504..f1d0bbb02151 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -275,17 +275,22 @@ ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp) static void * AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldptr = nullptr, size_t oldnbytes = 0) { - void *p; + uint8_t *p; // if oldptr is given, then we need to do a realloc if (oldptr) { - p = maybecx ? maybecx->runtime()->reallocCanGC(oldptr, nbytes) : js_realloc(oldptr, nbytes); + uint8_t *prior = static_cast(oldptr); + p = maybecx + ? maybecx->runtime()->pod_reallocCanGC(prior, oldnbytes, nbytes) + : js_pod_realloc(prior, oldnbytes, nbytes); // if we grew the array, we need to set the new bytes to 0 if (p && nbytes > oldnbytes) - memset(reinterpret_cast(p) + oldnbytes, 0, nbytes - oldnbytes); + memset(p + oldnbytes, 0, nbytes - oldnbytes); } else { - p = maybecx ? maybecx->runtime()->callocCanGC(nbytes) : js_calloc(nbytes); + p = maybecx + ? maybecx->runtime()->pod_callocCanGC(nbytes) + : js_pod_calloc(nbytes); } if (!p && maybecx) diff --git a/js/src/vm/MallocProvider.h b/js/src/vm/MallocProvider.h index a9ef261bbbd6..f94487297ef7 100644 --- a/js/src/vm/MallocProvider.h +++ b/js/src/vm/MallocProvider.h @@ -59,30 +59,6 @@ struct MallocProvider return MOZ_LIKELY(!!p) ? p : client->onOutOfMemory(nullptr, bytes); } - void *realloc_(void *p, size_t oldBytes, size_t newBytes) { - Client *client = static_cast(this); - /* - * For compatibility we do not account for realloc that decreases - * previously allocated memory. - */ - if (newBytes > oldBytes) - client->updateMallocCounter(newBytes - oldBytes); - void *p2 = js_realloc(p, newBytes); - return MOZ_LIKELY(!!p2) ? p2 : client->onOutOfMemory(p, newBytes); - } - - void *realloc_(void *p, size_t bytes) { - Client *client = static_cast(this); - /* - * For compatibility we do not account for realloc that increases - * previously allocated memory. - */ - if (!p) - client->updateMallocCounter(bytes); - void *p2 = js_realloc(p, bytes); - return MOZ_LIKELY(!!p2) ? p2 : client->onOutOfMemory(p, bytes); - } - template T *pod_malloc() { return (T *)malloc_(sizeof(T)); @@ -118,7 +94,7 @@ struct MallocProvider template T * - pod_calloc(size_t numElems, JSCompartment *comp = nullptr, JSContext *cx = nullptr) { + pod_calloc(size_t numElems) { if (numElems & mozilla::tl::MulOverflowMask::value) { Client *client = static_cast(this); client->reportAllocationOverflow(); @@ -136,16 +112,27 @@ struct MallocProvider template mozilla::UniquePtr - make_zeroed_pod_array(size_t numElems, - JSCompartment *comp = nullptr, - JSContext *cx = nullptr) - { - return mozilla::UniquePtr(pod_calloc(numElems, comp, cx)); + make_zeroed_pod_array(size_t numElems) { + return mozilla::UniquePtr(pod_calloc(numElems)); } template T *pod_realloc(T *prior, size_t oldSize, size_t newSize) { - return (T *)realloc_(prior, oldSize * sizeof(T), newSize * sizeof(T)); + Client *client = static_cast(this); + T *p = js_pod_realloc(prior, oldSize, newSize); + if (MOZ_LIKELY(p)) { + // For compatibility we do not account for realloc that decreases + // previously allocated memory. + if (newSize > oldSize) + client->updateMallocCounter((newSize - oldSize) * sizeof(T)); + return p; + } + if (newSize & mozilla::tl::MulOverflowMask::value) { + client->reportAllocationOverflow(); + return nullptr; + } + client->onOutOfMemory(prior, newSize * sizeof(T)); + return nullptr; } JS_DECLARE_NEW_METHODS(new_, malloc_, MOZ_ALWAYS_INLINE) diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 222acbd73ad7..d4e02e6ea842 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -1371,18 +1371,28 @@ struct JSRuntime : public JS::shadow::Runtime, static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024; - void *callocCanGC(size_t bytes) { - void *p = (void *)pod_calloc(bytes); + template + T *pod_callocCanGC(size_t numElems) { + T *p = pod_calloc(numElems); if (MOZ_LIKELY(!!p)) return p; - return onOutOfMemoryCanGC(reinterpret_cast(1), bytes); + if (numElems & mozilla::tl::MulOverflowMask::value) { + reportAllocationOverflow(); + return nullptr; + } + return (T *)onOutOfMemoryCanGC(reinterpret_cast(1), numElems * sizeof(T)); } - void *reallocCanGC(void *p, size_t bytes) { - void *p2 = realloc_(p, bytes); + template + T *pod_reallocCanGC(T *p, size_t oldSize, size_t newSize) { + T *p2 = pod_realloc(p, oldSize, newSize); if (MOZ_LIKELY(!!p2)) return p2; - return onOutOfMemoryCanGC(p, bytes); + if (newSize & mozilla::tl::MulOverflowMask::value) { + reportAllocationOverflow(); + return nullptr; + } + return (T *)onOutOfMemoryCanGC(p, newSize * sizeof(T)); } }; @@ -1658,7 +1668,11 @@ class RuntimeAllocPolicy return runtime->pod_calloc(numElems); } - void *realloc_(void *p, size_t bytes) { return runtime->realloc_(p, bytes); } + template + T *pod_realloc(T *p, size_t oldSize, size_t newSize) { + return runtime->pod_realloc(p, oldSize, newSize); + } + void free_(void *p) { js_free(p); } void reportAllocOverflow() const {} }; diff --git a/js/src/vm/StringBuffer.cpp b/js/src/vm/StringBuffer.cpp index 6e25208f9bfa..7cd87eac6e34 100644 --- a/js/src/vm/StringBuffer.cpp +++ b/js/src/vm/StringBuffer.cpp @@ -28,8 +28,7 @@ ExtractWellSized(ExclusiveContext *cx, Buffer &cb) /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */ JS_ASSERT(capacity >= length); if (length > Buffer::sMaxInlineStorage && capacity - length > length / 4) { - size_t bytes = sizeof(CharT) * (length + 1); - CharT *tmp = (CharT *)cx->realloc_(buf, bytes); + CharT *tmp = cx->zone()->pod_realloc(buf, capacity, length + 1); if (!tmp) { js_free(buf); return nullptr; diff --git a/js/src/vm/StringBuffer.h b/js/src/vm/StringBuffer.h index 13799d54925e..67896af0fe99 100644 --- a/js/src/vm/StringBuffer.h +++ b/js/src/vm/StringBuffer.h @@ -33,8 +33,8 @@ class StringBuffer * The Vector's buffer is taken by the new string so use * ContextAllocPolicy. */ - typedef Vector Latin1CharBuffer; - typedef Vector TwoByteCharBuffer; + typedef Vector Latin1CharBuffer; + typedef Vector TwoByteCharBuffer; ExclusiveContext *cx; diff --git a/js/xpconnect/src/XPCLocale.cpp b/js/xpconnect/src/XPCLocale.cpp index 03ecd931e0c6..9109a64bbce7 100644 --- a/js/xpconnect/src/XPCLocale.cpp +++ b/js/xpconnect/src/XPCLocale.cpp @@ -213,8 +213,8 @@ private: // nsIUnicodeDecoder::Convert may use fewer than srcLength PRUnichars if (unicharLength + 1 < srcLength + 1) { char16_t *shrunkUnichars = - (char16_t *)JS_realloc(cx, unichars, - (unicharLength + 1) * sizeof(char16_t)); + static_cast(JS_realloc(cx, unichars, srcLength + 1, + unicharLength + 1)); if (shrunkUnichars) unichars = shrunkUnichars; } diff --git a/memory/replace/dmd/DMD.cpp b/memory/replace/dmd/DMD.cpp index 91dd23daedd5..a8303ff07e1e 100644 --- a/memory/replace/dmd/DMD.cpp +++ b/memory/replace/dmd/DMD.cpp @@ -126,9 +126,12 @@ public: } // This realloc_ is required for this to be a JS container AllocPolicy. - static void* realloc_(void* aPtr, size_t aOldSize, size_t aNewSize) + template + static T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { - return InfallibleAllocPolicy::realloc_(aPtr, aNewSize); + if (aNewSize & mozilla::tl::MulOverflowMask::value) + return nullptr; + return (T*)InfallibleAllocPolicy::realloc_((void *)aPtr, aNewSize * sizeof(T)); } static void* memalign_(size_t aAlignment, size_t aSize) diff --git a/mfbt/AllocPolicy.h b/mfbt/AllocPolicy.h index c2fcd83d4fc5..b8d9b4f054c0 100644 --- a/mfbt/AllocPolicy.h +++ b/mfbt/AllocPolicy.h @@ -12,6 +12,8 @@ #ifndef mozilla_AllocPolicy_h #define mozilla_AllocPolicy_h +#include "mozilla/TemplateLib.h" + #include #include @@ -28,10 +30,9 @@ namespace mozilla { * Responsible for OOM reporting when null is returned. * - template T* pod_calloc(size_t) * Responsible for OOM reporting when null is returned. - * - void* realloc_(void*, size_t, size_t) - * Responsible for OOM reporting when null is returned. The *used* bytes - * of the previous buffer is passed in (rather than the old allocation - * size), in addition to the *new* allocation size requested. + * - template T* pod_realloc(T*, size_t, size_t) + * Responsible for OOM reporting when null is returned. The old allocation + * size is passed in, in addition to the new allocation size requested. * - void free_(void*) * - void reportAllocOverflow() const * Called on allocation overflow (that is, an allocation implicitly tried @@ -61,9 +62,12 @@ public: return static_cast(calloc(aNumElems, sizeof(T))); } - void* realloc_(void* aPtr, size_t aOldBytes, size_t aBytes) + template + T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { - return realloc(aPtr, aBytes); + if (aNewSize & mozilla::tl::MulOverflowMask::value) + return nullptr; + return static_cast(realloc(aPtr, aNewSize * sizeof(T))); } void free_(void* aPtr) diff --git a/mfbt/Vector.h b/mfbt/Vector.h index 8540caf476f4..ba4412ee9557 100644 --- a/mfbt/Vector.h +++ b/mfbt/Vector.h @@ -204,9 +204,7 @@ struct VectorImpl { MOZ_ASSERT(!aV.usingInlineStorage()); MOZ_ASSERT(!CapacityHasExcessSpace(aNewCap)); - size_t oldSize = sizeof(T) * aV.mCapacity; - size_t newSize = sizeof(T) * aNewCap; - T* newbuf = reinterpret_cast(aV.realloc_(aV.mBegin, oldSize, newSize)); + T* newbuf = aV.template pod_realloc(aV.mBegin, aV.mCapacity, aNewCap); if (!newbuf) { return false; }