Skip to content

[low] max_size=0 still caches one entry instead of disabling the cache #47

@toloco

Description

@toloco

Severity: ⚪ low • Category: correctness
Location: src/store.rs : 302-342, 411-430

What's wrong

With max_size=0, new() computes per_shard = 0.div_ceil(1) = 0, so capacity=0. In the insert path the eviction loop while shard.map.len() >= shard.capacity is 0 >= 0 (true), calls evict_one on an empty order (no-op), then if shard.order.is_empty() break, and proceeds to insert anyway. The result is the cache always retains one entry. A max_size of 0 is most naturally read as "do not cache", so this is a surprising edge case (current_size=1 observed).

Trigger

Decorate with @cache(max_size=0); call with distinct args; cache_info().current_size == 1.

Suggested fix

Special-case capacity == 0 (or max_size == 0) to skip insertion entirely, or validate max_size >= 1 in new()/the Python cache() factory and raise a clear error.

Adversarial verification note

Confirmed in the real code. In src/store.rs new() (lines 302-307): with max_size=0, n_shards = (0/8).clamp(1,16).next_power_of_two().min(16) = 1, and per_shard = 0.div_ceil(1) = 0, so each shard has capacity=0. In call insert path (lines 411-430): on a miss with an empty shard, needs_insert=true, the eviction loop while shard.map.len() >= shard.capacity evaluates 0 >= 0 true, calls evict_one which returns immediately on an empty order (verified at lines 185-189), then if shard.order.is_empty() break exits the loop, and the code unconditionally inserts at lines 428-429. The map then holds 1 entry. Subsequent distinct-key misses evict the prior entry (oscillating at most 1), so current_size caps at 1 rather than 0. The Python factory (warp_cache/_decorator.py:135-186) performs no max_size validation, so max_size=0 reaches new() directly. The finding's mechanism, math, and trigger are all accurate. Severity 'low' is correct: max_size=0 is an unusual input, there is no crash, memory unsafety, or systematically wrong results — just a surprising 1-entry retention instead of disabling the cache (TTL still applies to that one entry).


Filed from a multi-agent code review (finder → adversarial verification → synthesis). Confirmed real after a skeptic re-read the code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfrom-reviewFiled from the multi-agent code reviewrustPull requests that update rust codeseverity:lowMinor issue or nit

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions