diff --git a/src/config.c b/src/config.c index a83f5adc0..5b9616733 100644 --- a/src/config.c +++ b/src/config.c @@ -559,8 +559,8 @@ void loadServerConfigFromString(char *config) { "an invalid one, or 'master' which has no buffer limits."; goto loaderr; } - hard = memtoll(argv[2],NULL); - soft = memtoll(argv[3],NULL); + hard = memtoull(argv[2],NULL); + soft = memtoull(argv[3],NULL); soft_seconds = atoi(argv[4]); if (soft_seconds < 0) { err = "Negative number of seconds in soft limit is invalid"; @@ -744,8 +744,8 @@ void loadServerConfig(char *filename, char config_from_stdin, char *options) { #define config_set_memory_field(_name,_var) \ } else if (!strcasecmp(c->argv[2]->ptr,_name)) { \ - ll = memtoll(o->ptr,&err); \ - if (err || ll < 0) goto badfmt; \ + ll = memtoull(o->ptr,&err); \ + if (err) goto badfmt; \ _var = ll; #define config_set_special_field(_name) \ @@ -855,22 +855,26 @@ void configSetCommand(client *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++) { - long val; - if ((j % 4) == 0) { int class = getClientTypeByName(v[j]); - if (class == -1 || class == CLIENT_TYPE_MASTER) { - sdsfreesplitres(v,vlen); - goto badfmt; - } + if (class == -1 || class == CLIENT_TYPE_MASTER) + break; + } else if ((j % 4) == 3) { + char *endptr; + long l = strtoll(v[j],&endptr,10); + if (l < 0 || *endptr != '\0') + break; } else { - val = memtoll(v[j], &err); - if (err || val < 0) { - sdsfreesplitres(v,vlen); - goto badfmt; - } + memtoull(v[j], &err); + if (err) + break; } } + if (j < vlen) { + sdsfreesplitres(v,vlen); + goto badfmt; + } + /* Finally set the new config */ for (j = 0; j < vlen; j += 4) { int class; @@ -878,8 +882,8 @@ void configSetCommand(client *c) { int soft_seconds; class = getClientTypeByName(v[j]); - hard = memtoll(v[j+1],NULL); - soft = memtoll(v[j+2],NULL); + hard = memtoull(v[j+1],NULL); + soft = memtoull(v[j+2],NULL); soft_seconds = strtoll(v[j+3],NULL,10); server.client_obuf_limits[class].hard_limit_bytes = hard; @@ -2123,22 +2127,22 @@ static int numericBoundaryCheck(typeData data, long long ll, const char **err) { return 1; } + static int numericConfigSet(typeData data, sds value, int update, const char **err) { long long ll, prev = 0; if (data.numeric.is_memory) { int memerr; - ll = memtoll(value, &memerr); - if (memerr || ll < 0) { + ll = memtoull(value, &memerr); + if (memerr) { *err = "argument must be a memory value"; return 0; } } else { - if (!string2ll(value, sdslen(value),&ll)) { + if (!string2ll(value, sdslen(value), &ll)) { *err = "argument couldn't be parsed into an integer" ; return 0; } } - if (!numericBoundaryCheck(data, ll, err)) return 0; @@ -2157,12 +2161,21 @@ static int numericConfigSet(typeData data, sds value, int update, const char **e static void numericConfigGet(client *c, typeData data) { char buf[128]; - long long value = 0; + if (data.numeric.is_memory) { + unsigned long long value = 0; + + GET_NUMERIC_TYPE(value) - GET_NUMERIC_TYPE(value) + ull2string(buf, sizeof(buf), value); + addReplyBulkCString(c, buf); + } else{ + long long value = 0; + + GET_NUMERIC_TYPE(value) - ll2string(buf, sizeof(buf), value); - addReplyBulkCString(c, buf); + ll2string(buf, sizeof(buf), value); + addReplyBulkCString(c, buf); + } } static void numericConfigRewrite(typeData data, const char *name, struct rewriteConfigState *state) { diff --git a/src/util.c b/src/util.c index df7a489a5..d57420007 100644 --- a/src/util.c +++ b/src/util.c @@ -185,18 +185,19 @@ int stringmatchlen_fuzz_test(void) { return total_matches; } + /* Convert a string representing an amount of memory into the number of - * bytes, so for instance memtoll("1Gb") will return 1073741824 that is + * bytes, so for instance memtoull("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. 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) { +unsigned long long memtoull(const char *p, int *err) { const char *u; char buf[128]; long mul; /* unit multiplier */ - long long val; + unsigned long long val; unsigned int digits; if (err) *err = 0; @@ -236,7 +237,7 @@ long long memtoll(const char *p, int *err) { char *endptr; errno = 0; - val = strtoll(buf,&endptr,10); + val = strtoull(buf,&endptr,10); if ((val == 0 && errno == EINVAL) || *endptr != '\0') { if (err) *err = 1; return 0; @@ -307,26 +308,12 @@ uint32_t sdigits10(int64_t v) { /* Convert a long long into a string. Returns the number of * characters needed to represent the number. - * If the buffer is not big enough to store the string, 0 is returned. - * - * Based on the following article (that apparently does not provide a - * novel approach but only publicizes an already used technique): - * - * https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920 - * - * Modified in order to handle signed integers since the original code was - * designed for unsigned integers. */ + * If the buffer is not big enough to store the string, 0 is returned. */ int ll2string(char *dst, size_t dstlen, long long svalue) { - static const char digits[201] = - "0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"; - int negative; unsigned long long value; + int negative = 0; - /* The main loop works with 64bit unsigned integers for simplicity, so + /* The ull2string function with 64bit unsigned integers for simplicity, so * we convert the number here and remember if it is negative. */ if (svalue < 0) { if (svalue != LLONG_MIN) { @@ -334,20 +321,45 @@ int ll2string(char *dst, size_t dstlen, long long svalue) { } else { value = ((unsigned long long) LLONG_MAX)+1; } + if (dstlen < 2) + return 0; negative = 1; + dst[0] = '-'; + dst++; + dstlen--; } else { value = svalue; - negative = 0; } + /* Converts the unsigned long long value to string*/ + int length = ull2string(dst, dstlen, value); + if (length == 0) return 0; + return length + negative; +} + +/* Convert a unsigned long long into a string. Returns the number of + * characters needed to represent the number. + * If the buffer is not big enough to store the string, 0 is returned. + * + * Based on the following article (that apparently does not provide a + * novel approach but only publicizes an already used technique): + * + * https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920 */ +int ull2string(char *dst, size_t dstlen, unsigned long long value) { + static const char digits[201] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + /* Check length. */ - uint32_t const length = digits10(value)+negative; + uint32_t length = digits10(value); if (length >= dstlen) return 0; /* Null term. */ - uint32_t next = length; - dst[next] = '\0'; - next--; + uint32_t next = length - 1; + dst[next + 1] = '\0'; while (value >= 100) { int const i = (value % 100) * 2; value /= 100; @@ -365,8 +377,6 @@ int ll2string(char *dst, size_t dstlen, long long svalue) { dst[next - 1] = digits[i]; } - /* Add sign. */ - if (negative) dst[0] = '-'; return length; } diff --git a/src/util.h b/src/util.h index bf2115ab7..e568ac6b3 100644 --- a/src/util.h +++ b/src/util.h @@ -48,12 +48,13 @@ typedef enum { int stringmatchlen(const char *p, int plen, const char *s, int slen, int nocase); int stringmatch(const char *p, const char *s, int nocase); int stringmatchlen_fuzz_test(void); -long long memtoll(const char *p, int *err); +unsigned long long memtoull(const char *p, int *err); const char *mempbrk(const char *s, size_t len, const char *chars, size_t charslen); char *memmapchars(char *s, size_t len, const char *from, const char *to, size_t setlen); uint32_t digits10(uint64_t v); uint32_t sdigits10(int64_t v); int ll2string(char *s, size_t len, long long value); +int ull2string(char *s, size_t len, unsigned long long value); int string2ll(const char *s, size_t slen, long long *value); int string2ull(const char *s, unsigned long long *value); int string2l(const char *s, size_t slen, long *value);