]> git.saurik.com Git - redis.git/commitdiff
Validate numeric inputs.
authorAlex McHale <alexmchale@gmail.com>
Mon, 29 Mar 2010 20:24:39 +0000 (15:24 -0500)
committerAlex McHale <alexmchale@gmail.com>
Tue, 13 Apr 2010 15:23:10 +0000 (10:23 -0500)
redis.c
test-redis.tcl

diff --git a/redis.c b/redis.c
index e83a6269db7cf765a4785d71ee889e49f3ad85fc..cbb0993adef7381b817e4c6c991da81e192bebef 100644 (file)
--- a/redis.c
+++ b/redis.c
@@ -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 =========================== */
 
 static int rdbSaveType(FILE *fp, unsigned char type) {
@@ -3950,22 +4021,8 @@ static void incrDecrCommand(redisClient *c, long long incr) {
     robj *o;
 
     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)
-                value = strtoll(o->ptr, &eptr, 10);
-            else if (o->encoding == REDIS_ENCODING_INT)
-                value = (long)o->ptr;
-            else
-                redisAssert(1 != 1);
-        }
-    }
+    if (getLongLongFromObject(c, o, &value) != REDIS_OK) return;
 
     value += incr;
     o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
@@ -3992,12 +4049,18 @@ static void decrCommand(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);
 }
 
 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);
 }
 
@@ -5395,14 +5458,16 @@ static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scor
 static void zaddCommand(redisClient *c) {
     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);
 }
 
 static void zincrbyCommand(redisClient *c) {
     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);
 }
 
@@ -5436,12 +5501,15 @@ static void zremCommand(redisClient *c) {
 }
 
 static void zremrangebyscoreCommand(redisClient *c) {
-    double min = strtod(c->argv[2]->ptr,NULL);
-    double max = strtod(c->argv[3]->ptr,NULL);
+    double min;
+    double max;
     long deleted;
     robj *zsetobj;
     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 ||
         checkType(c,zsetobj,REDIS_ZSET)) return;
 
@@ -5454,13 +5522,16 @@ static void zremrangebyscoreCommand(redisClient *c) {
 }
 
 static void zremrangebyrankCommand(redisClient *c) {
-    int start = atoi(c->argv[2]->ptr);
-    int end = atoi(c->argv[3]->ptr);
+    long start;
+    long end;
     int llen;
     long deleted;
     robj *zsetobj;
     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 ||
         checkType(c,zsetobj,REDIS_ZSET)) return;
     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")) {
                 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")) {
                 j++; remaining--;
@@ -5689,8 +5761,8 @@ static void zinterCommand(redisClient *c) {
 
 static void zrangeGenericCommand(redisClient *c, int reverse) {
     robj *o;
-    int start = atoi(c->argv[2]->ptr);
-    int end = atoi(c->argv[3]->ptr);
+    long start;
+    long end;
     int withscores = 0;
     int llen;
     int rangelen, j;
@@ -5699,6 +5771,9 @@ static void zrangeGenericCommand(redisClient *c, int reverse) {
     zskiplistNode *ln;
     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")) {
         withscores = 1;
     } 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) {
         unsigned char *zm = o->ptr;
         unsigned char *zval;
@@ -6917,8 +6993,13 @@ static int deleteIfVolatile(redisDb *db, robj *key) {
     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;
+    time_t seconds;
+
+    if (getLongFromObject(c, param, &seconds) != REDIS_OK) return;
+
+    seconds -= offset;
 
     de = dictFind(c->db->dict,key);
     if (de == NULL) {
@@ -6942,11 +7023,11 @@ static void expireGenericCommand(redisClient *c, robj *key, time_t seconds) {
 }
 
 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) {
-    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) {
index 371b26e5c76c6eccfde5bfa3f7f4c2e5bc45323e..f45c473823c577a92a4b6d1e150a3ac513763edf 100644 (file)
@@ -359,10 +359,18 @@ proc main {server port} {
         $r incrby novar 17179869184
     } {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 incr novar
-    } {12}
+        catch {$r incr novar} err
+        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} {
         $r set novar 17179869184
@@ -902,9 +910,9 @@ proc main {server port} {
         $r lpush mysavelist world
         $r set myemptykey {}
         $r set mynormalkey {blablablba}
-        $r zadd mytestzset a 10
-        $r zadd mytestzset b 20
-        $r zadd mytestzset c 30
+        $r zadd mytestzset 10 a
+        $r zadd mytestzset 20 b
+        $r zadd mytestzset 30 c
         $r save
     } {OK}