[js] Try to catch bad pointers for GC and bail if not valid.

master
Fedor 2020-09-09 17:28:36 +03:00
parent ad2f81519e
commit 6d0d3e1922
2 changed files with 42 additions and 0 deletions

View File

@ -51,6 +51,7 @@ const size_t ChunkMarkBitmapBits = 129024;
const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*);
const size_t ChunkTrailerSize = 2 * sizeof(uintptr_t) + sizeof(uint64_t);
const size_t ChunkLocationOffset = ChunkSize - ChunkTrailerSize;
const size_t ChunkStoreBufferOffset = ChunkSize - ChunkTrailerSize + sizeof(uint64_t);
const size_t ArenaZoneOffset = sizeof(size_t);
const size_t ArenaHeaderSize = sizeof(size_t) + 2 * sizeof(uintptr_t) +
sizeof(size_t) + sizeof(uintptr_t);
@ -326,6 +327,20 @@ CellIsMarkedGray(const Cell* cell)
extern JS_PUBLIC_API(bool)
CellIsMarkedGrayIfKnown(const Cell* cell);
MOZ_ALWAYS_INLINE ChunkLocation GetCellLocation(const void* cell) {
uintptr_t addr = uintptr_t(cell);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkLocationOffset;
return *reinterpret_cast<ChunkLocation*>(addr);
}
MOZ_ALWAYS_INLINE bool NurseryCellHasStoreBuffer(const void* cell) {
uintptr_t addr = uintptr_t(cell);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkStoreBufferOffset;
return *reinterpret_cast<void**>(addr) != nullptr;
}
} /* namespace detail */
MOZ_ALWAYS_INLINE bool
@ -341,6 +356,28 @@ IsInsideNursery(const js::gc::Cell* cell)
return location == ChunkLocation::Nursery;
}
MOZ_ALWAYS_INLINE bool IsCellPointerValid(const void* cell) {
auto addr = uintptr_t(cell);
if (addr < ChunkSize || addr % CellSize != 0) {
return false;
}
auto location = detail::GetCellLocation(cell);
if (location == ChunkLocation::TenuredHeap) {
return !!detail::GetGCThingZone(addr);
}
if (location == ChunkLocation::Nursery) {
return detail::NurseryCellHasStoreBuffer(cell);
}
return false;
}
MOZ_ALWAYS_INLINE bool IsCellPointerValidOrNull(const void* cell) {
if (!cell) {
return true;
}
return IsCellPointerValid(cell);
}
} /* namespace gc */
} /* namespace js */

View File

@ -2267,6 +2267,8 @@ void
js::gc::StoreBuffer::SlotsEdge::trace(TenuringTracer& mover) const
{
NativeObject* obj = object();
if(!IsCellPointerValid(obj))
return;
// Beware JSObject::swap exchanging a native object for a non-native one.
if (!obj->isNative())
@ -2336,6 +2338,8 @@ js::gc::StoreBuffer::traceWholeCells(TenuringTracer& mover)
{
for (ArenaCellSet* cells = bufferWholeCell; cells; cells = cells->next) {
Arena* arena = cells->arena;
if(!IsCellPointerValid(arena))
continue;
MOZ_ASSERT(arena->bufferedCells == cells);
arena->bufferedCells = &ArenaCellSet::Empty;
@ -2364,6 +2368,7 @@ js::gc::StoreBuffer::CellPtrEdge::trace(TenuringTracer& mover) const
{
if (!*edge)
return;
// XXX: We should check if the cell pointer is valid here too
MOZ_ASSERT((*edge)->getTraceKind() == JS::TraceKind::Object);
mover.traverse(reinterpret_cast<JSObject**>(edge));