Bug 1318039 - Better fix for asm.js cache build-id mismatches (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Fri, 18 Nov 2016 11:50:01 -0600
changeset 323453 386d729a49929621e346e4ce7f5179947e22c1dd
parent 323452 42a9728ad5f8b61596cbca5c3b7d83c8e84dc74c
child 323454 6fb97e41a59039d77978090d8b282c54b86efdd9
push id30978
push usercbook@mozilla.com
push dateMon, 21 Nov 2016 14:44:46 +0000
treeherdermozilla-central@0534254e9a40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1318039
milestone53.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 1318039 - Better fix for asm.js cache build-id mismatches (r=bbouvier) MozReview-Commit-ID: HpDsEoMPM2T
js/src/wasm/AsmJS.cpp
js/src/wasm/WasmModule.cpp
js/src/wasm/WasmModule.h
js/src/wasm/WasmSerialize.h
js/src/wasm/WasmTypes.cpp
js/src/wasm/WasmTypes.h
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -8518,30 +8518,33 @@ LookupAsmJSModuleInCache(ExclusiveContex
 
     const char16_t* begin = parser.tokenStream.rawCharPtrAt(ModuleChars::beginOffset(parser));
     const char16_t* limit = parser.tokenStream.rawLimit();
 
     ScopedCacheEntryOpenedForRead entry(cx);
     if (!open(cx->global(), begin, limit, &entry.serializedSize, &entry.memory, &entry.handle))
         return true;
 
+    size_t remain = entry.serializedSize;
     const uint8_t* cursor = entry.memory;
 
     uint32_t bytecodeSize, compiledSize;
-    cursor = ReadScalar<uint32_t>(cursor, &bytecodeSize);
-    cursor = ReadScalar<uint32_t>(cursor, &compiledSize);
+    (cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &bytecodeSize)) &&
+    (cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &compiledSize));
+    if (!cursor)
+        return true;
 
     const uint8_t* compiledBegin = cursor;
     const uint8_t* bytecodeBegin = compiledBegin + compiledSize;
 
     Assumptions assumptions;
     if (!assumptions.initBuildIdFromContext(cx))
         return false;
 
-    if (!Module::assumptionsMatch(assumptions, compiledBegin))
+    if (!Module::assumptionsMatch(assumptions, compiledBegin, remain))
         return true;
 
     MutableAsmJSMetadata asmJSMetadata = cx->new_<AsmJSMetadata>();
     if (!asmJSMetadata)
         return false;
 
     *module = Module::deserialize(bytecodeBegin, bytecodeSize, compiledBegin, compiledSize,
                                   asmJSMetadata.get());
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -174,21 +174,20 @@ Module::serialize(uint8_t* bytecodeBegin
     cursor = SerializeVector(cursor, exports_);
     cursor = SerializePodVector(cursor, dataSegments_);
     cursor = SerializeVector(cursor, elemSegments_);
     cursor = metadata_->serialize(cursor);
     MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize);
 }
 
 /* static */ bool
-Module::assumptionsMatch(const Assumptions& current, const uint8_t* cursor)
+Module::assumptionsMatch(const Assumptions& current, const uint8_t* compiledBegin, size_t remain)
 {
     Assumptions cached;
-    cursor = cached.deserialize(cursor);
-    if (!cursor)
+    if (!cached.deserialize(compiledBegin, remain))
         return false;
 
     return current == cached;
 }
 
 /* static */ SharedModule
 Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
                     const uint8_t* compiledBegin, size_t compiledSize,
@@ -199,20 +198,18 @@ Module::deserialize(const uint8_t* bytec
         return nullptr;
 
     const uint8_t* bytecodeEnd = DeserializePodVector(bytecodeBegin, &bytecode->bytes);
     if (!bytecodeEnd)
         return nullptr;
 
     MOZ_RELEASE_ASSERT(bytecodeEnd == bytecodeBegin + bytecodeSize);
 
-    const uint8_t* cursor = compiledBegin;
-
     Assumptions assumptions;
-    cursor = assumptions.deserialize(cursor);
+    const uint8_t* cursor = assumptions.deserialize(compiledBegin, compiledSize);
     if (!cursor)
         return nullptr;
 
     Bytes code;
     cursor = DeserializePodVector(cursor, &code);
     if (!cursor)
         return nullptr;
 
@@ -309,17 +306,17 @@ bool
 wasm::CompiledModuleAssumptionsMatch(PRFileDesc* compiled, JS::BuildIdCharVector&& buildId)
 {
     PRFileInfo info;
     UniqueMapping mapping = MapFile(compiled, &info);
     if (!mapping)
         return false;
 
     Assumptions assumptions(Move(buildId));
-    return Module::assumptionsMatch(assumptions, mapping.get());
+    return Module::assumptionsMatch(assumptions, mapping.get(), info.size);
 }
 
 SharedModule
 wasm::DeserializeModule(PRFileDesc* bytecodeFile, PRFileDesc* maybeCompiledFile,
                         JS::BuildIdCharVector&& buildId, UniqueChars filename,
                         unsigned line, unsigned column)
 {
     PRFileInfo bytecodeInfo;
--- a/js/src/wasm/WasmModule.h
+++ b/js/src/wasm/WasmModule.h
@@ -148,17 +148,18 @@ class Module : public JS::WasmModule
                      HandleObject instanceProto,
                      MutableHandleWasmInstanceObject instanceObj) const;
 
     // Structured clone support:
 
     void serializedSize(size_t* bytecodeSize, size_t* compiledSize) const override;
     void serialize(uint8_t* bytecodeBegin, size_t bytecodeSize,
                    uint8_t* compiledBegin, size_t compiledSize) const override;
-    static bool assumptionsMatch(const Assumptions& current, const uint8_t* compiledBegin);
+    static bool assumptionsMatch(const Assumptions& current, const uint8_t* compiledBegin,
+                                 size_t remain);
     static RefPtr<Module> deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
                                       const uint8_t* compiledBegin, size_t compiledSize,
                                       Metadata* maybeMetadata = nullptr);
     JSObject* createObject(JSContext* cx) override;
 
     // about:memory reporting:
 
     void addSizeOfMisc(MallocSizeOf mallocSizeOf,
--- a/js/src/wasm/WasmSerialize.h
+++ b/js/src/wasm/WasmSerialize.h
@@ -36,32 +36,53 @@ WriteBytes(uint8_t* dst, const void* src
 
 static inline const uint8_t*
 ReadBytes(const uint8_t* src, void* dst, size_t nbytes)
 {
     memcpy(dst, src, nbytes);
     return src + nbytes;
 }
 
+static inline const uint8_t*
+ReadBytesChecked(const uint8_t* src, size_t* remain, void* dst, size_t nbytes)
+{
+    if (*remain < nbytes)
+        return nullptr;
+    memcpy(dst, src, nbytes);
+    *remain -= nbytes;
+    return src + nbytes;
+}
+
 template <class T>
 static inline uint8_t*
 WriteScalar(uint8_t* dst, T t)
 {
     memcpy(dst, &t, sizeof(t));
     return dst + sizeof(t);
 }
 
 template <class T>
 static inline const uint8_t*
 ReadScalar(const uint8_t* src, T* dst)
 {
     memcpy(dst, src, sizeof(*dst));
     return src + sizeof(*dst);
 }
 
+template <class T>
+static inline const uint8_t*
+ReadScalarChecked(const uint8_t* src, size_t* remain, T* dst)
+{
+    if (*remain < sizeof(*dst))
+        return nullptr;
+    memcpy(dst, src, sizeof(*dst));
+    *remain -= sizeof(*dst);
+    return src + sizeof(*dst);
+}
+
 template <class T, size_t N>
 static inline size_t
 SerializedVectorSize(const mozilla::Vector<T, N, SystemAllocPolicy>& vec)
 {
     size_t size = sizeof(uint32_t);
     for (size_t i = 0; i < vec.length(); i++)
         size += vec[i].serializedSize();
     return size;
@@ -130,12 +151,24 @@ DeserializePodVector(const uint8_t* curs
     uint32_t length;
     cursor = ReadScalar<uint32_t>(cursor, &length);
     if (!vec->initLengthUninitialized(length))
         return nullptr;
     cursor = ReadBytes(cursor, vec->begin(), length * sizeof(T));
     return cursor;
 }
 
+template <class T, size_t N>
+static inline const uint8_t*
+DeserializePodVectorChecked(const uint8_t* cursor, size_t* remain, mozilla::Vector<T, N, SystemAllocPolicy>* vec)
+{
+    uint32_t length;
+    cursor = ReadScalarChecked<uint32_t>(cursor, remain, &length);
+    if (!cursor || !vec->initLengthUninitialized(length))
+        return nullptr;
+    cursor = ReadBytesChecked(cursor, remain, vec->begin(), length * sizeof(T));
+    return cursor;
+}
+
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_serialize_h
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -743,20 +743,20 @@ Assumptions::serialize(uint8_t* cursor) 
     // assumptions of a different build-id.
 
     cursor = WriteScalar<uint32_t>(cursor, cpuId);
     cursor = SerializePodVector(cursor, buildId);
     return cursor;
 }
 
 const uint8_t*
-Assumptions::deserialize(const uint8_t* cursor)
+Assumptions::deserialize(const uint8_t* cursor, size_t remain)
 {
-    (cursor = ReadScalar<uint32_t>(cursor, &cpuId)) &&
-    (cursor = DeserializePodVector(cursor, &buildId));
+    (cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &cpuId)) &&
+    (cursor = DeserializePodVectorChecked(cursor, &remain, &buildId));
     return cursor;
 }
 
 size_t
 Assumptions::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return buildId.sizeOfExcludingThis(mallocSizeOf);
 }
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1091,17 +1091,20 @@ struct Assumptions
     Assumptions();
     bool initBuildIdFromContext(ExclusiveContext* cx);
 
     bool clone(const Assumptions& other);
 
     bool operator==(const Assumptions& rhs) const;
     bool operator!=(const Assumptions& rhs) const { return !(*this == rhs); }
 
-    WASM_DECLARE_SERIALIZABLE(Assumptions)
+    size_t serializedSize() const;
+    uint8_t* serialize(uint8_t* cursor) const;
+    const uint8_t* deserialize(const uint8_t* cursor, size_t remain);
+    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 };
 
 // A Module can either be asm.js or wasm.
 
 enum ModuleKind
 {
     Wasm,
     AsmJS