summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
authorLibravatar Jared Hance <jaredhance@gmail.com>2012-03-07 17:21:25 -0500
committerLibravatar Junio C Hamano <gitster@pobox.com>2012-03-07 14:56:08 -0800
commit6fe53908f954b5683ca08d3745be1d76dd665483 (patch)
treeecfb79acdac0385a6464d1c0ef9bcb314e4638bb /builtin
parentMerge branch 'maint-1.7.7' into maint-1.7.8 (diff)
downloadtgif-6fe53908f954b5683ca08d3745be1d76dd665483.tar.xz
apply: do not leak patches and fragments
In the while loop inside apply_patch, patch and fragments are dynamically allocated with a calloc. However, only unused patches are actually freed and the rest are left to leak. Since a list is actively built up consisting of the used patches, they can simply be iterated and freed at the end of the function. In addition, the text in fragments were not freed, primarily because they mostly point into a patch text that is freed as a whole. But there are some cases where new piece of memory is allocated and pointed by a fragment (namely, when handling a binary patch). Introduce a free_patch bitfield to mark each fragment if its text needs to be freed, and free patches, fragments and fragment text that need to be freed when we are done with the input. Signed-off-by: Jared Hance <jaredhance@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin')
-rw-r--r--builtin/apply.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/builtin/apply.c b/builtin/apply.c
index c24dc546d0..427c2634d7 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -152,8 +152,9 @@ struct fragment {
unsigned long oldpos, oldlines;
unsigned long newpos, newlines;
const char *patch;
+ unsigned free_patch:1,
+ rejected:1;
int size;
- int rejected;
int linenr;
struct fragment *next;
};
@@ -195,6 +196,24 @@ struct patch {
struct patch *next;
};
+static void free_patch(struct patch *patch)
+{
+ while (patch) {
+ struct patch *patch_next = patch->next;
+ struct fragment *fragment = patch->fragments;
+
+ while (fragment) {
+ struct fragment *fragment_next = fragment->next;
+ if (fragment->patch != NULL && fragment->free_patch)
+ free((char *)fragment->patch);
+ free(fragment);
+ fragment = fragment_next;
+ }
+ free(patch);
+ patch = patch_next;
+ }
+}
+
/*
* A line in a file, len-bytes long (includes the terminating LF,
* except for an incomplete line at the end if the file ends with
@@ -1741,6 +1760,7 @@ static struct fragment *parse_binary_hunk(char **buf_p,
frag = xcalloc(1, sizeof(*frag));
frag->patch = inflate_it(data, hunk_size, origlen);
+ frag->free_patch = 1;
if (!frag->patch)
goto corrupt;
free(data);
@@ -3686,7 +3706,6 @@ static int apply_patch(int fd, const char *filename, int options)
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;
- /* FIXME - memory leak when using multiple patch files as inputs */
memset(&fn_table, 0, sizeof(struct string_list));
patch_input_file = filename;
read_patch_file(&buf, fd);
@@ -3711,8 +3730,7 @@ static int apply_patch(int fd, const char *filename, int options)
listp = &patch->next;
}
else {
- /* perhaps free it a bit better? */
- free(patch);
+ free_patch(patch);
skipped_patch++;
}
offset += nr;
@@ -3753,6 +3771,7 @@ static int apply_patch(int fd, const char *filename, int options)
if (summary)
summary_patch_list(list);
+ free_patch(list);
strbuf_release(&buf);
return 0;
}