summaryrefslogtreecommitdiff
blob: fda8319c73c0e1e05ca21a743357f867538d384d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
From edd942ca27d570a33d612b12eecaa33a76640e46 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering@fb.com>
Date: Fri, 12 Aug 2016 21:40:29 -0700
Subject: diff3: fix leaks, for real

* src/diff3.c (struct diff_block)[lint]: Add member, n2.
(free_diff_block, next_to_n2): New functions.
---

diff --git a/src/diff3.c b/src/diff3.c
index 0eb643e..b80aeb3 100644
--- a/src/diff3.c
+++ b/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)
-- 
cgit v1.0