diff --git a/json-build.h b/json-build.h index f3c1d2d..cfde0ef 100644 --- a/json-build.h +++ b/json-build.h @@ -371,7 +371,10 @@ _jsonb_escape( } } - if (*pos + len + extra_bytes > bufsize) return JSONB_ERROR_NOMEM; + if (*pos + len + extra_bytes > bufsize) { + *buf = '\0'; + return JSONB_ERROR_NOMEM; + } if (esc_buf) { *pos += len + extra_bytes; @@ -400,7 +403,7 @@ jsonb_key(jsonb *b, char buf[], size_t bufsize, const char key[], size_t len) case JSONB_OBJECT_KEY_OR_CLOSE: { enum jsonbcode ret; BUFFER_COPY_CHAR(b, '"', pos, buf, bufsize); - ret = _jsonb_escape(&pos, buf + b->pos, bufsize, key, len); + ret = _jsonb_escape(&pos, buf + b->pos, bufsize - b->pos, key, len); if (ret != JSONB_OK) return ret; BUFFER_COPY(b, "\":", 2, pos, buf, bufsize); STACK_HEAD(b, JSONB_OBJECT_VALUE); @@ -551,7 +554,7 @@ jsonb_string( return JSONB_ERROR_INPUT; } BUFFER_COPY_CHAR(b, '"', pos, buf, bufsize); - ret = _jsonb_escape(&pos, buf + b->pos, bufsize, str, len); + ret = _jsonb_escape(&pos, buf + b->pos, bufsize - b->pos, str, len); if (ret != JSONB_OK) return ret; BUFFER_COPY_CHAR(b, '"', pos, buf, bufsize); STACK_HEAD(b, next_state); diff --git a/test/test.c b/test/test.c index 268fe10..1781275 100644 --- a/test/test.c +++ b/test/test.c @@ -228,6 +228,27 @@ check_string_escaping(void) PASS(); } +TEST +check_string_escaping_bounds(void) +{ + const char str[] = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; + char buf[(sizeof("{}") - 1) + + 4 * ((sizeof("\"\"") - 1) + (sizeof(str) - 1))]; + jsonb b; + + jsonb_init(&b); + jsonb_object(&b, buf, sizeof(buf)); + ASSERT_EQm(buf, JSONB_OK, + jsonb_key(&b, buf, sizeof(buf), str, sizeof(str) - 1)); + ASSERT_EQm(buf, JSONB_OK, + jsonb_string(&b, buf, sizeof(buf), str, sizeof(str) - 1)); + ASSERT_EQm(buf, JSONB_ERROR_NOMEM, + jsonb_key(&b, buf, sizeof(buf), str, sizeof(str) - 1)); + fprintf(stderr, "%s", buf); + + PASS(); +} + TEST check_string_streaming(void) { @@ -307,6 +328,7 @@ check_string_streaming(void) SUITE(string) { RUN_TEST(check_string_escaping); + RUN_TEST(check_string_escaping_bounds); RUN_TEST(check_string_streaming); }