Skip to content

Commit b3826b5

Browse files
author
Dmitrii Esin
committed
darwin: fix unsigned underflow in memory meter on ARM64
On macOS with Apple Silicon (16K pages), external_page_count (file-backed pages) can exceed active_count, causing the unsigned subtraction in Platform_setMemoryValues to wrap around to ~4 billion pages. This results in the memory meter displaying ~64 TB of used memory instead of the actual value. Use saturatingSub() to clamp the result to zero when the subtraction would underflow. Intermediate additions are promoted to unsigned long long to avoid narrowing before the saturating check. Affects both showCachedMemory=true and showCachedMemory=false paths.
1 parent ec95a5f commit b3826b5

1 file changed

Lines changed: 11 additions & 4 deletions

File tree

darwin/Platform.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,14 +432,21 @@ void Platform_setMemoryValues(Meter* mtr) {
432432

433433
mtr->total = dhost->host_info.max_mem / 1024;
434434
mtr->values[MEMORY_CLASS_WIRED] = page_K * vm->wire_count;
435+
436+
/*
437+
* Use saturatingSub() to prevent unsigned underflow: on macOS,
438+
* external_page_count (file-backed pages) can exceed active_count,
439+
* causing the result to wrap around to ~4 billion pages (~64 TB on
440+
* 16K-page ARM64 systems).
441+
*/
435442
if (settings->showCachedMemory) {
436443
mtr->values[MEMORY_CLASS_SPECULATIVE] = page_K * vm->speculative_count;
437-
mtr->values[MEMORY_CLASS_ACTIVE] = page_K * (vm->active_count - vm->purgeable_count - external_page_count); // external pages are pages swapped out
438-
mtr->values[MEMORY_CLASS_PURGEABLE] = page_K * vm->purgeable_count; // purgeable pages are flagged in the active pages
444+
mtr->values[MEMORY_CLASS_ACTIVE] = page_K * saturatingSub(vm->active_count, (unsigned long long)vm->purgeable_count + external_page_count);
445+
mtr->values[MEMORY_CLASS_PURGEABLE] = page_K * vm->purgeable_count;
439446
}
440-
else { // if showCachedMemory is disabled, merge speculative and purgeable into the active pages
447+
else {
441448
mtr->values[MEMORY_CLASS_SPECULATIVE] = 0;
442-
mtr->values[MEMORY_CLASS_ACTIVE] = page_K * (vm->speculative_count + vm->active_count - external_page_count); // external pages are pages swapped out
449+
mtr->values[MEMORY_CLASS_ACTIVE] = page_K * saturatingSub((unsigned long long)vm->speculative_count + vm->active_count, external_page_count);
443450
mtr->values[MEMORY_CLASS_PURGEABLE] = 0;
444451
}
445452
mtr->values[MEMORY_CLASS_COMPRESSED] = page_K * compressor_page_count;

0 commit comments

Comments
 (0)