tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 56701017d151b57915e49439bea7332c9fc73bbc
parent 215a117cd8427b16cb03089822c411bf7b0726e0
Author: Jon Coppeard <jcoppeard@mozilla.com>
Date:   Mon, 29 Dec 2025 14:45:14 +0000

Bug 2006614 - Make the ranges passed to NurseryChunk::markPagesInUseHard more precise r=sfink

Currently the memory ranges passed to this method often span memory that is
already in use as well as containing memory marked as not in use. This is
benign except that MarkPagesInUseHard calls MOZ_MAKE_MEM_UNDEFINED on the
range, causing valgrind to report these errors.

The patch makes us pass the start offset as well as the end offset as opposed
to assuming a start offset of the second page of the chunk (the smallest
possible start offset).

Differential Revision: https://phabricator.services.mozilla.com/D276848

Diffstat:
Mjs/src/gc/Nursery.cpp | 31++++++++++++++-----------------
1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp @@ -78,9 +78,9 @@ struct NurseryChunk : public ChunkBase { // not marked as unused. void markPagesUnusedHard(size_t startOffset); - // Mark pages from the second page of the chunk to endOffset as in use, - // following a call to markPagesUnusedHard. - [[nodiscard]] bool markPagesInUseHard(size_t endOffset); + // Mark pages from startOffset to endOffset as in use, undoing the effect of a + // previous call to markPagesUnusedHard. + [[nodiscard]] bool markPagesInUseHard(size_t startOffset, size_t endOffset); uintptr_t start() const { return uintptr_t(&data); } uintptr_t end() const { return uintptr_t(this) + ChunkSize; } @@ -178,12 +178,14 @@ inline void js::NurseryChunk::markPagesUnusedHard(size_t startOffset) { MarkPagesUnusedHard(reinterpret_cast<void*>(start), length); } -inline bool js::NurseryChunk::markPagesInUseHard(size_t endOffset) { - MOZ_ASSERT(endOffset >= NurseryChunkHeaderSize); - MOZ_ASSERT(endOffset >= SystemPageSize()); +inline bool js::NurseryChunk::markPagesInUseHard(size_t startOffset, + size_t endOffset) { + MOZ_ASSERT(startOffset >= NurseryChunkHeaderSize); + MOZ_ASSERT(startOffset >= SystemPageSize()); + MOZ_ASSERT(startOffset < endOffset); MOZ_ASSERT(endOffset <= ChunkSize); - uintptr_t start = uintptr_t(this) + SystemPageSize(); - size_t length = endOffset - SystemPageSize(); + uintptr_t start = uintptr_t(this) + startOffset; + size_t length = endOffset - startOffset; return MarkPagesInUseHard(reinterpret_cast<void*>(start), length); } @@ -651,14 +653,9 @@ void js::Nursery::enterZealMode() { AutoEnterOOMUnsafeRegion oomUnsafe; if (isSubChunkMode()) { - { - if (!chunk(0).markPagesInUseHard(ChunkSize)) { - oomUnsafe.crash("Out of memory trying to extend chunk for zeal mode"); - } + if (!chunk(0).markPagesInUseHard(capacity_, ChunkSize)) { + oomUnsafe.crash("Out of memory trying to extend chunk for zeal mode"); } - - // It'd be simpler to poison the whole chunk, but we can't do that - // because the nursery might be partially used. chunk(0).poisonRange(capacity_, ChunkSize, JS_FRESH_NURSERY_PATTERN, MemCheckKind::MakeUndefined); } @@ -2408,7 +2405,7 @@ bool js::Nursery::Space::commitSubChunkRegion(size_t oldCapacity, size_t newChunkEnd = std::min(newCapacity, ChunkSize); // The remainder of the chunk may have been decommitted. - if (!chunks_[0]->markPagesInUseHard(newChunkEnd)) { + if (!chunks_[0]->markPagesInUseHard(oldCapacity, newChunkEnd)) { // The OS won't give us the memory we need, we can't grow. return false; } @@ -2434,7 +2431,7 @@ void js::Nursery::freeChunksFrom(Space& space, const unsigned firstFreeChunk) { // Part of the first chunk may be hard-decommitted, un-decommit it so that // the GC's normal chunk-handling doesn't segfault. MOZ_ASSERT(space.currentChunk_ == 0); - if (!space.chunks_[0]->markPagesInUseHard(ChunkSize)) { + if (!space.chunks_[0]->markPagesInUseHard(capacity_, ChunkSize)) { // Free the chunk if we can't allocate its pages. UnmapPages(space.chunks_[0], ChunkSize); firstChunkToDecommit = 1;