Skip to content

darwin: fix memory meter showing ~64 TB on ARM64 due to unsigned underflow#1952

Merged
BenBE merged 1 commit intohtop-dev:mainfrom
EsDmitrii:fix/darwin-memory-unsigned-underflow
Apr 11, 2026
Merged

darwin: fix memory meter showing ~64 TB on ARM64 due to unsigned underflow#1952
BenBE merged 1 commit intohtop-dev:mainfrom
EsDmitrii:fix/darwin-memory-unsigned-underflow

Conversation

@EsDmitrii
Copy link
Copy Markdown

Problem

On macOS with Apple Silicon, the memory meter can display wildly incorrect
values — typically ~64 TB used out of 48 GB total. This makes the memory
bar completely unusable.

The root cause is an unsigned integer underflow in Platform_setMemoryValues()
(darwin/Platform.c). The active page count is computed as:

active_count - purgeable_count - external_page_count

All three variables are natural_t (unsigned 32-bit). On systems where
file-backed pages (external_page_count) exceed active_count - purgeable_count,
the subtraction wraps around to ~4,294,867,000 pages. Multiplied by
page_K (16 for ARM64's 16 KB pages), this produces ~64 TB.

Example from a live system (M4 Max, 48 GB RAM):

active_count         = 1,111,998
purgeable_count      =    66,505
external_page_count  = 1,144,396
result (signed)      =   -98,903
result (unsigned)    = 4,294,868,393
× 16 KB              ≈ 64.0 TB         ← displayed by htop

This is a normal state on macOS — the file cache often exceeds
active pages, especially after boot or heavy file I/O.

Fix

Cast each page count to double before subtraction so the arithmetic
is signed, and clamp the result to zero using the existing MAXIMUM()
macro. This avoids the wraparound while preserving the original
calculation semantics.

Both the showCachedMemory=true and showCachedMemory=false code paths
are fixed.

Before / After

Screenshot 2026-04-10 at 16 17 36 Screenshot 2026-04-10 at 16 18 31 Screenshot 2026-04-10 at 16 19 01

Test

Built and ran on macOS Sequoia 15.x, Apple M4 Max (48 GB).
Memory meter now shows correct values consistent with top and vm_stat.

@anitoanto
Copy link
Copy Markdown

Possible fix for #1953

@Explorer09
Copy link
Copy Markdown
Contributor

Explorer09 commented Apr 10, 2026

htop has a macro called saturatingSub() (in Macros.h). Maybe it's better to use that instead of cast to double.

@Explorer09
Copy link
Copy Markdown
Contributor

By the way, how did you capture the numbers as reported here?

active_count         = 1,111,998
purgeable_count      =    66,505
external_page_count  = 1,144,396

I hope these numbers are not made up.

@EsDmitrii
Copy link
Copy Markdown
Author

htop has a macro called saturatingSub() (in Macros.h). Maybe it's better to use that instead of cast to double.

Let me double check

@EsDmitrii
Copy link
Copy Markdown
Author

@Explorer09 Good call, updated. Using saturatingSub() with promotion to unsigned long long before the intermediate addition to stay safe across the full range.

About numbers these are live values captured from vm_stat on the affected system (M4 Max, 48 GB, macOS Sequoia). The command:

vm_stat | awk '/Pages active/{print "active_count =", $NF+0} /Pages purgeable/{print "purgeable_count =", $NF+0} /File-backed pages/{print "external_page_count =", $NF+0}'

The key condition is external_page_count > active_count - purgeable_count, which is a normal state on macOS when the file cache is large (e.g. right after boot or heavy file I/O).
Anyone with an ARM64 Mac can reproduce by checking vm_stat — if file-backed pages exceed active pages, htop will show ~64 TB in the memory meter.

@Explorer09
Copy link
Copy Markdown
Contributor

@EsDmitrii

Anyone with an ARM64 Mac can reproduce by checking vm_stat

I have an M2 MacBook, but unfortunately my use cases with a Mac didn't involve in a large number of file-backed pages. In other words I cannot reproduce the issue during my normal use.

@BenBE
Copy link
Copy Markdown
Member

BenBE commented Apr 10, 2026

Please squash/fixup the commits into one as per our style guide …

@BenBE BenBE added bug 🐛 Something isn't working MacOS 🍏 MacOS / Darwin related issues labels Apr 10, 2026
@BenBE BenBE added this to the 3.5.1 milestone Apr 10, 2026
@EsDmitrii EsDmitrii force-pushed the fix/darwin-memory-unsigned-underflow branch from ecb76f5 to 4a28727 Compare April 11, 2026 06:35
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.
@EsDmitrii EsDmitrii force-pushed the fix/darwin-memory-unsigned-underflow branch from 4a28727 to b3826b5 Compare April 11, 2026 06:39
@BenBE BenBE merged commit c5343ae into htop-dev:main Apr 11, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🐛 Something isn't working MacOS 🍏 MacOS / Darwin related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants