diff --git a/printbuf.c b/printbuf.c index f9964ad..30f4fe1 100644 --- a/printbuf.c +++ b/printbuf.c @@ -97,8 +97,6 @@ static int printbuf_extend(struct printbuf *p, int min_size) int printbuf_memappend(struct printbuf *p, const char *buf, int size) { - int buf_offset = -1; - /* Prevent signed integer overflows with large buffers. */ if (size < 0 || size > INT_MAX - p->bpos - 1) { @@ -107,6 +105,7 @@ int printbuf_memappend(struct printbuf *p, const char *buf, int size) } if (p->size <= p->bpos + size + 1) { + int buf_offset = -1; const uintptr_t buf_addr = (uintptr_t)(const void *)buf; const uintptr_t p_buf_addr = (uintptr_t)(const void *)p->buf; diff --git a/printbuf.h b/printbuf.h index 8dbf2c6..f5f6f88 100644 --- a/printbuf.h +++ b/printbuf.h @@ -52,6 +52,8 @@ JSON_EXPORT struct printbuf *printbuf_new(void); * * Your code should not use printbuf_memappend() directly unless it * checks the return code. Use printbuf_memappend_fast() instead. + * The source may point into p->buf, including a region that overlaps the + * appended destination. */ JSON_EXPORT int printbuf_memappend(struct printbuf *p, const char *buf, int size); @@ -112,6 +114,8 @@ JSON_EXPORT int printbuf_memset(struct printbuf *pb, int offset, int charvalue, * important than speed. Avoid using this function in high performance code or * tight loops; in these scenarios, consider using snprintf() with a static * buffer in conjunction with one of the printbuf_*append() functions. + * Format arguments may point into p->buf, including when appending the + * formatted result grows the buffer. * * See also: * printbuf_memappend_fast() diff --git a/tests/test_printbuf.c b/tests/test_printbuf.c index 1b57f52..3d56beb 100644 --- a/tests/test_printbuf.c +++ b/tests/test_printbuf.c @@ -154,6 +154,27 @@ static void test_printbuf_self_append(void) assert(pb->buf[i] == 'X'); assert(pb->buf[pb->bpos] == '\0'); + printbuf_free(pb); + + /* Formatted arguments may also point into a buffer that must grow. */ + pb = printbuf_new(); + assert(pb != NULL); + initial_size = pb->size; + data_size = initial_size - 2; + data = malloc(data_size); + assert(data != NULL); + memset(data, 'X', data_size); + assert(printbuf_memappend(pb, data, data_size) == data_size); + free(data); + assert(pb->size == initial_size); + + assert(sprintbuf(pb, "%s", pb->buf + 1) == data_size - 1); + assert(pb->size > initial_size); + assert(pb->bpos == data_size * 2 - 1); + for (i = 0; i < pb->bpos; i++) + assert(pb->buf[i] == 'X'); + assert(pb->buf[pb->bpos] == '\0'); + printbuf_free(pb); printf("%s: end test\n", __func__); }