summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff King <peff@peff.net>2016-02-15 20:12:58 -0500
committerJunio C Hamano <gitster@pobox.com>2016-02-16 13:21:57 -0800
commit2b6a95e6250ff2abd8158e53b2a4e5e4996a8767 (patch)
tree5ece2dd5cb50c2162eb9471a4dd8d3631b37d226
parenta2558fb8e1e387b630312311e1d22c95663da5d0 (diff)
downloadgit-jk/merge-tree-merge-blobs.tar.gz
merge_blobs: use strbuf instead of manually-sized mmfile_tjk/merge-tree-merge-blobs
The ancient merge_blobs function (which is used nowhere except in the equally ancient git-merge-tree, which does not itself seem to be called by any modern git code), tries to create a plausible base object for an add/add conflict by finding the common parts of the "ours" and "theirs" blobs. It does so by calling xdiff with XDIFF_EMIT_COMMON, and stores the result in a buffer that is as big as the smaller of "ours" and "theirs". In theory, this is right; we cannot have more common content than is in the smaller of the two blobs. But in practice, xdiff may give us more: if neither file ends in a newline, we get the "\nNo newline at end of file" marker. This is somewhat of a bug in itself (the "no newline" string becomes part of the blob output!), but much worse is that we may overflow our output buffer with this string (if the common content was otherwise close to the size of the smaller blob). The minimal fix for the memory corruption is to size the buffer appropriately. We could do so by manually adding in an extra 29 bytes for the "no newline" string to our buffer size. But that's somewhat fragile. Instead, let's replace the fixed-size output buffer with a strbuf which can grow as necessary. Reported-by: Stefan Frühwirth <stefan.fruehwirth@uni-graz.at> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--merge-blobs.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/merge-blobs.c b/merge-blobs.c
index 7abb894c68..ca6ae2179f 100644
--- a/merge-blobs.c
+++ b/merge-blobs.c
@@ -51,19 +51,16 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our
static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf)
{
int i;
- mmfile_t *dst = priv_;
+ struct strbuf *dst = priv_;
- for (i = 0; i < nbuf; i++) {
- memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size);
- dst->size += mb[i].size;
- }
+ for (i = 0; i < nbuf; i++)
+ strbuf_add(dst, mb[i].ptr, mb[i].size);
return 0;
}
static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
{
- unsigned long size = f1->size < f2->size ? f1->size : f2->size;
- void *ptr = xmalloc(size);
+ struct strbuf out = STRBUF_INIT;
xpparam_t xpp;
xdemitconf_t xecfg;
xdemitcb_t ecb;
@@ -75,11 +72,15 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
xecfg.flags = XDL_EMIT_COMMON;
ecb.outf = common_outf;
- res->ptr = ptr;
- res->size = 0;
+ ecb.priv = &out;
+ if (xdi_diff(f1, f2, &xpp, &xecfg, &ecb) < 0) {
+ strbuf_release(&out);
+ return -1;
+ }
- ecb.priv = res;
- return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
+ res->size = out.len; /* avoid long/size_t pointer mismatch below */
+ res->ptr = strbuf_detach(&out, NULL);
+ return 0;
}
void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)