Commit 3a1ab86a authored by Pieter Noordhuis's avatar Pieter Noordhuis
Browse files

Change getDoubleFromObject to fail on NaN.

Return an error when the resulting value is not a number (NaN). Fix
ZUNIONSTORE/ZINTERSTORE to clean up when a weight argument is not a
double value. Backport of 673e1fb7 to 2.0.0.
parent c6375e6a
...@@ -3288,7 +3288,7 @@ static int getDoubleFromObject(robj *o, double *target) { ...@@ -3288,7 +3288,7 @@ static int getDoubleFromObject(robj *o, double *target) {
redisAssert(o->type == REDIS_STRING); redisAssert(o->type == REDIS_STRING);
if (o->encoding == REDIS_ENCODING_RAW) { if (o->encoding == REDIS_ENCODING_RAW) {
value = strtod(o->ptr, &eptr); value = strtod(o->ptr, &eptr);
if (eptr[0] != '\0') return REDIS_ERR; if (eptr[0] != '\0' || isnan(value)) return REDIS_ERR;
} else if (o->encoding == REDIS_ENCODING_INT) { } else if (o->encoding == REDIS_ENCODING_INT) {
value = (long)o->ptr; value = (long)o->ptr;
} else { } else {
...@@ -5738,11 +5738,6 @@ static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scor ...@@ -5738,11 +5738,6 @@ static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scor
zset *zs; zset *zs;
double *score; double *score;
if (isnan(scoreval)) {
addReplySds(c,sdsnew("-ERR provide score is Not A Number (nan)\r\n"));
return;
}
zsetobj = lookupKeyWrite(c->db,key); zsetobj = lookupKeyWrite(c->db,key);
if (zsetobj == NULL) { if (zsetobj == NULL) {
zsetobj = createZsetObject(); zsetobj = createZsetObject();
...@@ -5773,7 +5768,7 @@ static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scor ...@@ -5773,7 +5768,7 @@ static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scor
} }
if (isnan(*score)) { if (isnan(*score)) {
addReplySds(c, addReplySds(c,
sdsnew("-ERR resulting score is Not A Number (nan)\r\n")); sdsnew("-ERR resulting score is not a number (NaN)\r\n"));
zfree(score); zfree(score);
/* Note that we don't need to check if the zset may be empty and /* Note that we don't need to check if the zset may be empty and
* should be removed here, as we can only obtain Nan as score if * should be removed here, as we can only obtain Nan as score if
...@@ -5827,15 +5822,13 @@ static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scor ...@@ -5827,15 +5822,13 @@ static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scor
static void zaddCommand(redisClient *c) { static void zaddCommand(redisClient *c) {
double scoreval; double scoreval;
if (getDoubleFromObjectOrReply(c,c->argv[2],&scoreval,NULL) != REDIS_OK) return;
if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0); zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
} }
static void zincrbyCommand(redisClient *c) { static void zincrbyCommand(redisClient *c) {
double scoreval; double scoreval;
if (getDoubleFromObjectOrReply(c,c->argv[2],&scoreval,NULL) != REDIS_OK) return;
if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1); zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
} }
...@@ -6010,8 +6003,12 @@ static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) { ...@@ -6010,8 +6003,12 @@ static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
if (remaining >= (zsetnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) { if (remaining >= (zsetnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
j++; remaining--; j++; remaining--;
for (i = 0; i < zsetnum; i++, j++, remaining--) { for (i = 0; i < zsetnum; i++, j++, remaining--) {
if (getDoubleFromObjectOrReply(c, c->argv[j], &src[i].weight, NULL) != REDIS_OK) if (getDoubleFromObjectOrReply(c,c->argv[j],&src[i].weight,
"weight value is not a double") != REDIS_OK)
{
zfree(src);
return; return;
}
} }
} else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) { } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
j++; remaining--; j++; remaining--;
......
...@@ -17,7 +17,7 @@ proc assert_equal {expected value} { ...@@ -17,7 +17,7 @@ proc assert_equal {expected value} {
} }
proc assert_error {pattern code} { proc assert_error {pattern code} {
if {[catch $code error]} { if {[catch {uplevel 1 $code} error]} {
assert_match $pattern $error assert_match $pattern $error
} else { } else {
puts "!! ERROR\nExpected an error but nothing was catched" puts "!! ERROR\nExpected an error but nothing was catched"
......
...@@ -419,6 +419,8 @@ start_server {tags {"zset"}} { ...@@ -419,6 +419,8 @@ start_server {tags {"zset"}} {
foreach cmd {ZUNIONSTORE ZINTERSTORE} { foreach cmd {ZUNIONSTORE ZINTERSTORE} {
test "$cmd with +inf/-inf scores" { test "$cmd with +inf/-inf scores" {
r del zsetinf1 zsetinf2
r zadd zsetinf1 +inf key r zadd zsetinf1 +inf key
r zadd zsetinf2 +inf key r zadd zsetinf2 +inf key
r $cmd zsetinf3 2 zsetinf1 zsetinf2 r $cmd zsetinf3 2 zsetinf1 zsetinf2
...@@ -439,6 +441,16 @@ start_server {tags {"zset"}} { ...@@ -439,6 +441,16 @@ start_server {tags {"zset"}} {
r $cmd zsetinf3 2 zsetinf1 zsetinf2 r $cmd zsetinf3 2 zsetinf1 zsetinf2
assert_equal -inf [r zscore zsetinf3 key] assert_equal -inf [r zscore zsetinf3 key]
} }
test "$cmd with NaN weights" {
r del zsetinf1 zsetinf2
r zadd zsetinf1 1.0 key
r zadd zsetinf2 1.0 key
assert_error "*weight value is not a double*" {
r $cmd zsetinf3 2 zsetinf1 zsetinf2 weights nan nan
}
}
} }
tags {"slow"} { tags {"slow"} {
...@@ -485,22 +497,16 @@ start_server {tags {"zset"}} { ...@@ -485,22 +497,16 @@ start_server {tags {"zset"}} {
} {} } {}
} }
test {ZSET element can't be set to nan with ZADD} { test {ZSET element can't be set to NaN with ZADD} {
set e {} assert_error "*not a double*" {r zadd myzset nan abc}
catch {r zadd myzset nan abc} e }
set _ $e
} {*Not A Number*}
test {ZSET element can't be set to nan with ZINCRBY} { test {ZSET element can't be set to NaN with ZINCRBY} {
set e {} assert_error "*not a double*" {r zadd myzset nan abc}
catch {r zincrby myzset nan abc} e }
set _ $e
} {*Not A Number*}
test {ZINCRBY calls leading to Nan are refused} { test {ZINCRBY calls leading to NaN result in error} {
set e {}
r zincrby myzset +inf abc r zincrby myzset +inf abc
catch {r zincrby myzset -inf abc} e assert_error "*NaN*" {r zincrby myzset -inf abc}
set _ $e }
} {*Not A Number*}
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment