mirror of
https://https.git.savannah.gnu.org/git/diffutils.git
synced 2026-01-27 01:44:20 +00:00
diff3: fix leaks, for real
* src/diff3.c (struct diff_block)[lint]: Add member, n2. (free_diff_block, next_to_n2): New functions. * tests/diff3: Add more test coverage.
This commit is contained in:
parent
b3def738f3
commit
edd942ca27
56
src/diff3.c
56
src/diff3.c
@ -78,6 +78,9 @@ struct diff_block {
|
||||
char **lines[2]; /* The actual lines (may contain nulls) */
|
||||
size_t *lengths[2]; /* Line lengths (including newlines, if any) */
|
||||
struct diff_block *next;
|
||||
#ifdef lint
|
||||
struct diff_block *n2; /* Used only when freeing. */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Three way diff */
|
||||
@ -176,7 +179,7 @@ static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);
|
||||
static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);
|
||||
static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);
|
||||
static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);
|
||||
static struct diff_block *process_diff (char const *, char const *, struct diff_block **);
|
||||
static struct diff_block *process_diff (char const *, char const *, struct diff_block **, char **);
|
||||
static void check_stdout (void);
|
||||
static void fatal (char const *) __attribute__((noreturn));
|
||||
static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);
|
||||
@ -212,6 +215,38 @@ static struct option const longopts[] =
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static void
|
||||
free_diff_block (struct diff_block *p)
|
||||
{
|
||||
#ifndef lint
|
||||
(void)p;
|
||||
#else
|
||||
while (p)
|
||||
{
|
||||
free (p->lines[0]);
|
||||
free (p->lines[1]);
|
||||
free (p->lengths[0]);
|
||||
free (p->lengths[1]);
|
||||
struct diff_block *next = p->n2;
|
||||
free (p);
|
||||
p = next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Copy each next pointer to n2, since make_3way_diff would clobber the former,
|
||||
yet we will still need something to free these buffers. */
|
||||
static void
|
||||
next_to_n2 (struct diff_block *p)
|
||||
{
|
||||
#ifndef lint
|
||||
(void)p;
|
||||
#else
|
||||
while (p)
|
||||
p = p->n2 = p->next;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@ -377,10 +412,19 @@ main (int argc, char **argv)
|
||||
/* Invoke diff twice on two pairs of input files, combine the two
|
||||
diffs, and output them. */
|
||||
|
||||
char *b0, *b1;
|
||||
commonname = file[rev_mapping[FILEC]];
|
||||
thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
|
||||
thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
|
||||
thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block, &b1);
|
||||
thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block, &b0);
|
||||
|
||||
next_to_n2 (thread0);
|
||||
next_to_n2 (thread1);
|
||||
|
||||
diff3 = make_3way_diff (thread0, thread1);
|
||||
|
||||
free_diff_block (thread0);
|
||||
free_diff_block (thread1);
|
||||
|
||||
if (edscript)
|
||||
conflicts_found
|
||||
= output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
|
||||
@ -400,6 +444,8 @@ main (int argc, char **argv)
|
||||
conflicts_found = false;
|
||||
}
|
||||
|
||||
free (b0);
|
||||
free (b1);
|
||||
check_stdout ();
|
||||
exit (conflicts_found);
|
||||
}
|
||||
@ -938,7 +984,8 @@ compare_line_list (char * const list1[], size_t const lengths1[],
|
||||
static struct diff_block *
|
||||
process_diff (char const *filea,
|
||||
char const *fileb,
|
||||
struct diff_block **last_block)
|
||||
struct diff_block **last_block,
|
||||
char **buf_to_free)
|
||||
{
|
||||
char *diff_contents;
|
||||
char *diff_limit;
|
||||
@ -953,6 +1000,7 @@ process_diff (char const *filea,
|
||||
sizeof *bptr->lengths[1]));
|
||||
|
||||
diff_limit = read_diff (filea, fileb, &diff_contents);
|
||||
*buf_to_free = diff_contents;
|
||||
scan_diff = diff_contents;
|
||||
|
||||
while (scan_diff < diff_limit)
|
||||
|
||||
66
tests/diff3
66
tests/diff3
@ -27,4 +27,70 @@ diff3 a a a > out 2> err || fail=1
|
||||
compare /dev/null out || fail=1
|
||||
compare /dev/null err || fail=1
|
||||
|
||||
# This would have provoked a nontrivial leak prior to diffutils-3.5,
|
||||
# due to the nontrivial list of diff_block structs.
|
||||
seq 10 40|sed 's/1$/x/' > d || framework_failure_
|
||||
seq 10 40|sed 's/5$/y/' > e || framework_failure_
|
||||
seq 10 40|sed 's/8$/z/' > f || framework_failure_
|
||||
cat <<'EOF' > exp40 || framework_failure_
|
||||
====1
|
||||
1:2c
|
||||
1x
|
||||
2:2c
|
||||
3:2c
|
||||
11
|
||||
====2
|
||||
1:6c
|
||||
3:6c
|
||||
15
|
||||
2:6c
|
||||
1y
|
||||
====3
|
||||
1:9c
|
||||
2:9c
|
||||
18
|
||||
3:9c
|
||||
1z
|
||||
====1
|
||||
1:12c
|
||||
2x
|
||||
2:12c
|
||||
3:12c
|
||||
21
|
||||
====2
|
||||
1:16c
|
||||
3:16c
|
||||
25
|
||||
2:16c
|
||||
2y
|
||||
====3
|
||||
1:19c
|
||||
2:19c
|
||||
28
|
||||
3:19c
|
||||
2z
|
||||
====1
|
||||
1:22c
|
||||
3x
|
||||
2:22c
|
||||
3:22c
|
||||
31
|
||||
====2
|
||||
1:26c
|
||||
3:26c
|
||||
35
|
||||
2:26c
|
||||
3y
|
||||
====3
|
||||
1:29c
|
||||
2:29c
|
||||
38
|
||||
3:29c
|
||||
3z
|
||||
EOF
|
||||
|
||||
diff3 d e f > out 2> err
|
||||
compare exp40 out || fail=1
|
||||
compare /dev/null err || fail=1
|
||||
|
||||
Exit $fail
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user