Repository navigation
fix(cache): clamp capacityInGB so the water marks cannot overflow - #1730
Merged
lihuiba merged 2 commits intoNov 6, 2026
Merged
Conversation
FileCachePool's constructor derives three values from capacityInGB with no
bound check:
int64_t capacityInBytes = capacityInGB_ * kGB;
waterMark_ = calcWaterMark(capacityInBytes, kMaxFreeSpace);
riskMark_ = std::max(capacityInBytes - kEvictionMark,
(waterMark_ + capacityInBytes) >> 1);
A large capacityInGB -- a unit typo, or a caller passing bytes where GB is
expected -- wraps all three, and nothing reports it:
capacityInGB capacityInBytes waterMark_ riskMark_
2^33 INT64_MIN huge 9223372031486066688
2^34 0 0 0
UINT64_MAX huge -54760833024 ...
2^34 is the worst case: every mark collapses to zero, so
totalUsed_ >= waterMark_ is always true and every eviction round tries to
empty the whole cache, while riskMark_ == 0 keeps the write path permanently
in the risk zone. A negative riskMark_ instead makes writes fail with ENOSPC
right away.
Clamp capacityInGB_ in the constructor and warn. 1 PiB is a round number far
below the tightest of the three limits -- calcWaterMark multiplies capacity
by kWaterMarkRatio in uint64_t before scaling, which wraps above
190,887,435 GB. Above 1 PiB capacity-based eviction is meaningless anyway,
and diskAvailInBytes still governs.
capacityInGB == 0 means "zero capacity, never cache", so the clamp only
fires above the bound and leaves 0 alone.
The new test asserts 0 < waterMark_ < riskMark_ < capacity for 2^33, 2^34
and UINT64_MAX, plus that the writes the wrecked marks used to reject with
ENOSPC now succeed. Verified red-green: with the clamp disabled it fails at
all three capacities with exactly the values tabulated above.
lihuiba
reviewed
Nov 6, 2026
lihuiba
approved these changes
Nov 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
FileCachePool's constructor derives three values fromcapacityInGBwith no bound check:A large
capacityInGB— a unit typo, or a caller passing bytes where GB is expected — wraps all three, and nothing reports it:capacityInGBcapacityInByteswaterMark_riskMark_2^33INT64_MIN92233720314860666882^34000UINT64_MAX-547608330242^34is the worst case, precisely because it is silent: every mark collapses to zero, sototalUsed_ >= waterMark_is always true and every eviction round tries to empty the whole cache, whileriskMark_ == 0keeps the write path permanently in the risk zone. A negativeriskMark_instead makes writes fail withENOSPCright away.Fix
Clamp
capacityInGB_in the constructor and warn.1 PiB is a round number far below the tightest of the three limits —
calcWaterMarkmultipliescapacitybykWaterMarkRatioinuint64_tbefore the* 0.01scaling, so that multiply wraps above 190,887,435 GB. (For comparison: thewaterMark_ + capacityInBytessum overflowsint64_tat 4,521,018,207 GB, andcapacityInGB * kGBgoes negative at2^33 - 1GB.) The warning only reports the clamp and its overflow-prevention purpose. Capacity-based eviction remains enabled at the clamped limit, anddiskAvailInBytescontinues to provide an independent disk-space floor.capacityInGB == 0means "zero capacity, never cache", so the clamp only fires above the bound and leaves0alone (RoCachedFs.BasicCacheFulldepends on that).Test
CachePool.huge_capacity_does_not_overflow_water_marksasserts0 < waterMark_ < riskMark_ < capacityfor2^33,2^34andUINT64_MAX, plus that the writes the wrecked marks used to reject withENOSPCnow succeed, and thatcapacityInGB == 0still yields all-zero marks.Verified red-green. With the clamp disabled the test fails at all three capacities with exactly the values in the table above:
Full
cache_testsuite on this branch:23 tests from 4 test cases ran. [ PASSED ] 23 tests., 0 failures.