Skip to content

cli: don't wrap levels above INT_MAX into negative levels - #4873

Open
kevin9327 wants to merge 1 commit into
meta:devfrom
kevin9327:fix-cli-level-int-wrap
Open

kevin9327 wants to merge 1 commit into
meta:devfrom
kevin9327:fix-cli-level-int-wrap

Conversation

@kevin9327

Copy link
Copy Markdown

The CLI reads compression levels as 32-bit unsigned values and casts them to int, so a level between 2^31 and 2^32-1 wraps around to a negative (fast) level instead of being treated as "too high":

$ zstd -f -19 README.md -o b.zst -q            # 4815 bytes
$ zstd -f -3000000000 README.md -o a.zst -q    # 11850 bytes: (int)3000000000 is -1294967296, clamped to the fastest level
$ zstd -f -4294967295 README.md -o a.zst -q    # compresses at level -1
$ ZSTD_CLEVEL=+3000000000 zstd ...             # same wrap through the environment variable
$ zstd -f --adapt=max=4294967295 README.md     # accepted, max level becomes -1

-99 and ZSTD_CLEVEL=+99 are clamped to the maximum level (there is a test for it), and values above 2^32-1 are rejected, but the range in between silently selected a fast level.

Changes, all in programs/zstdcli.c:

  • -# and the benchmark range -e# go through a new readCLevelFromChar(), which returns INT_MAX for a value above INT_MAX; the existing clamp then turns it into the maximum level, like -99.
  • ZSTD_CLEVEL clamps the absolute value the same way before applying the sign.
  • readIntFromChar() (used by --adapt=min=,max=) now rejects a value above INT_MAX with its existing "numeric value overflows 32-bit int" error, which it previously printed only above UINT_MAX. This also removes the signed overflow of (int)result * sign for -2147483648.

Tests:

  • tests/cli-tests/compression/levels.sh: zstd -3000000000 and ZSTD_CLEVEL=+3000000000 must produce the same output as -19 (expected stderr updated). Fails on dev (the outputs differ), passes with the change; compression/levels.sh and compression/basic.sh pass with run.py.
  • tests/playTests.sh: --adapt=max=4294967295 must fail (it exited 0 on dev; it now exits 1 with the overflow error). I checked this case by hand against both builds; I did not run the whole playTests.sh.

Built with gcc on Linux x86-64 (-DZSTD_MULTITHREAD -DZSTD_DISABLE_ASM).

AI disclosure (CONTRIBUTING rule 10): I used an AI assistant to help find this issue and write the change; I reviewed the code and ran the tests above.

@meta-cla meta-cla Bot added the CLA Signed label Oct 30, 2026

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant