All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 9/9] Cast 64 bit off_t to 32 bit size_t
@ 2007-03-07  1:44 Shawn O. Pearce
  0 siblings, 0 replies; only message in thread
From: Shawn O. Pearce @ 2007-03-07  1:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

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@spearce.org>
---
 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

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2007-03-07  1:46 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-07  1:44 [PATCH 9/9] Cast 64 bit off_t to 32 bit size_t Shawn O. Pearce

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.