Replace mmap with xmmap, better handling MAP_FAILED.
authorShawn O. Pearce <spearce@spearce.org>
Sun, 24 Dec 2006 05:47:23 +0000 (00:47 -0500)
committerJunio C Hamano <junkio@cox.net>
Fri, 29 Dec 2006 19:36:45 +0000 (11:36 -0800)
In some cases we did not even bother to check the return value of
mmap() and just assume it worked.  This is bad, because if we are
out of virtual address space the kernel returned MAP_FAILED and we
would attempt to dereference that address, segfaulting without any
real error output to the user.

We are replacing all calls to mmap() with xmmap() and moving all
MAP_FAILED checking into that single location.  If a mmap call
fails we try to release enough least-recently-used pack windows
to possibly succeed, then retry the mmap() attempt.  If we cannot
mmap even after releasing pack memory then we die() as none of our
callers have any reasonable recovery strategy for a failed mmap.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
config.c
diff.c
git-compat-util.h
read-cache.c
refs.c
sha1_file.c

index 3b8da569fa72f88023cfab597d0ca9e42a051619..2e0d5a8681c1167b178a355782c90149adc42d9f 100644 (file)
--- a/config.c
+++ b/config.c
@@ -704,7 +704,7 @@ int git_config_set_multivar(const char* key, const char* value,
                }
 
                fstat(in_fd, &st);
-               contents = mmap(NULL, st.st_size, PROT_READ,
+               contents = xmmap(NULL, st.st_size, PROT_READ,
                        MAP_PRIVATE, in_fd, 0);
                close(in_fd);
 
diff --git a/diff.c b/diff.c
index f14288bb8a100c43c6709f658b9a9ca44832fd7f..244292a70c5b8a86d23905036c4103d3d0c1df1c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1341,10 +1341,8 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
                fd = open(s->path, O_RDONLY);
                if (fd < 0)
                        goto err_empty;
-               s->data = mmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
+               s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
                close(fd);
-               if (s->data == MAP_FAILED)
-                       goto err_empty;
                s->should_munmap = 1;
        }
        else {
index 0f856747e578f176dae1ab3ab900a64062fb9292..f243b86d3296579a130220ba5cde74ec954f429d 100644 (file)
@@ -188,6 +188,19 @@ static inline void *xcalloc(size_t nmemb, size_t size)
        return ret;
 }
 
+static inline void *xmmap(void *start, size_t length,
+       int prot, int flags, int fd, off_t offset)
+{
+       void *ret = mmap(start, length, prot, flags, fd, offset);
+       if (ret == MAP_FAILED) {
+               release_pack_memory(length);
+               ret = mmap(start, length, prot, flags, fd, offset);
+               if (ret == MAP_FAILED)
+                       die("Out of memory? mmap failed: %s", strerror(errno));
+       }
+       return ret;
+}
+
 static inline ssize_t xread(int fd, void *buf, size_t len)
 {
        ssize_t nr;
index b8d83ccd9f7985d60f69b7cd44db698d4e932612..ca3efbbf0bb61ba3eebe39f31266d6ba77f30eed 100644 (file)
@@ -798,7 +798,7 @@ int read_cache_from(const char *path)
                cache_mmap_size = st.st_size;
                errno = EINVAL;
                if (cache_mmap_size >= sizeof(struct cache_header) + 20)
-                       cache_mmap = mmap(NULL, cache_mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+                       cache_mmap = xmmap(NULL, cache_mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
        }
        close(fd);
        if (cache_mmap == MAP_FAILED)
diff --git a/refs.c b/refs.c
index e88ed8b2d3f42f48e6859de16f3d6a7f3641a84c..121774cb328a4d8a773a6a870c642a030bf3752d 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1026,7 +1026,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
        fstat(logfd, &st);
        if (!st.st_size)
                die("Log %s is empty.", logfile);
-       logdata = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, logfd, 0);
+       logdata = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, logfd, 0);
        close(logfd);
 
        lastrec = NULL;
index fb1032b0fdf9f778441c49664da4f5f6b5da57f5..84037fe98fa6ea0e4f1127c165786df51a34c5dd 100644 (file)
@@ -355,10 +355,8 @@ static void read_info_alternates(const char * relative_base, int depth)
                close(fd);
                return;
        }
-       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       map = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
-       if (map == MAP_FAILED)
-               return;
 
        link_alt_odb_entries(map, map + st.st_size, '\n', relative_base, depth);
 
@@ -442,10 +440,8 @@ static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
                return -1;
        }
        idx_size = st.st_size;
-       idx_map = mmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       idx_map = xmmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
-       if (idx_map == MAP_FAILED)
-               return -1;
 
        index = idx_map;
        *idx_map_ = idx_map;
@@ -630,7 +626,7 @@ unsigned char* use_pack(struct packed_git *p,
                        while (packed_git_limit < pack_mapped
                                && unuse_one_window(p))
                                ; /* nothing */
-                       win->base = mmap(NULL, win->len,
+                       win->base = xmmap(NULL, win->len,
                                PROT_READ, MAP_PRIVATE,
                                p->pack_fd, win->offset);
                        if (win->base == MAP_FAILED)
@@ -828,10 +824,8 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
                 */
                sha1_file_open_flag = 0;
        }
-       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       map = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
-       if (map == MAP_FAILED)
-               return NULL;
        *size = st.st_size;
        return map;
 }
@@ -1987,10 +1981,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, con
 
        buf = "";
        if (size)
-               buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+               buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
-       if (buf == MAP_FAILED)
-               return -1;
 
        if (!type)
                type = blob_type;