Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/bf34b97757b3 # HG changeset patch # User Jon Coppeard # Date 1453890675 0 # Node ID bf34b97757b334af1f9f53b9b59e0b6902e7ed6f # Parent 228ca3f46cabaf3f388f6c6640690772aa13c1a5 Bug 1241731 - Handle incomplete buffer in DiscardTransferables r=sfink a=abillings a=sylvestre diff --git a/js/src/jit-test/tests/gc/bug-1241731.js b/js/src/jit-test/tests/gc/bug-1241731.js new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1241731.js @@ -0,0 +1,4 @@ +if (!('oomTest' in this)) + quit(); + +oomTest(() => serialize(0, [{}])); diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -379,39 +379,50 @@ ReadStructuredClone(JSContext* cx, uint6 // If the given buffer contains Transferables, free them. Note that custom // Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to // delete their transferables. static void Discard(uint64_t* buffer, size_t nbytes, const JSStructuredCloneCallbacks* cb, void* cbClosure) { MOZ_ASSERT(nbytes % sizeof(uint64_t) == 0); - if (nbytes < sizeof(uint64_t)) + uint64_t* end = buffer + nbytes / sizeof(uint64_t); + uint64_t* point = buffer; + if (point == end) return; // Empty buffer - uint64_t* point = buffer; uint32_t tag, data; SCInput::getPair(point++, &tag, &data); if (tag != SCTAG_TRANSFER_MAP_HEADER) return; if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED) return; // freeTransfer should not GC JS::AutoSuppressGCAnalysis nogc; + if (point == end) + return; + uint64_t numTransferables = LittleEndian::readUint64(point++); while (numTransferables--) { + if (point == end) + return; + uint32_t ownership; SCInput::getPair(point++, &tag, &ownership); MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY); + if (point == end) + return; void* content; SCInput::getPtr(point++, &content); + if (point == end) + return; uint64_t extraData = LittleEndian::readUint64(point++); if (ownership < JS::SCTAG_TMO_FIRST_OWNED) continue; if (ownership == JS::SCTAG_TMO_ALLOC_DATA) { js_free(content);