Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions programs/zstdcli.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <string.h> /* strcmp, strlen */
#include <stdio.h> /* fprintf(), stdin, stdout, stderr */
#include <assert.h> /* assert */
#include <limits.h> /* INT_MAX */

#include "fileio.h" /* stdinmark, stdoutmark, ZSTD_EXTENSION */
#ifndef ZSTD_NOBENCH
Expand Down Expand Up @@ -413,9 +414,20 @@ static int readIntFromChar(const char** stringPtr) {
sign = -1;
}
if (readU32FromCharChecked(stringPtr, &result)) { errorOut(errorMsg); }
if (result > (unsigned)INT_MAX) { errorOut(errorMsg); }
return (int) result * sign;
}

/*! readCLevelFromChar() :
* @return : compression level read from input in `char` format, as readU32FromChar().
* A value above INT_MAX is returned as INT_MAX, so that it is clamped to the maximum level
* like any other level that is too high, instead of wrapping around to a negative level.
* Note : function will exit() program if digit sequence overflows */
static int readCLevelFromChar(const char** stringPtr) {
unsigned const level = readU32FromChar(stringPtr);
return level > (unsigned)INT_MAX ? INT_MAX : (int)level;
}

/*! readSizeTFromCharChecked() :
* @return 0 if success, and store the result in *value.
* allows and interprets K, KB, KiB, M, MB, MiB, G, GB and GiB suffix.
Expand Down Expand Up @@ -791,7 +803,8 @@ static int init_cLevel(void) {
DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: numeric value too large \n", ENV_CLEVEL, env);
return ZSTDCLI_CLEVEL_DEFAULT;
} else if (*ptr == 0) {
return sign * (int)absLevel;
/* above INT_MAX, clamp like a level that is too high rather than wrap */
return sign * (absLevel > (unsigned)INT_MAX ? INT_MAX : (int)absLevel);
} }

DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: not a valid integer value \n", ENV_CLEVEL, env);
Expand Down Expand Up @@ -1207,7 +1220,7 @@ int main(int argCount, const char* argv[])
#ifndef ZSTD_NOCOMPRESS
/* compression Level */
if ((*argument>='0') && (*argument<='9')) {
dictCLevel = cLevel = (int)readU32FromChar(&argument);
dictCLevel = cLevel = readCLevelFromChar(&argument);
continue;
}
#endif
Expand Down Expand Up @@ -1282,7 +1295,7 @@ int main(int argCount, const char* argv[])
case 'e':
/* compression Level */
argument++;
cLevelLast = (int)readU32FromChar(&argument);
cLevelLast = readCLevelFromChar(&argument);
break;

/* Modify Nb Iterations (benchmark only) */
Expand Down
4 changes: 4 additions & 0 deletions tests/cli-tests/compression/levels.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,21 @@ zstd --fast=200000 file -c | zstd -t

zstd -5000000000 -f file && die "Level too large, must fail" ||:
zstd --fast=5000000000 -f file && die "Level too large, must fail" ||:
zstd -3000000000 file -o file-3g.zst -q
cmp file-19.zst file-3g.zst || die "Level 3000000000 is clamped to 19"

# Test setting a level through the environment variable
ZSTD_CLEVEL=-10 zstd file -o file-f10-env.zst -q
ZSTD_CLEVEL=1 zstd file -o file-1-env.zst -q
ZSTD_CLEVEL=+19 zstd file -o file-19-env.zst -q
ZSTD_CLEVEL=+99 zstd file -o file-99-env.zst -q
ZSTD_CLEVEL=+3000000000 zstd file -o file-3g-env.zst -q

cmp file-f10.zst file-f10-env.zst || die "Environment variable failed to set level"
cmp file-1.zst file-1-env.zst || die "Environment variable failed to set level"
cmp file-19.zst file-19-env.zst || die "Environment variable failed to set level"
cmp file-99.zst file-99-env.zst || die "Environment variable failed to set level"
cmp file-19.zst file-3g-env.zst || die "Environment variable failed to set level"

# Test invalid environment clevel is the default level
zstd -f file -q
Expand Down
4 changes: 4 additions & 0 deletions tests/cli-tests/compression/levels.sh.stderr.exact
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,21 @@ zstd -5000000000 -f file && die "Level too large, must fail" ||:
error: numeric value overflows 32-bit unsigned int
zstd --fast=5000000000 -f file && die "Level too large, must fail" ||:
error: numeric value overflows 32-bit unsigned int
zstd -3000000000 file -o file-3g.zst -q
cmp file-19.zst file-3g.zst || die "Level 3000000000 is clamped to 19"

# Test setting a level through the environment variable
ZSTD_CLEVEL=-10 zstd file -o file-f10-env.zst -q
ZSTD_CLEVEL=1 zstd file -o file-1-env.zst -q
ZSTD_CLEVEL=+19 zstd file -o file-19-env.zst -q
ZSTD_CLEVEL=+99 zstd file -o file-99-env.zst -q
ZSTD_CLEVEL=+3000000000 zstd file -o file-3g-env.zst -q

cmp file-f10.zst file-f10-env.zst || die "Environment variable failed to set level"
cmp file-1.zst file-1-env.zst || die "Environment variable failed to set level"
cmp file-19.zst file-19-env.zst || die "Environment variable failed to set level"
cmp file-99.zst file-99-env.zst || die "Environment variable failed to set level"
cmp file-19.zst file-3g-env.zst || die "Environment variable failed to set level"

# Test invalid environment clevel is the default level
zstd -f file -q
Expand Down
1 change: 1 addition & 0 deletions tests/playTests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,7 @@ then
datagen > tmp
zstd --adapt= tmp && die "invalid compression parameter"
zstd -f -vv --adapt=min=10,max=9 tmp && die "--adapt must fail on incoherent bounds"
zstd -f --adapt=max=4294967295 tmp && die "--adapt must reject a level that overflows int"

println "\n===> rsyncable mode "
roundTripTest -g10M " --rsyncable"
Expand Down