mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-10-31 13:10:52 +00:00 
			
		
		
		
	Merge pull request #503 from arrbee/git-buf-always-cstr
Make git_buf functions always maintain a valid cstr
This commit is contained in:
		
						commit
						f5f0482658
					
				
							
								
								
									
										118
									
								
								src/buffer.c
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								src/buffer.c
									
									
									
									
									
								
							| @ -8,13 +8,29 @@ | ||||
| #include "posix.h" | ||||
| #include <stdarg.h> | ||||
| 
 | ||||
| /* Used as default value for git_buf->ptr so that people can always
 | ||||
|  * assume ptr is non-NULL and zero terminated even for new git_bufs. | ||||
|  */ | ||||
| char git_buf_initbuf[1]; | ||||
| 
 | ||||
| #define ENSURE_SIZE(b, d) \ | ||||
| 	if ((ssize_t)(d) > buf->asize && git_buf_grow(b, (d)) < GIT_SUCCESS)\ | ||||
| 		return; | ||||
| 
 | ||||
| void git_buf_init(git_buf *buf, size_t initial_size) | ||||
| { | ||||
| 	buf->asize = 0; | ||||
| 	buf->size = 0; | ||||
| 	buf->ptr = git_buf_initbuf; | ||||
| 
 | ||||
| 	if (initial_size) | ||||
| 		git_buf_grow(buf, initial_size); | ||||
| } | ||||
| 
 | ||||
| int git_buf_grow(git_buf *buf, size_t target_size) | ||||
| { | ||||
| 	char *new_ptr; | ||||
| 	size_t new_size; | ||||
| 
 | ||||
| 	if (buf->asize < 0) | ||||
| 		return GIT_ENOMEM; | ||||
| @ -22,27 +38,56 @@ int git_buf_grow(git_buf *buf, size_t target_size) | ||||
| 	if (target_size <= (size_t)buf->asize) | ||||
| 		return GIT_SUCCESS; | ||||
| 
 | ||||
| 	if (buf->asize == 0) | ||||
| 		buf->asize = target_size; | ||||
| 	if (buf->asize == 0) { | ||||
| 		new_size = target_size; | ||||
| 		new_ptr = NULL; | ||||
| 	} else { | ||||
| 		new_size = (size_t)buf->asize; | ||||
| 		new_ptr = buf->ptr; | ||||
| 	} | ||||
| 
 | ||||
| 	/* grow the buffer size by 1.5, until it's big enough
 | ||||
| 	 * to fit our target size */ | ||||
| 	while (buf->asize < (int)target_size) | ||||
| 		buf->asize = (buf->asize << 1) - (buf->asize >> 1); | ||||
| 	while (new_size < target_size) | ||||
| 		new_size = (new_size << 1) - (new_size >> 1); | ||||
| 
 | ||||
| 	/* round allocation up to multiple of 8 */ | ||||
| 	buf->asize = (buf->asize + 7) & ~7; | ||||
| 	new_size = (new_size + 7) & ~7; | ||||
| 
 | ||||
| 	new_ptr = git__realloc(buf->ptr, buf->asize); | ||||
| 	new_ptr = git__realloc(new_ptr, new_size); | ||||
| 	if (!new_ptr) { | ||||
| 		buf->asize = -1; | ||||
| 		return GIT_ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	buf->ptr = new_ptr; | ||||
| 	buf->asize = new_size; | ||||
| 	buf->ptr   = new_ptr; | ||||
| 
 | ||||
| 	/* truncate the existing buffer size if necessary */ | ||||
| 	if (buf->size >= buf->asize) | ||||
| 		buf->size = buf->asize - 1; | ||||
| 	buf->ptr[buf->size] = '\0'; | ||||
| 
 | ||||
| 	return GIT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| void git_buf_free(git_buf *buf) | ||||
| { | ||||
| 	if (!buf) return; | ||||
| 
 | ||||
| 	if (buf->ptr != git_buf_initbuf) | ||||
| 		git__free(buf->ptr); | ||||
| 
 | ||||
| 	git_buf_init(buf, 0); | ||||
| } | ||||
| 
 | ||||
| void git_buf_clear(git_buf *buf) | ||||
| { | ||||
| 	buf->size = 0; | ||||
| 	if (buf->asize > 0) | ||||
| 		buf->ptr[0] = '\0'; | ||||
| } | ||||
| 
 | ||||
| int git_buf_oom(const git_buf *buf) | ||||
| { | ||||
| 	return (buf->asize < 0); | ||||
| @ -53,9 +98,10 @@ void git_buf_set(git_buf *buf, const char *data, size_t len) | ||||
| 	if (len == 0 || data == NULL) { | ||||
| 		git_buf_clear(buf); | ||||
| 	} else { | ||||
| 		ENSURE_SIZE(buf, len); | ||||
| 		ENSURE_SIZE(buf, len + 1); | ||||
| 		memmove(buf->ptr, data, len); | ||||
| 		buf->size = len; | ||||
| 		buf->ptr[buf->size] = '\0'; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -66,15 +112,17 @@ void git_buf_sets(git_buf *buf, const char *string) | ||||
| 
 | ||||
| void git_buf_putc(git_buf *buf, char c) | ||||
| { | ||||
| 	ENSURE_SIZE(buf, buf->size + 1); | ||||
| 	ENSURE_SIZE(buf, buf->size + 2); | ||||
| 	buf->ptr[buf->size++] = c; | ||||
| 	buf->ptr[buf->size] = '\0'; | ||||
| } | ||||
| 
 | ||||
| void git_buf_put(git_buf *buf, const char *data, size_t len) | ||||
| { | ||||
| 	ENSURE_SIZE(buf, buf->size + len); | ||||
| 	ENSURE_SIZE(buf, buf->size + len + 1); | ||||
| 	memmove(buf->ptr + buf->size, data, len); | ||||
| 	buf->size += len; | ||||
| 	buf->ptr[buf->size] = '\0'; | ||||
| } | ||||
| 
 | ||||
| void git_buf_puts(git_buf *buf, const char *string) | ||||
| @ -111,27 +159,25 @@ void git_buf_printf(git_buf *buf, const char *format, ...) | ||||
| 
 | ||||
| const char *git_buf_cstr(git_buf *buf) | ||||
| { | ||||
| 	if (buf->size + 1 > buf->asize && | ||||
| 		git_buf_grow(buf, buf->size + 1) < GIT_SUCCESS) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	buf->ptr[buf->size] = '\0'; | ||||
| 	return buf->ptr; | ||||
| } | ||||
| 
 | ||||
| void git_buf_free(git_buf *buf) | ||||
| void git_buf_copy_cstr(char *data, size_t datasize, git_buf *buf) | ||||
| { | ||||
| 	if (!buf) return; | ||||
| 	size_t copylen; | ||||
| 
 | ||||
| 	git__free(buf->ptr); | ||||
| 	buf->ptr = NULL; | ||||
| 	buf->asize = 0; | ||||
| 	buf->size = 0; | ||||
| } | ||||
| 	assert(data && datasize); | ||||
| 
 | ||||
| void git_buf_clear(git_buf *buf) | ||||
| { | ||||
| 	buf->size = 0; | ||||
| 	data[0] = '\0'; | ||||
| 
 | ||||
| 	if (buf->size == 0 || buf->asize <= 0) | ||||
| 		return; | ||||
| 
 | ||||
| 	copylen = buf->size; | ||||
| 	if (copylen > datasize - 1) | ||||
| 		copylen = datasize - 1; | ||||
| 	memmove(data, buf->ptr, copylen); | ||||
| 	data[copylen] = '\0'; | ||||
| } | ||||
| 
 | ||||
| void git_buf_consume(git_buf *buf, const char *end) | ||||
| @ -140,6 +186,7 @@ void git_buf_consume(git_buf *buf, const char *end) | ||||
| 		size_t consumed = end - buf->ptr; | ||||
| 		memmove(buf->ptr, end, buf->size - consumed); | ||||
| 		buf->size -= consumed; | ||||
| 		buf->ptr[buf->size] = '\0'; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -152,21 +199,12 @@ void git_buf_swap(git_buf *buf_a, git_buf *buf_b) | ||||
| 
 | ||||
| char *git_buf_take_cstr(git_buf *buf) | ||||
| { | ||||
| 	char *data = NULL; | ||||
| 	char *data = buf->ptr; | ||||
| 
 | ||||
| 	if (buf->ptr == NULL) | ||||
| 	if (buf->asize <= 0) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (buf->size + 1 > buf->asize && | ||||
| 		git_buf_grow(buf, buf->size + 1) < GIT_SUCCESS) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	data = buf->ptr; | ||||
| 	data[buf->size] = '\0'; | ||||
| 
 | ||||
| 	buf->ptr = NULL; | ||||
| 	buf->asize = 0; | ||||
| 	buf->size = 0; | ||||
| 	git_buf_init(buf, 0); | ||||
| 
 | ||||
| 	return data; | ||||
| } | ||||
| @ -199,7 +237,7 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) | ||||
| 	} | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	ENSURE_SIZE(buf, buf->size + total_size); | ||||
| 	ENSURE_SIZE(buf, buf->size + total_size + 1); | ||||
| 
 | ||||
| 	out = buf->ptr + buf->size; | ||||
| 
 | ||||
| @ -235,6 +273,7 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) | ||||
| 
 | ||||
| 	/* set size based on num characters actually written */ | ||||
| 	buf->size = out - buf->ptr; | ||||
| 	buf->ptr[buf->size] = '\0'; | ||||
| } | ||||
| 
 | ||||
| void git_buf_join( | ||||
| @ -277,7 +316,7 @@ void git_buf_join( | ||||
| 
 | ||||
| 	if (!add_size) return; | ||||
| 
 | ||||
| 	ENSURE_SIZE(buf, buf->size + add_size); | ||||
| 	ENSURE_SIZE(buf, buf->size + add_size + 1); | ||||
| 
 | ||||
| 	/* concatenate strings */ | ||||
| 	ptr = buf->ptr + buf->size; | ||||
| @ -296,4 +335,5 @@ void git_buf_join( | ||||
| 
 | ||||
| 	/* set size based on num characters actually written */ | ||||
| 	buf->size = ptr - buf->ptr; | ||||
| 	buf->ptr[buf->size] = '\0'; | ||||
| } | ||||
|  | ||||
| @ -14,8 +14,11 @@ typedef struct { | ||||
| 	ssize_t asize, size; | ||||
| } git_buf; | ||||
| 
 | ||||
| #define GIT_BUF_INIT {NULL, 0, 0} | ||||
| extern char git_buf_initbuf[]; | ||||
| 
 | ||||
| #define GIT_BUF_INIT { git_buf_initbuf, 0, 0 } | ||||
| 
 | ||||
| void git_buf_init(git_buf *buf, size_t initial_size); | ||||
| int git_buf_grow(git_buf *buf, size_t target_size); | ||||
| void git_buf_free(git_buf *buf); | ||||
| void git_buf_swap(git_buf *buf_a, git_buf *buf_b); | ||||
| @ -42,6 +45,7 @@ void git_buf_join(git_buf *buf, char separator, const char *str_a, const char *s | ||||
| 
 | ||||
| const char *git_buf_cstr(git_buf *buf); | ||||
| char *git_buf_take_cstr(git_buf *buf); | ||||
| void git_buf_copy_cstr(char *data, size_t datasize, git_buf *buf); | ||||
| 
 | ||||
| #define git_buf_PUTS(buf, str) git_buf_put(buf, str, sizeof(str) - 1) | ||||
| 
 | ||||
|  | ||||
| @ -52,19 +52,19 @@ void test_core_buffer__2(void) | ||||
| { | ||||
| 	git_buf buf = GIT_BUF_INIT; | ||||
| 	int i; | ||||
| 	char data[100]; | ||||
| 
 | ||||
| 	cl_assert(buf.size == 0); | ||||
| 
 | ||||
| 	/* this must be safe to do */ | ||||
| 	git_buf_free(&buf); | ||||
| 
 | ||||
| 	cl_assert(buf.size == 0); | ||||
| 	cl_assert(buf.asize == 0); | ||||
| 
 | ||||
| 	/* empty buffer should be empty string */ | ||||
| 	cl_assert_strequal("", git_buf_cstr(&buf)); | ||||
| 	cl_assert(buf.size == 0); | ||||
| 	cl_assert(buf.asize > 0); | ||||
| 	/* cl_assert(buf.asize == 0); -- should not assume what git_buf does */ | ||||
| 
 | ||||
| 	/* free should set us back to the beginning */ | ||||
| 	git_buf_free(&buf); | ||||
| @ -130,6 +130,27 @@ void test_core_buffer__2(void) | ||||
| 	cl_assert_strequal("", git_buf_cstr(&buf)); | ||||
| 
 | ||||
| 	git_buf_free(&buf); | ||||
| 
 | ||||
| 	/* test extracting data into buffer */ | ||||
| 	git_buf_puts(&buf, REP4("0123456789")); | ||||
| 	cl_assert(git_buf_oom(&buf) == 0); | ||||
| 
 | ||||
| 	git_buf_copy_cstr(data, 100, &buf); | ||||
| 	cl_assert_strequal(data, REP4("0123456789")); | ||||
| 	git_buf_copy_cstr(data, 11, &buf); | ||||
| 	cl_assert_strequal(data, "0123456789"); | ||||
| 	git_buf_copy_cstr(data, 3, &buf); | ||||
| 	cl_assert_strequal(data, "01"); | ||||
| 	git_buf_copy_cstr(data, 1, &buf); | ||||
| 	cl_assert_strequal(data, ""); | ||||
| 
 | ||||
| 	git_buf_copy_cstr(data, 100, &buf); | ||||
| 	cl_assert_strequal(data, REP4("0123456789")); | ||||
| 
 | ||||
| 	git_buf_free(&buf); | ||||
| 
 | ||||
| 	git_buf_copy_cstr(data, 100, &buf); | ||||
| 	cl_assert_strequal(data, ""); | ||||
| } | ||||
| 
 | ||||
| /* let's do some tests with larger buffers to push our limits */ | ||||
| @ -203,10 +224,7 @@ check_buf_append( | ||||
| 	cl_assert(git_buf_oom(&tgt) == 0); | ||||
| 	git_buf_puts(&tgt, data_b); | ||||
| 	cl_assert(git_buf_oom(&tgt) == 0); | ||||
| 	if (expected_data == NULL) | ||||
| 		cl_assert(tgt.ptr == NULL); | ||||
| 	else | ||||
| 		cl_assert_strequal(expected_data, git_buf_cstr(&tgt)); | ||||
| 	cl_assert_strequal(expected_data, git_buf_cstr(&tgt)); | ||||
| 	cl_assert(tgt.size == expected_size); | ||||
| 	if (expected_asize > 0) | ||||
| 		cl_assert(tgt.asize == expected_asize); | ||||
| @ -277,15 +295,15 @@ void test_core_buffer__5(void) | ||||
| 	 */ | ||||
| 
 | ||||
| 	check_buf_append("abcdefgh", "/", "abcdefgh/", 9, 16); | ||||
| 	check_buf_append("abcdefgh", "ijklmno", "abcdefghijklmno", 15, 24); | ||||
| 	check_buf_append("abcdefgh", "ijklmno", "abcdefghijklmno", 15, 16); | ||||
| 	check_buf_append("abcdefgh", "ijklmnop", "abcdefghijklmnop", 16, 24); | ||||
| 	check_buf_append("0123456789", "0123456789", | ||||
| 					 "01234567890123456789", 20, 24); | ||||
| 	check_buf_append(REP16("x"), REP16("o"), | ||||
| 					 REP16("x") REP16("o"), 32, 40); | ||||
| 
 | ||||
| 	check_buf_append(test_4096, "", test_4096, 4096, 6144); | ||||
| 	check_buf_append(test_4096, test_4096, test_8192, 8192, 9216); | ||||
| 	check_buf_append(test_4096, "", test_4096, 4096, 4104); | ||||
| 	check_buf_append(test_4096, test_4096, test_8192, 8192, 9240); | ||||
| 
 | ||||
| 	/* check sequences of appends */ | ||||
| 	check_buf_append_abc("a", "b", "c", | ||||
| @ -335,13 +353,13 @@ void test_core_buffer__7(void) | ||||
| 	b = git_buf_take_cstr(&a); | ||||
| 
 | ||||
| 	cl_assert_strequal("foo", b); | ||||
| 	cl_assert_strequal(NULL, a.ptr); | ||||
| 	cl_assert_strequal("", a.ptr); | ||||
| 	git__free(b); | ||||
| 
 | ||||
| 	b = git_buf_take_cstr(&a); | ||||
| 
 | ||||
| 	cl_assert_strequal(NULL, b); | ||||
| 	cl_assert_strequal(NULL, a.ptr); | ||||
| 	cl_assert_strequal("", a.ptr); | ||||
| 
 | ||||
| 	git_buf_free(&a); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Vicent Martí
						Vicent Martí