Commit 4b1018d24f980273528743c27c47ceb96cb720bd

Jeff Hostetler 2015-01-08T17:24:12

Fix crash in free() when git_buf_grow() fails.

diff --git a/src/buffer.c b/src/buffer.c
index 7744d8f..8013457 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -67,7 +67,8 @@ int git_buf_try_grow(
 
 	if (!new_ptr) {
 		if (mark_oom) {
-			if (buf->ptr) git__free(buf->ptr);
+			if (buf->ptr && (buf->ptr != git_buf__initbuf))
+				git__free(buf->ptr);
 			buf->ptr = git_buf__oom;
 		}
 		return -1;
diff --git a/tests/buf/oom.c b/tests/buf/oom.c
new file mode 100644
index 0000000..709439a
--- /dev/null
+++ b/tests/buf/oom.c
@@ -0,0 +1,31 @@
+#include "clar_libgit2.h"
+#include "buffer.h"
+
+#if defined(GIT_ARCH_64)
+#define TOOBIG 0xffffffffffffff00
+#else
+#define TOOBIG 0xffffff00
+#endif
+
+/**
+ * If we make a ridiculously large request the first time we
+ * actually allocate some space in the git_buf, the realloc()
+ * will fail.  And because the git_buf_grow() wrapper always
+ * sets mark_oom, the code in git_buf_try_grow() will free
+ * the internal buffer and set it to git_buf__oom.
+ * 
+ * We initialized the internal buffer to (the static variable)
+ * git_buf__initbuf.  The purpose of this test is to make sure
+ * that we don't try to free the static buffer.
+ */
+void test_buf_oom__grow(void)
+{
+	git_buf buf = GIT_BUF_INIT;
+
+	git_buf_clear(&buf);
+
+	cl_assert(git_buf_grow(&buf, TOOBIG) == -1);
+	cl_assert(git_buf_oom(&buf));
+
+	git_buf_free(&buf);
+}