Validate numeric inputs.

This commit is contained in:
Alex McHale 2010-03-29 15:24:39 -05:00
parent e0a62c7fdb
commit bbe025e04b
2 changed files with 125 additions and 36 deletions

141
redis.c
View File

@ -3065,6 +3065,77 @@ static size_t stringObjectLen(robj *o) {
} }
} }
static int getDoubleFromObject(redisClient *c, robj *o, double *value) {
double parsedValue;
char *eptr = NULL;
if (o && o->type != REDIS_STRING) {
addReplySds(c,sdsnew("-ERR value is not a double\r\n"));
return REDIS_ERR;
}
if (o == NULL)
parsedValue = 0;
else if (o->encoding == REDIS_ENCODING_RAW)
parsedValue = strtod(o->ptr, &eptr);
else if (o->encoding == REDIS_ENCODING_INT)
parsedValue = (long)o->ptr;
else
redisAssert(1 != 1);
if (eptr != NULL && *eptr != '\0') {
addReplySds(c,sdsnew("-ERR value is not a double\r\n"));
return REDIS_ERR;
}
*value = parsedValue;
return REDIS_OK;
}
static int getLongLongFromObject(redisClient *c, robj *o, long long *value) {
long long parsedValue;
char *eptr = NULL;
if (o && o->type != REDIS_STRING) {
addReplySds(c,sdsnew("-ERR value is not an integer\r\n"));
return REDIS_ERR;
}
if (o == NULL)
parsedValue = 0;
else if (o->encoding == REDIS_ENCODING_RAW)
parsedValue = strtoll(o->ptr, &eptr, 10);
else if (o->encoding == REDIS_ENCODING_INT)
parsedValue = (long)o->ptr;
else
redisAssert(1 != 1);
if (eptr != NULL && *eptr != '\0') {
addReplySds(c,sdsnew("-ERR value is not an integer\r\n"));
return REDIS_ERR;
}
*value = parsedValue;
return REDIS_OK;
}
static int getLongFromObject(redisClient *c, robj *o, long *value) {
long long actualValue;
if (getLongLongFromObject(c, o, &actualValue) != REDIS_OK) return REDIS_ERR;
if (actualValue < LONG_MIN || actualValue > LONG_MAX) {
addReplySds(c,sdsnew("-ERR value is out of range\r\n"));
return REDIS_ERR;
}
*value = actualValue;
return REDIS_OK;
}
/*============================ RDB saving/loading =========================== */ /*============================ RDB saving/loading =========================== */
static int rdbSaveType(FILE *fp, unsigned char type) { static int rdbSaveType(FILE *fp, unsigned char type) {
@ -3950,22 +4021,8 @@ static void incrDecrCommand(redisClient *c, long long incr) {
robj *o; robj *o;
o = lookupKeyWrite(c->db,c->argv[1]); o = lookupKeyWrite(c->db,c->argv[1]);
if (o == NULL) {
value = 0;
} else {
if (o->type != REDIS_STRING) {
value = 0;
} else {
char *eptr;
if (o->encoding == REDIS_ENCODING_RAW) if (getLongLongFromObject(c, o, &value) != REDIS_OK) return;
value = strtoll(o->ptr, &eptr, 10);
else if (o->encoding == REDIS_ENCODING_INT)
value = (long)o->ptr;
else
redisAssert(1 != 1);
}
}
value += incr; value += incr;
o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value)); o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
@ -3992,12 +4049,18 @@ static void decrCommand(redisClient *c) {
} }
static void incrbyCommand(redisClient *c) { static void incrbyCommand(redisClient *c) {
long long incr = strtoll(c->argv[2]->ptr, NULL, 10); long long incr;
if (getLongLongFromObject(c, c->argv[2], &incr) != REDIS_OK) return;
incrDecrCommand(c,incr); incrDecrCommand(c,incr);
} }
static void decrbyCommand(redisClient *c) { static void decrbyCommand(redisClient *c) {
long long incr = strtoll(c->argv[2]->ptr, NULL, 10); long long incr;
if (getLongLongFromObject(c, c->argv[2], &incr) != REDIS_OK) return;
incrDecrCommand(c,-incr); incrDecrCommand(c,-incr);
} }
@ -5395,14 +5458,16 @@ 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;
scoreval = strtod(c->argv[2]->ptr,NULL); if (getDoubleFromObject(c, c->argv[2], &scoreval) != 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;
scoreval = strtod(c->argv[2]->ptr,NULL); if (getDoubleFromObject(c, c->argv[2], &scoreval) != REDIS_OK) return;
zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1); zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
} }
@ -5436,12 +5501,15 @@ static void zremCommand(redisClient *c) {
} }
static void zremrangebyscoreCommand(redisClient *c) { static void zremrangebyscoreCommand(redisClient *c) {
double min = strtod(c->argv[2]->ptr,NULL); double min;
double max = strtod(c->argv[3]->ptr,NULL); double max;
long deleted; long deleted;
robj *zsetobj; robj *zsetobj;
zset *zs; zset *zs;
if ((getDoubleFromObject(c, c->argv[2], &min) != REDIS_OK) ||
(getDoubleFromObject(c, c->argv[3], &max) != REDIS_OK)) return;
if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL || if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,zsetobj,REDIS_ZSET)) return; checkType(c,zsetobj,REDIS_ZSET)) return;
@ -5454,13 +5522,16 @@ static void zremrangebyscoreCommand(redisClient *c) {
} }
static void zremrangebyrankCommand(redisClient *c) { static void zremrangebyrankCommand(redisClient *c) {
int start = atoi(c->argv[2]->ptr); long start;
int end = atoi(c->argv[3]->ptr); long end;
int llen; int llen;
long deleted; long deleted;
robj *zsetobj; robj *zsetobj;
zset *zs; zset *zs;
if ((getLongFromObject(c, c->argv[2], &start) != REDIS_OK) ||
(getLongFromObject(c, c->argv[3], &end) != REDIS_OK)) return;
if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL || if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,zsetobj,REDIS_ZSET)) return; checkType(c,zsetobj,REDIS_ZSET)) return;
zs = zsetobj->ptr; zs = zsetobj->ptr;
@ -5567,7 +5638,8 @@ 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--) {
src[i].weight = strtod(c->argv[j]->ptr, NULL); if (getDoubleFromObject(c, c->argv[j], &src[i].weight) != REDIS_OK)
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--;
@ -5689,8 +5761,8 @@ static void zinterCommand(redisClient *c) {
static void zrangeGenericCommand(redisClient *c, int reverse) { static void zrangeGenericCommand(redisClient *c, int reverse) {
robj *o; robj *o;
int start = atoi(c->argv[2]->ptr); long start;
int end = atoi(c->argv[3]->ptr); long end;
int withscores = 0; int withscores = 0;
int llen; int llen;
int rangelen, j; int rangelen, j;
@ -5699,6 +5771,9 @@ static void zrangeGenericCommand(redisClient *c, int reverse) {
zskiplistNode *ln; zskiplistNode *ln;
robj *ele; robj *ele;
if ((getLongFromObject(c, c->argv[2], &start) != REDIS_OK) ||
(getLongFromObject(c, c->argv[3], &end) != REDIS_OK)) return;
if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) { if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
withscores = 1; withscores = 1;
} else if (c->argc >= 5) { } else if (c->argc >= 5) {
@ -6085,7 +6160,8 @@ static void hincrbyCommand(redisClient *c) {
} }
} }
incr = strtoll(c->argv[3]->ptr, NULL, 10); if (getLongLongFromObject(c, c->argv[3], &incr) != REDIS_OK) return;
if (o->encoding == REDIS_ENCODING_ZIPMAP) { if (o->encoding == REDIS_ENCODING_ZIPMAP) {
unsigned char *zm = o->ptr; unsigned char *zm = o->ptr;
unsigned char *zval; unsigned char *zval;
@ -6917,8 +6993,13 @@ static int deleteIfVolatile(redisDb *db, robj *key) {
return dictDelete(db->dict,key) == DICT_OK; return dictDelete(db->dict,key) == DICT_OK;
} }
static void expireGenericCommand(redisClient *c, robj *key, time_t seconds) { static void expireGenericCommand(redisClient *c, robj *key, robj *param, long offset) {
dictEntry *de; dictEntry *de;
time_t seconds;
if (getLongFromObject(c, param, &seconds) != REDIS_OK) return;
seconds -= offset;
de = dictFind(c->db->dict,key); de = dictFind(c->db->dict,key);
if (de == NULL) { if (de == NULL) {
@ -6942,11 +7023,11 @@ static void expireGenericCommand(redisClient *c, robj *key, time_t seconds) {
} }
static void expireCommand(redisClient *c) { static void expireCommand(redisClient *c) {
expireGenericCommand(c,c->argv[1],strtol(c->argv[2]->ptr,NULL,10)); expireGenericCommand(c,c->argv[1],c->argv[2],0);
} }
static void expireatCommand(redisClient *c) { static void expireatCommand(redisClient *c) {
expireGenericCommand(c,c->argv[1],strtol(c->argv[2]->ptr,NULL,10)-time(NULL)); expireGenericCommand(c,c->argv[1],c->argv[2],time(NULL));
} }
static void ttlCommand(redisClient *c) { static void ttlCommand(redisClient *c) {

View File

@ -359,10 +359,18 @@ proc main {server port} {
$r incrby novar 17179869184 $r incrby novar 17179869184
} {34359738368} } {34359738368}
test {INCR against key with spaces (no integer encoded)} { test {INCR fails against key with spaces (no integer encoded)} {
$r set novar " 11 " $r set novar " 11 "
$r incr novar catch {$r incr novar} err
} {12} format $err
} {ERR*}
test {INCR fails against a key holding a list} {
$r rpush mylist 1
catch {$r incr novar} err
$r rpop mylist
format $err
} {ERR*}
test {DECRBY over 32bit value with over 32bit increment, negative res} { test {DECRBY over 32bit value with over 32bit increment, negative res} {
$r set novar 17179869184 $r set novar 17179869184
@ -902,9 +910,9 @@ proc main {server port} {
$r lpush mysavelist world $r lpush mysavelist world
$r set myemptykey {} $r set myemptykey {}
$r set mynormalkey {blablablba} $r set mynormalkey {blablablba}
$r zadd mytestzset a 10 $r zadd mytestzset 10 a
$r zadd mytestzset b 20 $r zadd mytestzset 20 b
$r zadd mytestzset c 30 $r zadd mytestzset 30 c
$r save $r save
} {OK} } {OK}