Skip to content
/ git Public
forked from git/git

Commit

Permalink
Cast 64 bit off_t to 32 bit size_t
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
spearce authored and Junio C Hamano committed Mar 7, 2007
1 parent 6777a59 commit dc49cd7
Show file tree
Hide file tree
Showing 16 changed files with 83 additions and 59 deletions.
2 changes: 1 addition & 1 deletion builtin-apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion builtin-blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion builtin-count-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
9 changes: 6 additions & 3 deletions builtin-grep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions combine-diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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;

Expand Down
28 changes: 15 additions & 13 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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--)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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 */
Expand All @@ -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);
}

Expand Down
9 changes: 5 additions & 4 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 ?
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion diffcore-break.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 4 additions & 2 deletions diffcore-order.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
7 changes: 4 additions & 3 deletions diffcore-rename.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
}

Expand Down Expand Up @@ -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 */
}
Expand Down
4 changes: 2 additions & 2 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions git-compat-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions read-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 5 additions & 3 deletions refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Loading

0 comments on commit dc49cd7

Please sign in to comment.