From 7236fdb22f7fdb60833c32121b0828f11a13883c Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Wed, 13 Oct 2010 21:58:21 +0200 Subject: [PATCH] Return error when min and/or max in the sorted set range spec is not a double --- src/t_zset.c | 25 ++++++++++++++++++------- tests/unit/type/zset.tcl | 12 ++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/t_zset.c b/src/t_zset.c index f1a10378..d45e9369 100644 --- a/src/t_zset.c +++ b/src/t_zset.c @@ -307,7 +307,8 @@ zskiplistNode* zslistTypeGetElementByRank(zskiplist *zsl, unsigned long rank) { } /* Populate the rangespec according to the objects min and max. */ -int zslParseRange(robj *min, robj *max, zrangespec *spec) { +static int zslParseRange(robj *min, robj *max, zrangespec *spec) { + char *eptr; spec->minex = spec->maxex = 0; /* Parse the min-max interval. If one of the values is prefixed @@ -318,20 +319,24 @@ int zslParseRange(robj *min, robj *max, zrangespec *spec) { spec->min = (long)min->ptr; } else { if (((char*)min->ptr)[0] == '(') { - spec->min = strtod((char*)min->ptr+1,NULL); + spec->min = strtod((char*)min->ptr+1,&eptr); + if (eptr[0] != '\0' || isnan(spec->min)) return REDIS_ERR; spec->minex = 1; } else { - spec->min = strtod((char*)min->ptr,NULL); + spec->min = strtod((char*)min->ptr,&eptr); + if (eptr[0] != '\0' || isnan(spec->min)) return REDIS_ERR; } } if (max->encoding == REDIS_ENCODING_INT) { spec->max = (long)max->ptr; } else { if (((char*)max->ptr)[0] == '(') { - spec->max = strtod((char*)max->ptr+1,NULL); + spec->max = strtod((char*)max->ptr+1,&eptr); + if (eptr[0] != '\0' || isnan(spec->max)) return REDIS_ERR; spec->maxex = 1; } else { - spec->max = strtod((char*)max->ptr,NULL); + spec->max = strtod((char*)max->ptr,&eptr); + if (eptr[0] != '\0' || isnan(spec->max)) return REDIS_ERR; } } @@ -481,7 +486,10 @@ void zremrangebyscoreCommand(redisClient *c) { zset *zs; /* Parse the range arguments. */ - zslParseRange(c->argv[2],c->argv[3],&range); + if (zslParseRange(c->argv[2],c->argv[3],&range) != REDIS_OK) { + addReplyError(c,"min or max is not a double"); + return; + } if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL || checkType(c,o,REDIS_ZSET)) return; @@ -838,7 +846,10 @@ void genericZrangebyscoreCommand(redisClient *c, int reverse, int justcount) { void *replylen = NULL; /* Parse the range arguments. */ - zslParseRange(c->argv[2],c->argv[3],&range); + if (zslParseRange(c->argv[2],c->argv[3],&range) != REDIS_OK) { + addReplyError(c,"min or max is not a double"); + return; + } /* Parse optional extra arguments. Note that ZCOUNT will exactly have * 4 arguments, so we'll never enter the following code path. */ diff --git a/tests/unit/type/zset.tcl b/tests/unit/type/zset.tcl index 47c05607..6b8fc54a 100644 --- a/tests/unit/type/zset.tcl +++ b/tests/unit/type/zset.tcl @@ -253,6 +253,12 @@ start_server {tags {"zset"}} { assert_equal {d 3 c 2} [r zrevrangebyscore zset 5 2 LIMIT 2 3 WITHSCORES] } + test "ZRANGEBYSCORE with non-value min or max" { + assert_error "*not a double*" {r zrangebyscore fooz str 1} + assert_error "*not a double*" {r zrangebyscore fooz 1 str} + assert_error "*not a double*" {r zrangebyscore fooz 1 NaN} + } + tags {"slow"} { test {ZRANGEBYSCORE fuzzy test, 100 ranges in 1000 elements sorted set} { set err {} @@ -386,6 +392,12 @@ start_server {tags {"zset"}} { assert_equal {a e} [r zrange zset 0 -1] } + test "ZREMRANGEBYSCORE with non-value min or max" { + assert_error "*not a double*" {r zremrangebyscore fooz str 1} + assert_error "*not a double*" {r zremrangebyscore fooz 1 str} + assert_error "*not a double*" {r zremrangebyscore fooz 1 NaN} + } + test "ZREMRANGEBYRANK basics" { proc remrangebyrank {min max} { create_zset zset {1 a 2 b 3 c 4 d 5 e}