Jeff King wrote:
> AFAIK there's no way to turn it on for specific functions, but I'm far
> from a gcc-warning guru. Even if you could, though, the error may be far
> from the function (e.g., if we store the result in an ssize_t and then
> compare that with a size_t).
It turns out that yes, we have two of those. Both handle errors
separately already, so they should be safe.
While investigating the second, I noticed that read_in_full can
overflow its return value. malloc doesn't typically allow allocating
a buffer with size greater than SSIZE_MAX so this should be safe, but
it would be confusing to static analyzers.
Combining these observations yields the following (just for
illustration):
diff --git i/bulk-checkin.c w/bulk-checkin.c
index 9a1f6c49ab..f8e3060041 100644
--- i/bulk-checkin.c
+++ w/bulk-checkin.c
@@ -114,7 +114,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
unsigned char ibuf[16384];
if (size && !s.avail_in) {
- ssize_t rsize = size < sizeof(ibuf) ? size :
sizeof(ibuf);
+ size_t rsize = size < sizeof(ibuf) ? size :
sizeof(ibuf);
if (read_in_full(fd, ibuf, rsize) != rsize)
die("failed to read %d bytes from '%s'",
(int)rsize, path);
diff --git i/combine-diff.c w/combine-diff.c
index 9e163d5ada..e966d4f393 100644
--- i/combine-diff.c
+++ w/combine-diff.c
@@ -1026,7 +1026,7 @@ static void show_patch_diff(struct combine_diff_path
*elem, int num_parent,
result_size = fill_textconv(textconv, df, &result);
free_filespec(df);
} else if (0 <= (fd = open(elem->path, O_RDONLY))) {
- size_t len = xsize_t(st.st_size);
+ ssize_t len = xssize_t(st.st_size);
ssize_t done;
int is_file, i;
@@ -1040,6 +1040,8 @@ static void show_patch_diff(struct combine_diff_path
*elem, int num_parent,
if (!is_file)
elem->mode = canon_mode(S_IFLNK);
+ if (len > ULONG_MAX)
+ die("cannot handle files this big");
result_size = len;
result = xmallocz(len);
diff --git i/git-compat-util.h w/git-compat-util.h
index 6678b488cc..20fea81589 100644
--- i/git-compat-util.h
+++ w/git-compat-util.h
@@ -903,6 +903,13 @@ static inline size_t xsize_t(off_t len)
return (size_t)len;
}
+static inline ssize_t xssize_t(off_t len)
+{
+ if (len > SSIZE_MAX)
+ die("cannot handle files this big");
+ return (ssize_t)len;
+}
+
__attribute__((format (printf, 3, 4)))
extern int xsnprintf(char *dst, size_t max, const char *fmt, ...);
diff --git i/wrapper.c w/wrapper.c
index 36630e5d18..2b52b7367d 100644
--- i/wrapper.c
+++ w/wrapper.c
@@ -314,6 +314,9 @@ ssize_t read_in_full(int fd, void *buf, size_t count)
char *p = buf;
ssize_t total = 0;
+ if (count > SSIZE_MAX)
+ BUG("read_in_full called with absurdly high count %"PRIuMAX,
+ (uintmax_t) count);
while (count > 0) {
ssize_t loaded = xread(fd, p, count);
if (loaded < 0)