Bug 1325200 - Simplify AllocateExecutableMemory, count executable memory size. r=luke,bhackett a=lizzard
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 12 Jan 2017 12:48:36 +0100
changeset 353553 d51ff865f7da04783da5431d287ed24d57ee5a0e
parent 353552 8a89dd47e7847c27ffe04b12832f0cdba7262b56
child 353554 41f18ace160f8aa99ecb68a243d836ece87342b9
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke, bhackett, lizzard
bugs1325200
milestone52.0a2
Bug 1325200 - Simplify AllocateExecutableMemory, count executable memory size. r=luke,bhackett a=lizzard
js/src/jit-test/tests/asm.js/testBug1301191.js
js/src/jit-test/tests/asm.js/testBug975182.js
js/src/jit/ExecutableAllocator.cpp
js/src/jit/ExecutableAllocator.h
js/src/jit/ExecutableAllocatorPosix.cpp
js/src/jit/ExecutableAllocatorWin.cpp
js/src/jsmath.cpp
js/src/jsmath.h
js/src/vm/Initialization.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/TypeInference.cpp
js/src/wasm/WasmCode.cpp
--- a/js/src/jit-test/tests/asm.js/testBug1301191.js
+++ b/js/src/jit-test/tests/asm.js/testBug1301191.js
@@ -9,13 +9,16 @@ timeout(1);
             ff()
         }
         return f
     })(this, {
         ff: arguments.callee
     })
 })()
 function m(f) {
+    var i = 0;
     while (true) {
         f();
+        if ((i++ % 1000) === 0)
+            gc();
     }
 }
 m(g);
--- a/js/src/jit-test/tests/asm.js/testBug975182.js
+++ b/js/src/jit-test/tests/asm.js/testBug975182.js
@@ -8,11 +8,13 @@ Function("\
         return f\
     })(this, {\
         ff: arguments.callee\
     }, new ArrayBuffer(4096))\
 ")()
 function m(f) {
     for (var j = 0; j < 6000; ++j) {
         f();
+        if ((j % 1000) === 0)
+            gc();
     }
 }
 m(g);
--- a/js/src/jit/ExecutableAllocator.cpp
+++ b/js/src/jit/ExecutableAllocator.cpp
@@ -22,16 +22,18 @@
  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "jit/ExecutableAllocator.h"
 
+#include "mozilla/Atomics.h"
+
 #include "jit/JitCompartment.h"
 #include "js/MemoryMetrics.h"
 
 #ifdef __APPLE__
 #include <TargetConditionals.h>
 #endif
 
 using namespace js::jit;
@@ -231,18 +233,18 @@ ExecutableAllocator::createPool(size_t n
 
     ExecutablePool* pool = js_new<ExecutablePool>(this, a);
     if (!pool) {
         systemRelease(a);
         return nullptr;
     }
 
     if (!m_pools.put(pool)) {
+        // Note: this will call |systemRelease(a)|.
         js_delete(pool);
-        systemRelease(a);
         return nullptr;
     }
 
     return pool;
 }
 
 void*
 ExecutableAllocator::alloc(size_t n, ExecutablePool** poolp, CodeKind type)
@@ -402,8 +404,52 @@ ExecutableAllocator::poisonCode(JSRuntim
         ExecutablePool* pool = ranges[i].pool;
         if (pool->isMarked()) {
             reprotectPool(rt, pool, Executable);
             pool->unmark();
         }
         pool->release();
     }
 }
+
+// Limit on the number of bytes of executable memory to prevent JIT spraying
+// attacks.
+#if JS_BITS_PER_WORD == 32
+static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024;
+#else
+static const size_t MaxCodeBytesPerProcess = 512 * 1024 * 1024;
+#endif
+
+static mozilla::Atomic<size_t> allocatedExecutableBytes(0);
+
+bool
+js::jit::AddAllocatedExecutableBytes(size_t bytes)
+{
+    MOZ_ASSERT(allocatedExecutableBytes <= MaxCodeBytesPerProcess);
+
+    // Multiple threads can call this concurrently. We use compareExchange to
+    // ensure allocatedExecutableBytes is always <= MaxCodeBytesPerProcess.
+    while (true) {
+        size_t bytesOld = allocatedExecutableBytes;
+        size_t bytesNew = bytesOld + bytes;
+
+        if (bytesNew > MaxCodeBytesPerProcess)
+            return false;
+
+        if (allocatedExecutableBytes.compareExchange(bytesOld, bytesNew))
+            return true;
+    }
+
+    MOZ_CRASH();
+}
+
+void
+js::jit::SubAllocatedExecutableBytes(size_t bytes)
+{
+    MOZ_ASSERT(bytes <= allocatedExecutableBytes);
+    allocatedExecutableBytes -= bytes;
+}
+
+void
+js::jit::AssertAllocatedExecutableBytesIsZero()
+{
+    MOZ_ASSERT(allocatedExecutableBytes == 0);
+}
--- a/js/src/jit/ExecutableAllocator.h
+++ b/js/src/jit/ExecutableAllocator.h
@@ -156,19 +156,16 @@ struct JitPoisonRange
 };
 
 typedef Vector<JitPoisonRange, 0, SystemAllocPolicy> JitPoisonRangeVector;
 
 #define NON_WRITABLE_JIT_CODE 1
 
 class ExecutableAllocator
 {
-#ifdef XP_WIN
-    mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomNumberGenerator;
-#endif
     JSRuntime* rt_;
 
   public:
     enum ProtectionSetting { Writable, Executable };
 
     explicit ExecutableAllocator(JSRuntime* rt);
     ~ExecutableAllocator();
 
@@ -191,17 +188,16 @@ class ExecutableAllocator
 
     static const size_t OVERSIZE_ALLOCATION = size_t(-1);
 
     static size_t roundUpAllocationSize(size_t request, size_t granularity);
 
     // On OOM, this will return an Allocation where pages is nullptr.
     ExecutablePool::Allocation systemAlloc(size_t n);
     static void systemRelease(const ExecutablePool::Allocation& alloc);
-    void* computeRandomAllocationAddress();
 
     ExecutablePool* createPool(size_t n);
     ExecutablePool* poolForSize(size_t n);
 
     static void reprotectPool(JSRuntime* rt, ExecutablePool* pool, ProtectionSetting protection);
 
   public:
     MOZ_MUST_USE
@@ -330,18 +326,31 @@ class ExecutableAllocator
     typedef js::HashSet<ExecutablePool*, js::DefaultHasher<ExecutablePool*>, js::SystemAllocPolicy>
             ExecPoolHashSet;
     ExecPoolHashSet m_pools;    // All pools, just for stats purposes.
 
     static size_t determinePageSize();
 };
 
 extern void*
-AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag,
+AllocateExecutableMemory(size_t bytes, unsigned permissions, const char* tag,
                          size_t pageSize);
 
 extern void
 DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize);
 
+// These functions are called by the platform-specific definitions of
+// (Allocate|Deallocate)ExecutableMemory and should not otherwise be
+// called directly.
+
+extern MOZ_MUST_USE bool
+AddAllocatedExecutableBytes(size_t bytes);
+
+extern void
+SubAllocatedExecutableBytes(size_t bytes);
+
+extern void
+AssertAllocatedExecutableBytesIsZero();
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_ExecutableAllocator_h */
--- a/js/src/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/jit/ExecutableAllocatorPosix.cpp
@@ -21,16 +21,17 @@
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "mozilla/DebugOnly.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/TaggedAnonymousMemory.h"
 
 #include <errno.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
 #include "jit/ExecutableAllocator.h"
 #include "js/Utility.h"
@@ -39,36 +40,49 @@ using namespace js::jit;
 
 size_t
 ExecutableAllocator::determinePageSize()
 {
     return getpagesize();
 }
 
 void*
-js::jit::AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag,
+js::jit::AllocateExecutableMemory(size_t bytes, unsigned permissions, const char* tag,
                                   size_t pageSize)
 {
     MOZ_ASSERT(bytes % pageSize == 0);
-    void* p = MozTaggedAnonymousMmap(addr, bytes, permissions, MAP_PRIVATE | MAP_ANON, -1, 0, tag);
-    return p == MAP_FAILED ? nullptr : p;
+
+    if (!AddAllocatedExecutableBytes(bytes))
+        return nullptr;
+
+    auto autoSubtract = mozilla::MakeScopeExit([&] { SubAllocatedExecutableBytes(bytes); });
+
+    void* p = MozTaggedAnonymousMmap(nullptr, bytes, permissions, MAP_PRIVATE | MAP_ANON, -1, 0,
+                                     tag);
+    if (p == MAP_FAILED)
+        return nullptr;
+
+    autoSubtract.release();
+    return p;
 }
 
 void
 js::jit::DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize)
 {
     MOZ_ASSERT(bytes % pageSize == 0);
     mozilla::DebugOnly<int> result = munmap(addr, bytes);
     MOZ_ASSERT(!result || errno == ENOMEM);
+
+    SubAllocatedExecutableBytes(bytes);
 }
 
 ExecutablePool::Allocation
 ExecutableAllocator::systemAlloc(size_t n)
 {
-    void* allocation = AllocateExecutableMemory(nullptr, n, initialProtectionFlags(Executable),
+    void* allocation = AllocateExecutableMemory(n, initialProtectionFlags(Executable),
                                                 "js-jit-code", pageSize);
     ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
     return alloc;
 }
 
 void
 ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
 {
--- a/js/src/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/jit/ExecutableAllocatorWin.cpp
@@ -24,16 +24,17 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifdef MOZ_STACKWALKING
 #include "mozilla/StackWalk_windows.h"
 #endif
 
+#include "mozilla/ScopeExit.h"
 #include "mozilla/WindowsVersion.h"
 
 #include "jsfriendapi.h"
 #include "jsmath.h"
 #include "jswin.h"
 
 #include "jit/ExecutableAllocator.h"
 
@@ -42,18 +43,18 @@ using namespace js::jit;
 size_t
 ExecutableAllocator::determinePageSize()
 {
     SYSTEM_INFO system_info;
     GetSystemInfo(&system_info);
     return system_info.dwPageSize;
 }
 
-void*
-ExecutableAllocator::computeRandomAllocationAddress()
+static void*
+ComputeRandomAllocationAddress()
 {
     /*
      * Inspiration is V8's OS::Allocate in platform-win32.cc.
      *
      * VirtualAlloc takes 64K chunks out of the virtual address space, so we
      * keep 16b alignment.
      *
      * x86: V8 comments say that keeping addresses in the [64MiB, 1GiB) range
@@ -66,23 +67,17 @@ ExecutableAllocator::computeRandomAlloca
     static const uintptr_t mask = 0x000003ffffff0000;
 #elif defined(JS_CPU_X86)
     static const uintptr_t base = 0x04000000;
     static const uintptr_t mask = 0x3fff0000;
 #else
 # error "Unsupported architecture"
 #endif
 
-    if (randomNumberGenerator.isNothing()) {
-        mozilla::Array<uint64_t, 2> seed;
-        js::GenerateXorShift128PlusSeed(seed);
-        randomNumberGenerator.emplace(seed[0], seed[1]);
-    }
-
-    uint64_t rand = randomNumberGenerator.ref().next();
+    uint64_t rand = js::GenerateRandomSeed();
     return (void*) (base | (rand & mask));
 }
 
 #ifdef JS_CPU_X64
 static js::JitExceptionHandler sJitExceptionHandler;
 
 JS_FRIEND_API(void)
 js::SetJitExceptionHandler(JitExceptionHandler handler)
@@ -198,69 +193,86 @@ UnregisterExecutableMemory(void* p, size
     RtlDeleteFunctionTable(&r->runtimeFunction);
 
 #ifdef MOZ_STACKWALKING
     ReleaseStackWalkWorkaroundLock();
 #endif
 }
 #endif
 
+static const size_t VirtualAllocGranularity = 64 * 1024;
+
 void*
-js::jit::AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag,
+js::jit::AllocateExecutableMemory(size_t bytes, unsigned permissions, const char* tag,
                                   size_t pageSize)
 {
     MOZ_ASSERT(bytes % pageSize == 0);
 
+    // VirtualAlloc returns 64 KB chunks, so we round the value we pass to
+    // AddAllocatedExecutableBytes up to 64 KB to account for this. See
+    // bug 1325200.
+    size_t bytesRounded = JS_ROUNDUP(bytes, VirtualAllocGranularity);
+    if (!AddAllocatedExecutableBytes(bytesRounded))
+        return nullptr;
+
+    auto autoSubtract = mozilla::MakeScopeExit([&] { SubAllocatedExecutableBytes(bytesRounded); });
+
 #ifdef JS_CPU_X64
     if (sJitExceptionHandler)
         bytes += pageSize;
 #endif
 
-    void* p = VirtualAlloc(addr, bytes, MEM_COMMIT | MEM_RESERVE, permissions);
-    if (!p)
-        return nullptr;
+    void* randomAddr = ComputeRandomAllocationAddress();
+
+    void* p = VirtualAlloc(randomAddr, bytes, MEM_COMMIT | MEM_RESERVE, permissions);
+    if (!p) {
+        // Try again without randomAddr.
+        p = VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, permissions);
+        if (!p)
+            return nullptr;
+    }
 
 #ifdef JS_CPU_X64
     if (sJitExceptionHandler) {
         if (!RegisterExecutableMemory(p, bytes, pageSize)) {
             VirtualFree(p, 0, MEM_RELEASE);
             return nullptr;
         }
 
         p = (uint8_t*)p + pageSize;
     }
 #endif
 
+    autoSubtract.release();
     return p;
 }
 
 void
 js::jit::DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize)
 {
     MOZ_ASSERT(bytes % pageSize == 0);
 
 #ifdef JS_CPU_X64
     if (sJitExceptionHandler) {
         addr = (uint8_t*)addr - pageSize;
         UnregisterExecutableMemory(addr, bytes, pageSize);
     }
 #endif
 
     VirtualFree(addr, 0, MEM_RELEASE);
+
+    SubAllocatedExecutableBytes(JS_ROUNDUP(bytes, VirtualAllocGranularity));
 }
 
 ExecutablePool::Allocation
 ExecutableAllocator::systemAlloc(size_t n)
 {
-    void* randomAddress = computeRandomAllocationAddress();
     unsigned flags = initialProtectionFlags(Executable);
-    void* allocation = AllocateExecutableMemory(randomAddress, n, flags, "js-jit-code", pageSize);
-    if (!allocation) {
-        allocation = AllocateExecutableMemory(nullptr, n, flags, "js-jit-code", pageSize);
-    }
+    void* allocation = AllocateExecutableMemory(n, flags, "js-jit-code", pageSize);
+
     ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
     return alloc;
 }
 
 void
 ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
 {
     DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize);
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -671,46 +671,46 @@ js::math_pow_handle(JSContext* cx, Handl
 bool
 js::math_pow(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     return math_pow_handle(cx, args.get(0), args.get(1), args.rval());
 }
 
-static uint64_t
-GenerateSeed()
+uint64_t
+js::GenerateRandomSeed()
 {
     uint64_t seed = 0;
 
 #if defined(XP_WIN)
     MOZ_ALWAYS_TRUE(RtlGenRandom(&seed, sizeof(seed)));
 #elif defined(HAVE_ARC4RANDOM)
     seed = (static_cast<uint64_t>(arc4random()) << 32) | arc4random();
 #elif defined(XP_UNIX)
     int fd = open("/dev/urandom", O_RDONLY);
     if (fd >= 0) {
         mozilla::Unused << read(fd, static_cast<void*>(&seed), sizeof(seed));
         close(fd);
     }
 #else
-# error "Platform needs to implement GenerateSeed()"
+# error "Platform needs to implement GenerateRandomSeed()"
 #endif
 
     // Also mix in PRMJ_Now() in case we couldn't read random bits from the OS.
     return seed ^ PRMJ_Now();
 }
 
 void
 js::GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed)
 {
     // XorShift128PlusRNG must be initialized with a non-zero seed.
     do {
-        seed[0] = GenerateSeed();
-        seed[1] = GenerateSeed();
+        seed[0] = GenerateRandomSeed();
+        seed[1] = GenerateRandomSeed();
     } while (seed[0] == 0 && seed[1] == 0);
 }
 
 void
 JSCompartment::ensureRandomNumberGenerator()
 {
     if (randomNumberGenerator.isNothing()) {
         mozilla::Array<uint64_t, 2> seed;
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -81,16 +81,19 @@ class MathCache
 
 /*
  * JS math functions.
  */
 
 extern JSObject*
 InitMathClass(JSContext* cx, HandleObject obj);
 
+extern uint64_t
+GenerateRandomSeed();
+
 // Fill |seed[0]| and |seed[1]| with random bits, suitable for
 // seeding a XorShift128+ random number generator.
 extern void
 GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed);
 
 extern uint64_t
 random_next(uint64_t* rngState, int bits);
 
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -169,16 +169,19 @@ JS_ShutDown(void)
     // so), so we really don't want to do it in JS_Init, and we really do want
     // to do it only when PRMJ_Now is eventually called.
     PRMJ_NowShutdown();
 
 #if EXPOSE_INTL_API
     u_cleanup();
 #endif // EXPOSE_INTL_API
 
+    if (!JSRuntime::hasLiveRuntimes())
+        js::jit::AssertAllocatedExecutableBytesIsZero();
+
     libraryInitState = InitState::ShutDown;
 }
 
 JS_PUBLIC_API(bool)
 JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn)
 {
     MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
                "must call JS_SetICUMemoryFunctions before any other JSAPI "
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -1274,26 +1274,37 @@ RegExpShared::needsSweep(JSRuntime* rt)
         clearMarked();
         return false;
     }
 
     return true;
 }
 
 void
+RegExpShared::discardJitCode()
+{
+    for (size_t i = 0; i < ArrayLength(compilationArray); i++)
+        compilationArray[i].jitCode = nullptr;
+}
+
+void
 RegExpCompartment::sweep(JSRuntime* rt)
 {
     if (!set_.initialized())
         return;
 
     for (Set::Enum e(set_); !e.empty(); e.popFront()) {
         RegExpShared* shared = e.front();
         if (shared->needsSweep(rt)) {
             js_delete(shared);
             e.removeFront();
+        } else {
+            // Discard code to avoid holding onto ExecutablePools.
+            if (rt->gc.isHeapCompacting())
+                shared->discardJitCode();
         }
     }
 
     if (matchResultTemplateObject_ &&
         IsAboutToBeFinalized(&matchResultTemplateObject_))
     {
         matchResultTemplateObject_.set(nullptr);
     }
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -203,16 +203,17 @@ class RegExpShared
     }
     bool isCompiled() const {
         return isCompiled(Normal, true) || isCompiled(Normal, false)
             || isCompiled(MatchOnly, true) || isCompiled(MatchOnly, false);
     }
 
     void trace(JSTracer* trc);
     bool needsSweep(JSRuntime* rt);
+    void discardJitCode();
 
     bool marked() const { return marked_; }
     void clearMarked() { marked_ = false; }
 
     static size_t offsetOfSource() {
         return offsetof(RegExpShared, source);
     }
 
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -4276,16 +4276,20 @@ ObjectGroup::sweep(AutoClearTypeInferenc
         // Remove unboxed layouts that are about to be finalized from the
         // compartment wide list while we are still on the main thread.
         ObjectGroup* group = this;
         if (IsAboutToBeFinalizedUnbarriered(&group))
             unboxedLayout().detachFromCompartment();
 
         if (unboxedLayout().newScript())
             unboxedLayout().newScript()->sweep();
+
+        // Discard constructor code to avoid holding onto ExecutablePools.
+        if (zone()->isGCCompacting())
+            unboxedLayout().setConstructorCode(nullptr);
     }
 
     if (maybePreliminaryObjects())
         maybePreliminaryObjects()->sweep();
 
     if (newScript())
         newScript()->sweep();
 
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -62,18 +62,18 @@ AllocateCodeSegment(ExclusiveContext* cx
 {
     if (wasmCodeAllocations >= MaxWasmCodeAllocations)
         return nullptr;
 
     // Allocate RW memory. DynamicallyLinkModule will reprotect the code as RX.
     unsigned permissions =
         ExecutableAllocator::initialProtectionFlags(ExecutableAllocator::Writable);
 
-    void* p = AllocateExecutableMemory(nullptr, totalLength, permissions,
-                                       "wasm-code-segment", gc::SystemPageSize());
+    void* p = AllocateExecutableMemory(totalLength, permissions, "wasm-code-segment",
+                                       gc::SystemPageSize());
     if (!p) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     wasmCodeAllocations++;
     return (uint8_t*)p;
 }