summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Shawn O. Pearce <spearce@spearce.org>2006-12-24 00:47:23 -0500
committerLibravatar Junio C Hamano <junkio@cox.net>2006-12-29 11:36:45 -0800
commitc4712e4553f13d87d655325a57538f299402d457 (patch)
treed09717f9d9a811d36ae5572b131a5b40e1dfcdcf
parentRelease pack windows before reporting out of memory. (diff)
downloadtgif-c4712e4553f13d87d655325a57538f299402d457.tar.xz
Replace mmap with xmmap, better handling MAP_FAILED.
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>
-rw-r--r--config.c2
-rw-r--r--diff.c4
-rw-r--r--git-compat-util.h13
-rw-r--r--read-cache.c2
-rw-r--r--refs.c2
-rw-r--r--sha1_file.c18
6 files changed, 22 insertions, 19 deletions
diff --git a/config.c b/config.c
index 3b8da569fa..2e0d5a8681 100644
--- 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 f14288bb8a..244292a70c 100644
--- 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 {
diff --git a/git-compat-util.h b/git-compat-util.h
index 0f856747e5..f243b86d32 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -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;
diff --git a/read-cache.c b/read-cache.c
index b8d83ccd9f..ca3efbbf0b 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -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 e88ed8b2d3..121774cb32 100644
--- 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;
diff --git a/sha1_file.c b/sha1_file.c
index fb1032b0fd..84037fe98f 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -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;