[PATCH 9/9] Cast 64 bit off_t to 32 bit size_t

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Some systems have sizeof(off_t) == 8 while sizeof(size_t) == 4.
This implies that we are able to access and work on files whose
maximum length is around 2^63-1 bytes, but we can only malloc or
mmap somewhat less than 2^32-1 bytes of memory.

On such a system an implicit conversion of off_t to size_t can cause
the size_t to wrap, resulting in unexpected and exciting behavior.
Right now we are working around all gcc warnings generated by the
-Wshorten-64-to-32 option by passing the off_t through xsize_t().

In the future we should make xsize_t on such problematic platforms
detect the wrapping and die if such a file is accessed.

Signed-off-by: Shawn O. Pearce <spearce@xxxxxxxxxxx>
---
 builtin-apply.c         |    2 +-
 builtin-blame.c         |    2 +-
 builtin-count-objects.c |    2 +-
 builtin-grep.c          |    9 ++++++---
 combine-diff.c          |    4 ++--
 config.c                |   28 +++++++++++++++-------------
 diff.c                  |    9 +++++----
 diffcore-break.c        |    2 +-
 diffcore-order.c        |    6 ++++--
 diffcore-rename.c       |    7 ++++---
 dir.c                   |    4 ++--
 git-compat-util.h       |    5 +++++
 read-cache.c            |    6 +++---
 refs.c                  |    8 +++++---
 sha1_file.c             |   40 +++++++++++++++++++++++-----------------
 xdiff-interface.c       |    8 +++++---
 16 files changed, 83 insertions(+), 59 deletions(-)

diff --git a/builtin-apply.c b/builtin-apply.c
index 5393510..dfa1716 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -1981,7 +1981,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
 		}
 	}
 	else if (patch->old_name) {
-		size = st->st_size;
+		size = xsize_t(st->st_size);
 		alloc = size + 8192;
 		buf = xmalloc(alloc);
 		if (read_old_data(st, patch->old_name, &buf, &alloc, &size))
diff --git a/builtin-blame.c b/builtin-blame.c
index 20966b9..b51cdc7 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1963,7 +1963,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
 				die("Cannot lstat %s", path);
 			read_from = path;
 		}
-		fin_size = st.st_size;
+		fin_size = xsize_t(st.st_size);
 		buf = xmalloc(fin_size+1);
 		mode = canon_mode(st.st_mode);
 		switch (st.st_mode & S_IFMT) {
diff --git a/builtin-count-objects.c b/builtin-count-objects.c
index f5b22bb..6263d8a 100644
--- a/builtin-count-objects.c
+++ b/builtin-count-objects.c
@@ -44,7 +44,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
 			if (lstat(path, &st) || !S_ISREG(st.st_mode))
 				bad = 1;
 			else
-				(*loose_size) += st.st_blocks;
+				(*loose_size) += xsize_t(st.st_blocks);
 		}
 		if (bad) {
 			if (verbose) {
diff --git a/builtin-grep.c b/builtin-grep.c
index e4f06f2..694da5b 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -122,6 +122,8 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 	struct stat st;
 	int i;
 	char *data;
+	size_t sz;
+
 	if (lstat(filename, &st) < 0) {
 	err_ret:
 		if (errno != ENOENT)
@@ -132,11 +134,12 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 		return 0; /* empty file -- no grep hit */
 	if (!S_ISREG(st.st_mode))
 		return 0;
+	sz = xsize_t(st.st_size);
 	i = open(filename, O_RDONLY);
 	if (i < 0)
 		goto err_ret;
-	data = xmalloc(st.st_size + 1);
-	if (st.st_size != read_in_full(i, data, st.st_size)) {
+	data = xmalloc(sz + 1);
+	if (st.st_size != read_in_full(i, data, sz)) {
 		error("'%s': short read %s", filename, strerror(errno));
 		close(i);
 		free(data);
@@ -145,7 +148,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 	close(i);
 	if (opt->relative && opt->prefix_length)
 		filename += opt->prefix_length;
-	i = grep_buffer(opt, filename, data, st.st_size);
+	i = grep_buffer(opt, filename, data, sz);
 	free(data);
 	return i;
 }
diff --git a/combine-diff.c b/combine-diff.c
index 6d928f2..3a9b32f 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -684,7 +684,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
 			goto deleted_file;
 
 		if (S_ISLNK(st.st_mode)) {
-			size_t len = st.st_size;
+			size_t len = xsize_t(st.st_size);
 			result_size = len;
 			result = xmalloc(len + 1);
 			if (result_size != readlink(elem->path, result, len)) {
@@ -697,7 +697,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
 		}
 		else if (0 <= (fd = open(elem->path, O_RDONLY)) &&
 			 !fstat(fd, &st)) {
-			size_t len = st.st_size;
+			size_t len = xsize_t(st.st_size);
 			size_t sz = 0;
 			int is_file, i;
 
diff --git a/config.c b/config.c
index 7ac3947..8fc4f11 100644
--- a/config.c
+++ b/config.c
@@ -431,7 +431,7 @@ static struct {
 	int do_not_match;
 	regex_t* value_regex;
 	int multi_replace;
-	off_t offset[MAX_MATCHES];
+	size_t offset[MAX_MATCHES];
 	enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
 	int seen;
 } store;
@@ -579,11 +579,11 @@ static int store_write_pair(int fd, const char* key, const char* value)
 	return 1;
 }
 
-static int find_beginning_of_line(const char* contents, int size,
-	int offset_, int* found_bracket)
+static ssize_t find_beginning_of_line(const char* contents, size_t size,
+	size_t offset_, int* found_bracket)
 {
-	int equal_offset = size, bracket_offset = size;
-	int offset;
+	size_t equal_offset = size, bracket_offset = size;
+	ssize_t offset;
 
 	for (offset = offset_-2; offset > 0 
 			&& contents[offset] != '\n'; offset--)
@@ -727,7 +727,8 @@ int git_config_set_multivar(const char* key, const char* value,
 	} else {
 		struct stat st;
 		char* contents;
-		int i, copy_begin, copy_end, new_line = 0;
+		size_t contents_sz, copy_begin, copy_end;
+		int i, new_line = 0;
 
 		if (value_regex == NULL)
 			store.value_regex = NULL;
@@ -784,7 +785,8 @@ int git_config_set_multivar(const char* key, const char* value,
 		}
 
 		fstat(in_fd, &st);
-		contents = xmmap(NULL, st.st_size, PROT_READ,
+		contents_sz = xsize_t(st.st_size);
+		contents = xmmap(NULL, contents_sz, PROT_READ,
 			MAP_PRIVATE, in_fd, 0);
 		close(in_fd);
 
@@ -793,12 +795,12 @@ int git_config_set_multivar(const char* key, const char* value,
 
 		for (i = 0, copy_begin = 0; i < store.seen; i++) {
 			if (store.offset[i] == 0) {
-				store.offset[i] = copy_end = st.st_size;
+				store.offset[i] = copy_end = contents_sz;
 			} else if (store.state != KEY_SEEN) {
 				copy_end = store.offset[i];
 			} else
 				copy_end = find_beginning_of_line(
-					contents, st.st_size,
+					contents, contents_sz,
 					store.offset[i]-2, &new_line);
 
 			/* write the first part of the config */
@@ -825,13 +827,13 @@ int git_config_set_multivar(const char* key, const char* value,
 		}
 
 		/* write the rest of the config */
-		if (copy_begin < st.st_size)
+		if (copy_begin < contents_sz)
 			if (write_in_full(fd, contents + copy_begin,
-					  st.st_size - copy_begin) <
-			    st.st_size - copy_begin)
+					  contents_sz - copy_begin) <
+			    contents_sz - copy_begin)
 				goto write_err_out;
 
-		munmap(contents, st.st_size);
+		munmap(contents, contents_sz);
 		unlink(config_filename);
 	}
 
diff --git a/diff.c b/diff.c
index e225de2..8f7a7d1 100644
--- a/diff.c
+++ b/diff.c
@@ -1399,7 +1399,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
 				return err;
 			}
 		}
-		s->size = st.st_size;
+		s->size = xsize_t(st.st_size);
 		if (!s->size)
 			goto empty;
 		if (size_only)
@@ -1515,12 +1515,13 @@ static void prepare_temp_file(const char *name,
 		if (S_ISLNK(st.st_mode)) {
 			int ret;
 			char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
+			size_t sz = xsize_t(st.st_size);
 			if (sizeof(buf) <= st.st_size)
 				die("symlink too long: %s", name);
-			ret = readlink(name, buf, st.st_size);
+			ret = readlink(name, buf, sz);
 			if (ret < 0)
 				die("readlink(%s)", name);
-			prep_temp_blob(temp, buf, st.st_size,
+			prep_temp_blob(temp, buf, sz,
 				       (one->sha1_valid ?
 					one->sha1 : null_sha1),
 				       (one->sha1_valid ?
@@ -2138,7 +2139,7 @@ static int parse_num(const char **cp_p)
 	/* user says num divided by scale and we say internally that
 	 * is MAX_SCORE * num / scale.
 	 */
-	return (num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale);
+	return (int)((num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale));
 }
 
 int diff_scoreopt_parse(const char *opt)
diff --git a/diffcore-break.c b/diffcore-break.c
index acb18db..9c19b8c 100644
--- a/diffcore-break.c
+++ b/diffcore-break.c
@@ -89,7 +89,7 @@ static int should_break(struct diff_filespec *src,
 	 * merge the surviving pair together if the score is
 	 * less than the minimum, after rename/copy runs.
 	 */
-	*merge_score_p = src_removed * MAX_SCORE / src->size;
+	*merge_score_p = (int)(src_removed * MAX_SCORE / src->size);
 
 	/* Extent of damage, which counts both inserts and
 	 * deletes.
diff --git a/diffcore-order.c b/diffcore-order.c
index 7ad0946..2a4bd82 100644
--- a/diffcore-order.c
+++ b/diffcore-order.c
@@ -14,6 +14,7 @@ static void prepare_order(const char *orderfile)
 	void *map;
 	char *cp, *endp;
 	struct stat st;
+	size_t sz;
 
 	if (order)
 		return;
@@ -25,11 +26,12 @@ static void prepare_order(const char *orderfile)
 		close(fd);
 		return;
 	}
-	map = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+	sz = xsize_t(st.st_size);
+	map = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
 	close(fd);
 	if (map == MAP_FAILED)
 		return;
-	endp = (char *) map + st.st_size;
+	endp = (char *) map + sz;
 	for (pass = 0; pass < 2; pass++) {
 		cnt = 0;
 		cp = map;
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 91fa2be..7903041 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -172,7 +172,8 @@ static int estimate_similarity(struct diff_filespec *src,
 		return 0; /* error but caught downstream */
 
 
-	delta_limit = base_size * (MAX_SCORE-minimum_score) / MAX_SCORE;
+	delta_limit = (unsigned long)
+		(base_size * (MAX_SCORE-minimum_score) / MAX_SCORE);
 	if (diffcore_count_changes(src->data, src->size,
 				   dst->data, dst->size,
 				   &src->cnt_data, &dst->cnt_data,
@@ -186,7 +187,7 @@ static int estimate_similarity(struct diff_filespec *src,
 	if (!dst->size)
 		score = 0; /* should not happen */
 	else
-		score = src_copied * MAX_SCORE / max_size;
+		score = (int)(src_copied * MAX_SCORE / max_size);
 	return score;
 }
 
@@ -297,7 +298,7 @@ void diffcore_rename(struct diff_options *options)
 				struct diff_filespec *one = rename_src[j].one;
 				if (!is_exact_match(one, two, contents_too))
 					continue;
-				record_rename_pair(i, j, MAX_SCORE);
+				record_rename_pair(i, j, (int)MAX_SCORE);
 				rename_count++;
 				break; /* we are done with this entry */
 			}
diff --git a/dir.c b/dir.c
index 32b57f0..b48e19d 100644
--- a/dir.c
+++ b/dir.c
@@ -130,13 +130,13 @@ static int add_excludes_from_file_1(const char *fname,
 {
 	struct stat st;
 	int fd, i;
-	long size;
+	size_t size;
 	char *buf, *entry;
 
 	fd = open(fname, O_RDONLY);
 	if (fd < 0 || fstat(fd, &st) < 0)
 		goto err;
-	size = st.st_size;
+	size = xsize_t(st.st_size);
 	if (size == 0) {
 		close(fd);
 		return 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 33b68e4..7534db1 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -258,6 +258,11 @@ static inline ssize_t xwrite(int fd, const void *buf, size_t len)
 	}
 }
 
+static inline size_t xsize_t(off_t len)
+{
+	return (size_t)len;
+}
+
 static inline int has_extension(const char *filename, const char *ext)
 {
 	size_t len = strlen(filename);
diff --git a/read-cache.c b/read-cache.c
index 4a972b4..6339a27 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -66,7 +66,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
 	return match;
 }
 
-static int ce_compare_link(struct cache_entry *ce, unsigned long expected_size)
+static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
 {
 	int match = -1;
 	char *target;
@@ -101,7 +101,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
 			return DATA_CHANGED;
 		break;
 	case S_IFLNK:
-		if (ce_compare_link(ce, st->st_size))
+		if (ce_compare_link(ce, xsize_t(st->st_size)))
 			return DATA_CHANGED;
 		break;
 	default:
@@ -797,7 +797,7 @@ int read_cache_from(const char *path)
 	}
 
 	if (!fstat(fd, &st)) {
-		cache_mmap_size = st.st_size;
+		cache_mmap_size = xsize_t(st.st_size);
 		errno = EINVAL;
 		if (cache_mmap_size >= sizeof(struct cache_header) + 20)
 			cache_mmap = xmmap(NULL, cache_mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
diff --git a/refs.c b/refs.c
index 7a1f89c..76c08d0 100644
--- a/refs.c
+++ b/refs.c
@@ -1075,6 +1075,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
 	unsigned long date;
 	unsigned char logged_sha1[20];
 	void *log_mapped;
+	size_t mapsz;
 
 	logfile = git_path("logs/%s", ref);
 	logfd = open(logfile, O_RDONLY, 0);
@@ -1083,7 +1084,8 @@ 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);
-	log_mapped = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, logfd, 0);
+	mapsz = xsize_t(st.st_size);
+	log_mapped = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, logfd, 0);
 	logdata = log_mapped;
 	close(logfd);
 
@@ -1136,7 +1138,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
 						logfile, show_rfc2822_date(date, tz));
 				}
 			}
-			munmap(log_mapped, st.st_size);
+			munmap(log_mapped, mapsz);
 			return 0;
 		}
 		lastrec = rec;
@@ -1155,7 +1157,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
 		die("Log %s is corrupt.", logfile);
 	if (msg)
 		*msg = ref_msg(logdata, logend);
-	munmap(log_mapped, st.st_size);
+	munmap(log_mapped, mapsz);
 
 	if (cutoff_time)
 		*cutoff_time = date;
diff --git a/sha1_file.c b/sha1_file.c
index 50d800e..219a10f 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -349,6 +349,7 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
 static void read_info_alternates(const char * relative_base, int depth)
 {
 	char *map;
+	size_t mapsz;
 	struct stat st;
 	char path[PATH_MAX];
 	int fd;
@@ -361,12 +362,13 @@ static void read_info_alternates(const char * relative_base, int depth)
 		close(fd);
 		return;
 	}
-	map = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	mapsz = xsize_t(st.st_size);
+	map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
 
-	link_alt_odb_entries(map, map + st.st_size, '\n', relative_base, depth);
+	link_alt_odb_entries(map, map + mapsz, '\n', relative_base, depth);
 
-	munmap(map, st.st_size);
+	munmap(map, mapsz);
 }
 
 void prepare_alt_odb(void)
@@ -436,7 +438,7 @@ static int check_packed_git_idx(const char *path,
 {
 	void *idx_map;
 	uint32_t *index;
-	unsigned long idx_size;
+	size_t idx_size;
 	uint32_t nr, i;
 	int fd = open(path, O_RDONLY);
 	struct stat st;
@@ -446,7 +448,7 @@ static int check_packed_git_idx(const char *path,
 		close(fd);
 		return -1;
 	}
-	idx_size = st.st_size;
+	idx_size = xsize_t(st.st_size);
 	if (idx_size < 4 * 256 + 20 + 20) {
 		close(fd);
 		return error("index file %s is too small", path);
@@ -669,11 +671,13 @@ unsigned char* use_pack(struct packed_git *p,
 		}
 		if (!win) {
 			size_t window_align = packed_git_window_size / 2;
+			off_t len;
 			win = xcalloc(1, sizeof(*win));
 			win->offset = (offset / window_align) * window_align;
-			win->len = p->pack_size - win->offset;
-			if (win->len > packed_git_window_size)
-				win->len = packed_git_window_size;
+			len = p->pack_size - win->offset;
+			if (len > packed_git_window_size)
+				len = packed_git_window_size;
+			win->len = (size_t)len;
 			pack_mapped += win->len;
 			while (packed_git_limit < pack_mapped
 				&& unuse_one_window(p))
@@ -702,7 +706,7 @@ unsigned char* use_pack(struct packed_git *p,
 	}
 	offset -= win->offset;
 	if (left)
-		*left = win->len - offset;
+		*left = win->len - xsize_t(offset);
 	return win->base + offset;
 }
 
@@ -878,9 +882,9 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
 		 */
 		sha1_file_open_flag = 0;
 	}
-	map = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	*size = xsize_t(st.st_size);
+	map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	*size = st.st_size;
 	return map;
 }
 
@@ -1346,7 +1350,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
 uint32_t num_packed_objects(const struct packed_git *p)
 {
 	/* See check_packed_git_idx() */
-	return (p->index_size - 20 - 20 - 4*256) / 24;
+	return (uint32_t)((p->index_size - 20 - 20 - 4*256) / 24);
 }
 
 int nth_packed_object_sha1(const struct packed_git *p, uint32_t n,
@@ -2068,7 +2072,7 @@ int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
 int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
 	     enum object_type type, const char *path)
 {
-	unsigned long size = st->st_size;
+	size_t size = xsize_t(st->st_size);
 	void *buf = NULL;
 	int ret, re_allocated = 0;
 
@@ -2111,6 +2115,7 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
 {
 	int fd;
 	char *target;
+	size_t len;
 
 	switch (st->st_mode & S_IFMT) {
 	case S_IFREG:
@@ -2123,16 +2128,17 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
 				     path);
 		break;
 	case S_IFLNK:
-		target = xmalloc(st->st_size+1);
-		if (readlink(path, target, st->st_size+1) != st->st_size) {
+		len = xsize_t(st->st_size);
+		target = xmalloc(len + 1);
+		if (readlink(path, target, len + 1) != st->st_size) {
 			char *errstr = strerror(errno);
 			free(target);
 			return error("readlink(\"%s\"): %s", path,
 			             errstr);
 		}
 		if (!write_object)
-			hash_sha1_file(target, st->st_size, blob_type, sha1);
-		else if (write_sha1_file(target, st->st_size, blob_type, sha1))
+			hash_sha1_file(target, len, blob_type, sha1);
+		else if (write_sha1_file(target, len, blob_type, sha1))
 			return error("%s: failed to insert into database",
 				     path);
 		free(target);
diff --git a/xdiff-interface.c b/xdiff-interface.c
index 6c1f99b..10816e9 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -107,16 +107,18 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
 {
 	struct stat st;
 	FILE *f;
+	size_t sz;
 
 	if (stat(filename, &st))
 		return error("Could not stat %s", filename);
 	if ((f = fopen(filename, "rb")) == NULL)
 		return error("Could not open %s", filename);
-	ptr->ptr = xmalloc(st.st_size);
-	if (fread(ptr->ptr, st.st_size, 1, f) != 1)
+	sz = xsize_t(st.st_size);
+	ptr->ptr = xmalloc(sz);
+	if (fread(ptr->ptr, sz, 1, f) != 1)
 		return error("Could not read %s", filename);
 	fclose(f);
-	ptr->size = st.st_size;
+	ptr->size = sz;
 	return 0;
 }
 
-- 
1.5.0.3.863.gf0989
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]