diff --git a/src/config.c b/src/config.c index 05cb7c9f..4132c830 100644 --- a/src/config.c +++ b/src/config.c @@ -609,6 +609,7 @@ void loadServerConfig(char *filename, char *options) { void configSetCommand(redisClient *c) { robj *o; long long ll; + int err; redisAssertWithInfo(c,c->argv[2],sdsEncodedObject(c->argv[2])); redisAssertWithInfo(c,c->argv[3],sdsEncodedObject(c->argv[3])); o = c->argv[3]; @@ -628,8 +629,8 @@ void configSetCommand(redisClient *c) { zfree(server.masterauth); server.masterauth = ((char*)o->ptr)[0] ? zstrdup(o->ptr) : NULL; } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) { - if (getLongLongFromObject(o,&ll) == REDIS_ERR || - ll < 0) goto badfmt; + ll = memtoll(o->ptr,&err); + if (err || ll < 0) goto badfmt; server.maxmemory = ll; if (server.maxmemory) { if (server.maxmemory < zmalloc_used_memory()) { @@ -851,7 +852,6 @@ void configSetCommand(redisClient *c) { * whole configuration string or accept it all, even if a single * error in a single client class is present. */ for (j = 0; j < vlen; j++) { - char *eptr; long val; if ((j % 4) == 0) { @@ -860,8 +860,8 @@ void configSetCommand(redisClient *c) { goto badfmt; } } else { - val = strtoll(v[j], &eptr, 10); - if (eptr[0] != '\0' || val < 0) { + val = memtoll(v[j], &err); + if (err || val < 0) { sdsfreesplitres(v,vlen); goto badfmt; } @@ -895,7 +895,8 @@ void configSetCommand(redisClient *c) { if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) goto badfmt; server.repl_timeout = ll; } else if (!strcasecmp(c->argv[2]->ptr,"repl-backlog-size")) { - if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) goto badfmt; + ll = memtoll(o->ptr,&err); + if (err || ll < 0) goto badfmt; resizeReplicationBacklog(ll); } else if (!strcasecmp(c->argv[2]->ptr,"repl-backlog-ttl")) { if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; diff --git a/src/util.c b/src/util.c index c5386f3a..91c4d687 100644 --- a/src/util.c +++ b/src/util.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "util.h" #include "sha1.h" @@ -170,11 +171,12 @@ int stringmatch(const char *pattern, const char *string, int nocase) { } /* Convert a string representing an amount of memory into the number of - * bytes, so for instance memtoll("1Gi") will return 1073741824 that is + * bytes, so for instance memtoll("1Gb") will return 1073741824 that is * (1024*1024*1024). * * On parsing error, if *err is not NULL, it's set to 1, otherwise it's - * set to 0 */ + * set to 0. On error the function return value is 0, regardless of the + * fact 'err' is NULL or not. */ long long memtoll(const char *p, int *err) { const char *u; char buf[128]; @@ -183,6 +185,7 @@ long long memtoll(const char *p, int *err) { unsigned int digits; if (err) *err = 0; + /* Search the first non digit character. */ u = p; if (*u == '-') u++; @@ -203,16 +206,26 @@ long long memtoll(const char *p, int *err) { mul = 1024L*1024*1024; } else { if (err) *err = 1; - mul = 1; + return 0; } + + /* Copy the digits into a buffer, we'll use strtoll() to convert + * the digit (without the unit) into a number. */ digits = u-p; if (digits >= sizeof(buf)) { if (err) *err = 1; - return LLONG_MAX; + return 0; } memcpy(buf,p,digits); buf[digits] = '\0'; - val = strtoll(buf,NULL,10); + + char *endptr; + errno = 0; + val = strtoll(buf,&endptr,10); + if ((val == 0 && errno == EINVAL) || *endptr != '\0') { + if (err) *err = 1; + return 0; + } return val*mul; }