summaryrefslogtreecommitdiff
path: root/src/sds.c
diff options
context:
space:
mode:
authorEgor Seredin <4819888+agmt@users.noreply.github.com>2020-11-04 20:38:46 +0900
committerGitHub <noreply@github.com>2020-11-04 13:38:46 +0200
commitf4ca3d8757d6abb3536610ddb7b9ab3ad39e81df (patch)
treed8a6e05448871c551b30d55a64d5980a3a5721ed /src/sds.c
parent762be79f0bc26366fbc3ac16e33d3baa854fbcf1 (diff)
downloadredis-f4ca3d8757d6abb3536610ddb7b9ab3ad39e81df.tar.gz
Allow '\0' inside of result of sdscatvprintf, and efficiency improvements (#6260)
This will allow to use: RedisModule_CreateStringPrintf(ctx, "%s %c %s", "string1", 0, "string2"); On large string, the previous code would incrementally retry to double the output buffer. now it uses the the return value of snprintf and grows to the right size in one step. and also avoids an excessive strlen in sdscat at the end.
Diffstat (limited to 'src/sds.c')
-rw-r--r--src/sds.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/src/sds.c b/src/sds.c
index 4cbbabfbb..f72eac921 100644
--- a/src/sds.c
+++ b/src/sds.c
@@ -545,6 +545,7 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
va_list cpy;
char staticbuf[1024], *buf = staticbuf, *t;
size_t buflen = strlen(fmt)*2;
+ int bufstrlen;
/* We try to start using a static buffer for speed.
* If not possible we revert to heap allocation. */
@@ -555,16 +556,19 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
buflen = sizeof(staticbuf);
}
- /* Try with buffers two times bigger every time we fail to
+ /* Alloc enough space for buffer and \0 after failing to
* fit the string in the current buffer size. */
while(1) {
- buf[buflen-2] = '\0';
va_copy(cpy,ap);
- vsnprintf(buf, buflen, fmt, cpy);
+ bufstrlen = vsnprintf(buf, buflen, fmt, cpy);
va_end(cpy);
- if (buf[buflen-2] != '\0') {
+ if (bufstrlen < 0) {
if (buf != staticbuf) s_free(buf);
- buflen *= 2;
+ return NULL;
+ }
+ if (((size_t)bufstrlen) >= buflen) {
+ if (buf != staticbuf) s_free(buf);
+ buflen = ((size_t)bufstrlen) + 1;
buf = s_malloc(buflen);
if (buf == NULL) return NULL;
continue;
@@ -573,7 +577,7 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
}
/* Finally concat the obtained string to the SDS string and return it. */
- t = sdscat(s, buf);
+ t = sdscatlen(s, buf, bufstrlen);
if (buf != staticbuf) s_free(buf);
return t;
}
@@ -1183,6 +1187,22 @@ int sdsTest(int argc, char **argv) {
sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)
sdsfree(x);
+ x = sdscatprintf(sdsempty(),"a%cb",0);
+ test_cond("sdscatprintf() seems working with \\0 inside of result",
+ sdslen(x) == 3 && memcmp(x,"a\0""b\0",4) == 0)
+
+ {
+ sdsfree(x);
+ char etalon[1024*1024];
+ for (size_t i = 0; i < sizeof(etalon); i++) {
+ etalon[i] = '0';
+ }
+ x = sdscatprintf(sdsempty(),"%0*d",(int)sizeof(etalon),0);
+ test_cond("sdscatprintf() can print 1MB",
+ sdslen(x) == sizeof(etalon) && memcmp(x,etalon,sizeof(etalon)) == 0)
+ }
+
+ sdsfree(x);
x = sdsnew("--");
x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);
test_cond("sdscatfmt() seems working in the base case",