From 36cb80d1cac66a1511bec4ad97947a2deeab2e08 Mon Sep 17 00:00:00 2001 From: trav90 Date: Sun, 2 Sep 2018 18:59:51 -0500 Subject: Call the relevant scope-data constructor when allocating it, and poison/mark as undefined the memory for the trailing array of BindingNames, ratther than impermissibly PodZero-ing non-trivial classes. --- js/src/ds/LifoAlloc.h | 16 ++++++++++ js/src/frontend/Parser.cpp | 8 ++--- js/src/vm/Scope.cpp | 4 +-- js/src/vm/Scope.h | 75 +++++++++++++++++++++++++++++++--------------- 4 files changed, 72 insertions(+), 31 deletions(-) diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index f349cd476..b4e9c3418 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -15,6 +15,8 @@ #include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" +#include + // This data structure supports stacky LIFO allocation (mark/release and // LifoAllocScope). It does not maintain one contiguous segment; instead, it // maintains a bunch of linked memory segments. In order to prevent malloc/free @@ -285,6 +287,20 @@ class LifoAlloc return allocImpl(n); } + template + MOZ_ALWAYS_INLINE T* + allocInSize(size_t n, Args&&... args) + { + MOZ_ASSERT(n >= sizeof(T), "must request enough space to store a T"); + static_assert(alignof(T) <= detail::LIFO_ALLOC_ALIGN, + "LifoAlloc must provide enough alignment to store T"); + void* ptr = alloc(n); + if (!ptr) + return nullptr; + + return new (ptr) T(mozilla::Forward(args)...); + } + MOZ_ALWAYS_INLINE void* allocInfallible(size_t n) { AutoEnterOOMUnsafeRegion oomUnsafe; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 343621194..7bfab87a3 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1453,13 +1453,11 @@ template static typename Scope::Data* NewEmptyBindingData(ExclusiveContext* cx, LifoAlloc& alloc, uint32_t numBindings) { + using Data = typename Scope::Data; size_t allocSize = Scope::sizeOfData(numBindings); - auto* bindings = static_cast(alloc.alloc(allocSize)); - if (!bindings) { + auto* bindings = alloc.allocInSize(allocSize, numBindings); + if (!bindings) ReportOutOfMemory(cx); - return nullptr; - } - PodZero(bindings); return bindings; } diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index 25e389d8a..8bb1702ea 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -191,12 +191,12 @@ template static UniquePtr NewEmptyScopeData(ExclusiveContext* cx, uint32_t length = 0) { - uint8_t* bytes = cx->zone()->pod_calloc(ConcreteScope::sizeOfData(length)); + uint8_t* bytes = cx->zone()->pod_malloc(ConcreteScope::sizeOfData(length)); if (!bytes) ReportOutOfMemory(cx); auto data = reinterpret_cast(bytes); if (data) - new (data) typename ConcreteScope::Data(); + new (data) typename ConcreteScope::Data(length); return UniquePtr(data); } diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h index 387eb30eb..1d04fd9f6 100644 --- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -12,6 +12,7 @@ #include "jsobj.h" #include "jsopcode.h" +#include "jsutil.h" #include "gc/Heap.h" #include "gc/Policy.h" @@ -139,6 +140,14 @@ class TrailingNamesArray } public: + // Explicitly ensure no one accidentally allocates scope data without + // poisoning its trailing names. + TrailingNamesArray() = delete; + + explicit TrailingNamesArray(size_t nameCount) { + if (nameCount) + JS_POISON(&data_, 0xCC, sizeof(BindingName) * nameCount); + } BindingName* start() { return reinterpret_cast(ptr()); } BindingName& operator[](size_t i) { return start()[i]; } @@ -370,17 +379,20 @@ class LexicalScope : public Scope // // lets - [0, constStart) // consts - [constStart, length) - uint32_t constStart; - uint32_t length; + uint32_t constStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -466,11 +478,11 @@ class FunctionScope : public Scope // The canonical function of the scope, as during a scope walk we // often query properties of the JSFunction (e.g., is the function an // arrow). - GCPtrFunction canonicalFunction; + GCPtrFunction canonicalFunction = {}; // If parameter expressions are present, parameters act like lexical // bindings. - bool hasParameterExprs; + bool hasParameterExprs = false; // Bindings are sorted by kind in both frames and environments. // @@ -485,18 +497,21 @@ class FunctionScope : public Scope // positional formals - [0, nonPositionalFormalStart) // other formals - [nonPositionalParamStart, varStart) // vars - [varStart, length) - uint16_t nonPositionalFormalStart; - uint16_t varStart; - uint32_t length; + uint16_t nonPositionalFormalStart = 0; + uint16_t varStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -581,16 +596,19 @@ class VarScope : public Scope struct Data { // All bindings are vars. - uint32_t length; + uint32_t length = 0; // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is // the innermost scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -671,15 +689,18 @@ class GlobalScope : public Scope // vars - [varStart, letStart) // lets - [letStart, constStart) // consts - [constStart, length) - uint32_t varStart; - uint32_t letStart; - uint32_t constStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t letStart = 0; + uint32_t constStart = 0; + uint32_t length = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -769,17 +790,20 @@ class EvalScope : public Scope // // top-level funcs - [0, varStart) // vars - [varStart, length) - uint32_t varStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -860,7 +884,7 @@ class ModuleScope : public Scope struct Data { // The module of the scope. - GCPtr module; + GCPtr module = {}; // Bindings are sorted by kind. // @@ -868,19 +892,22 @@ class ModuleScope : public Scope // vars - [varStart, letStart) // lets - [letStart, constStart) // consts - [constStart, length) - uint32_t varStart; - uint32_t letStart; - uint32_t constStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t letStart = 0; + uint32_t constStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; -- cgit v1.2.3