Subject: [PATCH 5/7] Introduce malloc/strdup/pathdup variants for permanent allocations

From: Jonathan Nieder <[email-masked]>
Date: Sat, 2 Oct 2010 03:38:51 -0500

In git (option parsing and some other places), we sometimes leak tiny
bits of memory on purpose.  Introduce a way to declare such
allocations, to make the lives of people searching for real memory
leaks easier.

Currently these are thin wrappers around xmalloc and xstrdup.  The
KEEP_WRAPPER attribute avoids a tail call to ensure their stack frame
does not get replaced with the true xmalloc/xstrdup, so tools like
valgrind can easily distinguish them and know that the memory they
return is not meant to be freed.

In the long run it might be nice to tighten the semantics of these
functions and use memory from a large pool that is never freed (to
avoid fragmentation and save some allocation overhead).

Signed-off-by: Jonathan Nieder <[email-masked]>
---
 cache.h                 |    2 ++
 git-compat-util.h       |    2 ++
 path.c                  |   10 ++++++++++
 t/valgrind/default.supp |   17 +++++++++++++++++
 wrapper.c               |   14 ++++++++++++++
 5 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/cache.h b/cache.h
index 9ee61a2..bbf32ff 100644
--- a/cache.h
+++ b/cache.h
@@ -638,6 +638,8 @@ extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
 	__attribute__((format (printf, 3, 4)));
 extern char *git_pathdup(const char *fmt, ...)
 	__attribute__((format (printf, 1, 2)));
+extern char *git_pathdup_permanent(const char *fmt, ...)
+	__attribute__((format (printf, 1, 2)));
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
diff --git a/git-compat-util.h b/git-compat-util.h
index 81883e7..f00ee33 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -380,7 +380,9 @@ typedef void (*try_to_free_t)(size_t);
 extern try_to_free_t set_try_to_free_routine(try_to_free_t);
 
 extern char *xstrdup(const char *str);
+extern char *strdup_permanent(const char *str);
 extern void *xmalloc(size_t size);
+extern void *alloc_permanent(size_t size);
 extern void *xmallocz(size_t size);
 extern void *xmemdupz(const void *data, size_t len);
 extern char *xstrndup(const char *str, size_t len);
diff --git a/path.c b/path.c
index a2c9d1e..332c903 100644
--- a/path.c
+++ b/path.c
@@ -87,6 +87,16 @@ char *git_pathdup(const char *fmt, ...)
 	return xstrdup(path);
 }
 
+char *git_pathdup_permanent(const char *fmt, ...)
+{
+	char path[PATH_MAX];
+	va_list args;
+	va_start(args, fmt);
+	(void)git_vsnpath(path, sizeof(path), fmt, args);
+	va_end(args);
+	return strdup_permanent(path);
+}
+
 char *mkpath(const char *fmt, ...)
 {
 	va_list args;
diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp
index 7789edd..d237210 100644
--- a/t/valgrind/default.supp
+++ b/t/valgrind/default.supp
@@ -45,6 +45,23 @@
 }
 
 {
+	leaky malloc for option parsing and configuration
+	Memcheck:Leak
+	fun:malloc
+	fun:xmalloc
+	fun:alloc_permanent
+}
+
+{
+	leaky strdup for option parsing and configuration
+	Memcheck:Leak
+	fun:malloc
+	fun:strdup
+	fun:xstrdup
+	fun:strdup_permanent
+}
+
+{
 	see api-lockfile.txt
 	Memcheck:Leak
 	fun:calloc
diff --git a/wrapper.c b/wrapper.c
index fd8ead3..88ca3dd 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -3,6 +3,8 @@
  */
 #include "cache.h"
 
+#define KEEP_WRAPPER __attribute__((optimize("-fno-optimize-sibling-calls")))
+
 static void try_to_free_builtin(size_t size)
 {
 	release_pack_memory(size, -1);
@@ -17,6 +19,12 @@ try_to_free_t set_try_to_free_routine(try_to_free_t routine)
 	return old;
 }
 
+KEEP_WRAPPER
+char *strdup_permanent(const char *str)
+{
+	return xstrdup(str);
+}
+
 char *xstrdup(const char *str)
 {
 	char *ret = strdup(str);
@@ -29,6 +37,12 @@ char *xstrdup(const char *str)
 	return ret;
 }
 
+KEEP_WRAPPER
+void *alloc_permanent(size_t size)
+{
+	return xmalloc(size);
+}
+
 void *xmalloc(size_t size)
 {
 	void *ret = malloc(size);
-- 
1.7.2.3