Code

Merge branch 'jn/diffstat-tests'
[git.git] / wrapper.c
index 8d7dd31c4ba5439652d11e5ada06e0d52bc04e4f..6ccd0595f43d0ef62bd60a5863804f9a842a4235 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -9,6 +9,18 @@ static void do_nothing(size_t size)
 
 static void (*try_to_free_routine)(size_t size) = do_nothing;
 
+static void memory_limit_check(size_t size)
+{
+       static int limit = -1;
+       if (limit == -1) {
+               const char *env = getenv("GIT_ALLOC_LIMIT");
+               limit = env ? atoi(env) * 1024 : 0;
+       }
+       if (limit && size > limit)
+               die("attempting to allocate %"PRIuMAX" over limit %d",
+                   (intmax_t)size, limit);
+}
+
 try_to_free_t set_try_to_free_routine(try_to_free_t routine)
 {
        try_to_free_t old = try_to_free_routine;
@@ -32,7 +44,10 @@ char *xstrdup(const char *str)
 
 void *xmalloc(size_t size)
 {
-       void *ret = malloc(size);
+       void *ret;
+
+       memory_limit_check(size);
+       ret = malloc(size);
        if (!ret && !size)
                ret = malloc(1);
        if (!ret) {
@@ -53,7 +68,7 @@ void *xmalloc(size_t size)
 void *xmallocz(size_t size)
 {
        void *ret;
-       if (size + 1 < size)
+       if (unsigned_add_overflows(size, 1))
                die("Data too large to fit into virtual memory space.");
        ret = xmalloc(size + 1);
        ((char*)ret)[size] = 0;
@@ -79,7 +94,10 @@ char *xstrndup(const char *str, size_t len)
 
 void *xrealloc(void *ptr, size_t size)
 {
-       void *ret = realloc(ptr, size);
+       void *ret;
+
+       memory_limit_check(size);
+       ret = realloc(ptr, size);
        if (!ret && !size)
                ret = realloc(ptr, 1);
        if (!ret) {
@@ -95,7 +113,10 @@ void *xrealloc(void *ptr, size_t size)
 
 void *xcalloc(size_t nmemb, size_t size)
 {
-       void *ret = calloc(nmemb, size);
+       void *ret;
+
+       memory_limit_check(size * nmemb);
+       ret = calloc(nmemb, size);
        if (!ret && (!nmemb || !size))
                ret = calloc(1, 1);
        if (!ret) {
@@ -148,8 +169,10 @@ ssize_t read_in_full(int fd, void *buf, size_t count)
 
        while (count > 0) {
                ssize_t loaded = xread(fd, p, count);
-               if (loaded <= 0)
-                       return total ? total : loaded;
+               if (loaded < 0)
+                       return -1;
+               if (loaded == 0)
+                       return total;
                count -= loaded;
                p += loaded;
                total += loaded;
@@ -198,10 +221,22 @@ FILE *xfdopen(int fd, const char *mode)
 int xmkstemp(char *template)
 {
        int fd;
+       char origtemplate[PATH_MAX];
+       strlcpy(origtemplate, template, sizeof(origtemplate));
 
        fd = mkstemp(template);
-       if (fd < 0)
-               die_errno("Unable to create temporary file");
+       if (fd < 0) {
+               int saved_errno = errno;
+               const char *nonrelative_template;
+
+               if (!template[0])
+                       template = origtemplate;
+
+               nonrelative_template = absolute_path(template);
+               errno = saved_errno;
+               die_errno("Unable to create temporary file '%s'",
+                       nonrelative_template);
+       }
        return fd;
 }
 
@@ -321,10 +356,22 @@ int gitmkstemps(char *pattern, int suffix_len)
 int xmkstemp_mode(char *template, int mode)
 {
        int fd;
+       char origtemplate[PATH_MAX];
+       strlcpy(origtemplate, template, sizeof(origtemplate));
 
        fd = git_mkstemp_mode(template, mode);
-       if (fd < 0)
-               die_errno("Unable to create temporary file");
+       if (fd < 0) {
+               int saved_errno = errno;
+               const char *nonrelative_template;
+
+               if (!template[0])
+                       template = origtemplate;
+
+               nonrelative_template = absolute_path(template);
+               errno = saved_errno;
+               die_errno("Unable to create temporary file '%s'",
+                       nonrelative_template);
+       }
        return fd;
 }