Skip to content

Commit 06f46f2

Browse files
peffgitster
authored andcommitted
avoid "write_in_full(fd, buf, len) != len" pattern
The return value of write_in_full() is either "-1", or the requested number of bytes[1]. If we make a partial write before seeing an error, we still return -1, not a partial value. This goes back to f6aa66c (write_in_full: really write in full or return error on disk full., 2007-01-11). So checking anything except "was the return value negative" is pointless. And there are a couple of reasons not to do so: 1. It can do a funny signed/unsigned comparison. If your "len" is signed (e.g., a size_t) then the compiler will promote the "-1" to its unsigned variant. This works out for "!= len" (unless you really were trying to write the maximum size_t bytes), but is a bug if you check "< len" (an example of which was fixed recently in config.c). We should avoid promoting the mental model that you need to check the length at all, so that new sites are not tempted to copy us. 2. Checking for a negative value is shorter to type, especially when the length is an expression. 3. Linus says so. In d34cf19 (Clean up write_in_full() users, 2007-01-11), right after the write_in_full() semantics were changed, he wrote: I really wish every "write_in_full()" user would just check against "<0" now, but this fixes the nasty and stupid ones. Appeals to authority aside, this makes it clear that writing it this way does not have an intentional benefit. It's a historical curiosity that we never bothered to clean up (and which was undoubtedly cargo-culted into new sites). So let's convert these obviously-correct cases (this includes write_str_in_full(), which is just a wrapper for write_in_full()). [1] A careful reader may notice there is one way that write_in_full() can return a different value. If we ask write() to write N bytes and get a return value that is _larger_ than N, we could return a larger total. But besides the fact that this would imply a totally broken version of write(), it would already invoke undefined behavior. Our internal remaining counter is an unsigned size_t, which means that subtracting too many byte will wrap it around to a very large number. So we'll instantly begin reading off the end of the buffer, trying to write gigabytes (or petabytes) of data. Signed-off-by: Jeff King <[email protected]> Reviewed-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 68a423a commit 06f46f2

16 files changed

+26
-27
lines changed

builtin/receive-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
742742
size_t n;
743743
if (feed(feed_state, &buf, &n))
744744
break;
745-
if (write_in_full(proc.in, buf, n) != n)
745+
if (write_in_full(proc.in, buf, n) < 0)
746746
break;
747747
}
748748
close(proc.in);

builtin/rerere.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
1818
{
1919
int i;
2020
for (i = 0; i < nbuf; i++)
21-
if (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size)
21+
if (write_in_full(1, ptr[i].ptr, ptr[i].size) < 0)
2222
return -1;
2323
return 0;
2424
}

builtin/unpack-file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ static char *create_temp_file(unsigned char *sha1)
1515

1616
xsnprintf(path, sizeof(path), ".merge_file_XXXXXX");
1717
fd = xmkstemp(path);
18-
if (write_in_full(fd, buf, size) != size)
18+
if (write_in_full(fd, buf, size) < 0)
1919
die_errno("unable to write temp-file");
2020
close(fd);
2121
return path;

config.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2565,7 +2565,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
25652565
copy_end - copy_begin) < 0)
25662566
goto write_err_out;
25672567
if (new_line &&
2568-
write_str_in_full(fd, "\n") != 1)
2568+
write_str_in_full(fd, "\n") < 0)
25692569
goto write_err_out;
25702570
}
25712571
copy_begin = store.offset[i];
@@ -2796,7 +2796,7 @@ int git_config_rename_section_in_file(const char *config_filename,
27962796
if (remove)
27972797
continue;
27982798
length = strlen(output);
2799-
if (write_in_full(out_fd, output, length) != length) {
2799+
if (write_in_full(out_fd, output, length) < 0) {
28002800
ret = write_error(get_lock_file_path(lock));
28012801
goto out;
28022802
}

diff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2975,7 +2975,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
29752975
blob = buf.buf;
29762976
size = buf.len;
29772977
}
2978-
if (write_in_full(fd, blob, size) != size)
2978+
if (write_in_full(fd, blob, size) < 0)
29792979
die_errno("unable to write temp-file");
29802980
close_tempfile(&temp->tempfile);
29812981
temp->name = get_tempfile_path(&temp->tempfile);

fast-import.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2951,7 +2951,7 @@ static void parse_reset_branch(const char *arg)
29512951

29522952
static void cat_blob_write(const char *buf, unsigned long size)
29532953
{
2954-
if (write_in_full(cat_blob_fd, buf, size) != size)
2954+
if (write_in_full(cat_blob_fd, buf, size) < 0)
29552955
die_errno("Write to frontend failed");
29562956
}
29572957

http-backend.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ static void inflate_request(const char *prog_name, int out, int buffer_input)
357357
die("zlib error inflating request, result %d", ret);
358358

359359
n = stream.total_out - cnt;
360-
if (write_in_full(out, out_buf, n) != n)
360+
if (write_in_full(out, out_buf, n) < 0)
361361
die("%s aborted reading request", prog_name);
362362
cnt += n;
363363

@@ -378,7 +378,7 @@ static void copy_request(const char *prog_name, int out)
378378
ssize_t n = read_request(0, &buf);
379379
if (n < 0)
380380
die_errno("error reading request body");
381-
if (write_in_full(out, buf, n) != n)
381+
if (write_in_full(out, buf, n) < 0)
382382
die("%s aborted reading request", prog_name);
383383
close(out);
384384
free(buf);

ll-merge.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ static void create_temp(mmfile_t *src, char *path, size_t len)
154154

155155
xsnprintf(path, len, ".merge_file_XXXXXX");
156156
fd = xmkstemp(path);
157-
if (write_in_full(fd, src->ptr, src->size) != src->size)
157+
if (write_in_full(fd, src->ptr, src->size) < 0)
158158
die_errno("unable to write temp-file");
159159
close(fd);
160160
}

read-cache.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,7 @@ static int ce_write_flush(git_SHA_CTX *context, int fd)
19211921
unsigned int buffered = write_buffer_len;
19221922
if (buffered) {
19231923
git_SHA1_Update(context, write_buffer, buffered);
1924-
if (write_in_full(fd, write_buffer, buffered) != buffered)
1924+
if (write_in_full(fd, write_buffer, buffered) < 0)
19251925
return -1;
19261926
write_buffer_len = 0;
19271927
}
@@ -1970,7 +1970,7 @@ static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
19701970

19711971
/* Flush first if not enough space for SHA1 signature */
19721972
if (left + 20 > WRITE_BUFFER_SIZE) {
1973-
if (write_in_full(fd, write_buffer, left) != left)
1973+
if (write_in_full(fd, write_buffer, left) < 0)
19741974
return -1;
19751975
left = 0;
19761976
}
@@ -1979,7 +1979,7 @@ static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
19791979
git_SHA1_Final(write_buffer + left, context);
19801980
hashcpy(sha1, write_buffer + left);
19811981
left += 20;
1982-
return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
1982+
return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
19831983
}
19841984

19851985
static void ce_smudge_racily_clean_entry(struct cache_entry *ce)

refs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
592592
}
593593
}
594594

595-
if (write_in_full(fd, buf.buf, buf.len) != buf.len) {
595+
if (write_in_full(fd, buf.buf, buf.len) < 0) {
596596
strbuf_addf(err, "could not write to '%s'", filename);
597597
rollback_lock_file(&lock);
598598
goto done;

0 commit comments

Comments
 (0)