Skip to content

avoid signed overflow in cache memory limit#4561

Merged
lovell merged 1 commit into
lovell:mainfrom
metsw24-max:cache-memory-overflow
Jun 26, 2026
Merged

avoid signed overflow in cache memory limit#4561
lovell merged 1 commit into
lovell:mainfrom
metsw24-max:cache-memory-overflow

Conversation

@metsw24-max

Copy link
Copy Markdown
Contributor

sharp.cache({ memory }) passes the megabyte value through to the native cache helper, which reads it as a 32-bit int and multiplies by 1048576 to convert to bytes before handing the result to vips_cache_set_max_mem. The multiply runs in 32-bit signed arithmetic and only widens to the size_t the function expects afterwards, so any value of 2048 or above overflows first. A 2048MB request wraps to a negative number that sign-extends to roughly 16 exabytes, which leaves the operation cache effectively unbounded, while exactly 4096MB wraps to zero and silently disables it. I came across this while confirming that larger cache limits were honoured and saw the reported memory.max had no relation to the value passed in. Casting the operand to size_t before the multiply keeps the conversion in 64-bit so the byte count stays correct across the documented range. I have limited the change to that one expression and added a regression test at 4096MB, which reported a maximum of zero beforehand.

@lovell

lovell commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Thanks for the PR. Whilst we're fixing this, I think we might also want to use Uint32Value instead of Int32Value for the cache values as they should all be positive integers. I guess we could also verify these values in the JavaScript layer.

@metsw24-max metsw24-max force-pushed the cache-memory-overflow branch from 76a3289 to 69a016f Compare June 26, 2026 09:12
@metsw24-max

Copy link
Copy Markdown
Contributor Author

Makes sense. Switched all three cache values to Uint32Value. I kept the size_t widening on memory because Uint32Value on its own still does the MB-to-bytes multiply in 32-bit and wraps from 4096MB up.

Also added a guard in lib/utility.mjs that rejects any cache value that isn't a non-negative integer, with a test for it. All squashed into the one commit.

@lovell

lovell commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Thanks for the updates, it looks like we might have to skip the max memory test on 32-bit systems. The buildPlatformArch() function should provide a suitable value for this.

Read the cache values as unsigned integers and keep the megabyte to byte conversion in size_t, so the memory limit no longer wraps at 2048MB and above. Reject non-integer and negative values in the JavaScript layer.
@metsw24-max metsw24-max force-pushed the cache-memory-overflow branch from 69a016f to 6b3e1c7 Compare June 26, 2026 15:21
@metsw24-max

Copy link
Copy Markdown
Contributor Author

Good shout. The 4096MB byte count overflows a 32-bit size_t too, so I now skip that test when buildPlatformArch() reports a 32-bit arch (arm, ia32, wasm32). Runs as before on 64-bit and skips cleanly when I force npm_config_arch=ia32.

@lovell lovell merged commit bd0c2c7 into lovell:main Jun 26, 2026
31 of 32 checks passed
@lovell

lovell commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Thank you. (The wasm32 test failure is unrelated, I'm fixing this now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants