Improve BLMPOP/BZMPOP/WAIT timeout overflow handling and error messages (#11338)

Refine getTimeoutFromObjectOrReply() out-of-range check.

Timeout is parsed (and verifies out of range) as double and
multiplied by 1000, added mstime() and stored in long-long
which might lead to out-of-range value of long-long.

Co-authored-by: moticless <moticless@github.com>
Co-authored-by: Oran Agra <oran@redislabs.com>
Co-authored-by: Ozan Tezcan <ozantezcan@gmail.com>
This commit is contained in:
Moti Cohen 2022-10-06 12:12:05 +03:00 committed by GitHub
parent b08ebff31f
commit 210ad2e4db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 3 deletions

View File

@ -164,12 +164,19 @@ void handleBlockedClientsTimeout(void) {
int getTimeoutFromObjectOrReply(client *c, robj *object, mstime_t *timeout, int unit) {
long long tval;
long double ftval;
mstime_t now = mstime();
if (unit == UNIT_SECONDS) {
if (getLongDoubleFromObjectOrReply(c,object,&ftval,
"timeout is not a float or out of range") != C_OK)
return C_ERR;
tval = (long long) (ftval * 1000.0);
ftval *= 1000.0; /* seconds => millisec */
if (ftval > LLONG_MAX) {
addReplyError(c, "timeout is out of range");
return C_ERR;
}
tval = (long long) ftval;
} else {
if (getLongLongFromObjectOrReply(c,object,&tval,
"timeout is not an integer or out of range") != C_OK)
@ -182,7 +189,11 @@ int getTimeoutFromObjectOrReply(client *c, robj *object, mstime_t *timeout, int
}
if (tval > 0) {
tval += mstime();
if (tval > LLONG_MAX - now) {
addReplyError(c,"timeout is out of range"); /* 'tval+now' would overflow */
return C_ERR;
}
tval += now;
}
*timeout = tval;

View File

@ -1215,6 +1215,14 @@ foreach {pop} {BLPOP BLMPOP_LEFT} {
} {foo{t} aguacate}
}
test "BLPOP: timeout value out of range" {
# Timeout is parsed as float and multiplied by 1000, added mstime()
# and stored in long-long which might lead to out-of-range value.
# (Even though given timeout is smaller than LLONG_MAX, the result
# will be bigger)
assert_error "ERR *is out of range*" {r BLPOP blist1 0x7FFFFFFFFFFFFF}
}
foreach {pop} {BLPOP BRPOP BLMPOP_LEFT BLMPOP_RIGHT} {
test "$pop: with single empty list argument" {
set rd [redis_deferring_client]

View File

@ -18,7 +18,20 @@ start_server {} {
fail "Replication not started."
}
}
test {WAIT out of range timeout (milliseconds)} {
# Timeout is parsed as milliseconds by getLongLongFromObjectOrReply().
# Verify we get out of range message if value is behind LLONG_MAX
# (decimal value equals to 0x8000000000000000)
assert_error "*or out of range*" {$master wait 2 9223372036854775808}
# expected to fail by later overflow condition after addition
# of mstime(). (decimal value equals to 0x7FFFFFFFFFFFFFFF)
assert_error "*timeout is out of range*" {$master wait 2 9223372036854775807}
assert_error "*timeout is negative*" {$master wait 2 -1}
}
test {WAIT should acknowledge 1 additional copy of the data} {
$master set foo 0
$master incr foo