Mercurial > hg
annotate mercurial/mpatch.c @ 39018:e793e11e1462
changegroup: introduce requests to define delta generation
Currently, we iterate through each revision we will be producing
a delta for then call into 1 of 2 functions for generating that
delta. Deltas are emitted as we iterate.
A problem with this model is that revision generation is tightly
coupled to the changegroup code. And the storage layer needs to
expose APIs like deltaparent() so changegroup delta generation
can produce a delta with that knowledge.
Another problem is that in this model, deltas can only be produced
sequentially after the previous delta was produced and emitted.
Some storage backends might be capable of producing deltas in
parallel (e.g. if the changegroup deltas are cached somewhere).
This commit aims to solve these problems by turning delta generation
into a 2 phase implementation where the first phase determines
info about all the deltas that need to be generated and the 2nd
phase resolves those deltas.
We introduce a "revisiondeltarequest" object that holds data about
a to-be-generated delta. We perform a full pass over all revisions
whose delta is to be generated and generate a "revisiondeltarequest"
for each. Then we iterate over the "revisiondeltarequest" instances
and derive a "revisiondelta" for each.
This patch was quite large. In order to avoid even more churn, aspects
of the implementation are less than ideal. e.g. we're recording
revision numbers instead of nodes in a few places and we don't
yet have a formal API for resolving an iterable of revisiondeltarequest
instances. Things will be improved in subsequent commits.
Unfortunately, this commit reduces performance substantially. For
`hg perfchangegroupchangelog` on my hg repo:
! wall 1.512607 comb 1.510000 user 1.490000 sys 0.020000 (best of 7)
! wall 2.150863 comb 2.150000 user 2.150000 sys 0.000000 (best of 5)
And for `hg bundle -t none-v2 -a` for the mozilla-unified repo:
178.32user 4.22system 3:02.59elapsed
190.97user 4.17system 3:15.19elapsed
Some of this was attributed to changelog slowdown. `hg
perfchangegroupchangelog` on mozilla-unified:
! wall 21.688715 comb 21.690000 user 21.570000 sys 0.120000 (best of 3)
! wall 25.683659 comb 25.680000 user 25.540000 sys 0.140000 (best of 3)
Profiling seems to reveal that the changelog slowdown is due to reading
changelog revisions multiple times. First in the linknode callback
to resolve the set of files changed. Second in the delta generation.
Before, we likely had hit the last revision cache in the revlog when
doing delta generation since we performed that immediately after
performing the linknode callback.
I'm not exactly sure where the other ~8s are being spent. It might be
from overhead of constructing a few million revisiondeltarequest
objects. I'm OK with the regression for now because it is in service
of a larger cause (storage abstraction). I'll try to profile later
and claw back the performance.
Differential Revision: https://phab.mercurial-scm.org/D4215
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 09 Aug 2018 09:28:26 -0700 |
parents | 9c5ced5276d6 |
children | 763b45bc4483 |
rev | line source |
---|---|
72 | 1 /* |
2 mpatch.c - efficient binary patching for Mercurial | |
3 | |
4 This implements a patch algorithm that's O(m + nlog n) where m is the | |
5 size of the output and n is the number of patches. | |
6 | |
7 Given a list of binary patches, it unpacks each into a hunk list, | |
8 then combines the hunk lists with a treewise recursion to form a | |
9 single hunk list. This hunk list is then applied to the original | |
10 text. | |
11 | |
12 The text (or binary) fragments are copied directly from their source | |
13 Python objects into a preallocated output string to avoid the | |
14 allocation of intermediate Python objects. Working memory is about 2x | |
15 the total number of hunks. | |
16 | |
2859 | 17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> |
72 | 18 |
19 This software may be used and distributed according to the terms | |
20 of the GNU General Public License, incorporated herein by reference. | |
21 */ | |
22 | |
38190
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
23 #include <limits.h> |
72 | 24 #include <stdlib.h> |
25 #include <string.h> | |
2468
1ac0574f1768
mac os x: fixes for 10.2 from chris monson <monpublic@gmail.com>
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2083
diff
changeset
|
26 |
29444
284d742e5611
internals: move the bitmanipulation routines into its own file
Maciej Fijalkowski <fijall@gmail.com>
parents:
28782
diff
changeset
|
27 #include "bitmanipulation.h" |
29691
e9a0bcc9314d
mpatch: change Py_ssize_t to ssize_t in places that will be later copied
Maciej Fijalkowski <fijall@gmail.com>
parents:
29444
diff
changeset
|
28 #include "compat.h" |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
29 #include "mpatch.h" |
72 | 30 |
38190
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
31 /* VC9 doesn't include bool and lacks stdbool.h based on cext/util.h */ |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
32 #if defined(_MSC_VER) || __STDC_VERSION__ < 199901L |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
33 #define true 1 |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
34 #define false 0 |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
35 typedef unsigned char bool; |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
36 #else |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
37 #include <stdbool.h> |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
38 #endif |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
39 |
29741
9a1685c70db4
mpatch: change lalloc() to local function
Yuya Nishihara <yuya@tcha.org>
parents:
29740
diff
changeset
|
40 static struct mpatch_flist *lalloc(ssize_t size) |
72 | 41 { |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
42 struct mpatch_flist *a = NULL; |
72 | 43 |
3138
cc856c4d91ca
mpatch: Fix for malloc corner case on AIX
Matt Mackall <mpm@selenic.com>
parents:
2859
diff
changeset
|
44 if (size < 1) |
cc856c4d91ca
mpatch: Fix for malloc corner case on AIX
Matt Mackall <mpm@selenic.com>
parents:
2859
diff
changeset
|
45 size = 1; |
cc856c4d91ca
mpatch: Fix for malloc corner case on AIX
Matt Mackall <mpm@selenic.com>
parents:
2859
diff
changeset
|
46 |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
47 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist)); |
128 | 48 if (a) { |
34633
347c0f4232e1
mpatch: re-wrap wide line with clang-format
Augie Fackler <augie@google.com>
parents:
29749
diff
changeset
|
49 a->base = (struct mpatch_frag *)malloc( |
347c0f4232e1
mpatch: re-wrap wide line with clang-format
Augie Fackler <augie@google.com>
parents:
29749
diff
changeset
|
50 sizeof(struct mpatch_frag) * size); |
2048
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
51 if (a->base) { |
128 | 52 a->head = a->tail = a->base; |
2048
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
53 return a; |
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
54 } |
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
55 free(a); |
128 | 56 } |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
57 return NULL; |
72 | 58 } |
59 | |
29693
b9b9f9a92481
mpatch: split mpatch into two files
Maciej Fijalkowski <fijall@gmail.com>
parents:
29692
diff
changeset
|
60 void mpatch_lfree(struct mpatch_flist *a) |
72 | 61 { |
128 | 62 if (a) { |
63 free(a->base); | |
64 free(a); | |
65 } | |
72 | 66 } |
67 | |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
68 static ssize_t lsize(struct mpatch_flist *a) |
72 | 69 { |
70 return a->tail - a->head; | |
71 } | |
72 | |
38190
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
73 /* add helper to add src and *dest iff it won't overflow */ |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
74 static inline bool safeadd(int src, int *dest) |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
75 { |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
76 if ((src > 0) == (*dest > 0)) { |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
77 if (*dest > 0) { |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
78 if (src > (INT_MAX - *dest)) { |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
79 return false; |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
80 } |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
81 } else { |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
82 if (src < (INT_MIN - *dest)) { |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
83 return false; |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
84 } |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
85 } |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
86 } |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
87 *dest += src; |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
88 return true; |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
89 } |
1ec4cb8cbc87
mpatch: introduce a safeadd() helper to work around UB int overflow
Augie Fackler <augie@google.com>
parents:
38189
diff
changeset
|
90 |
38191
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
91 /* subtract src from dest and store result in dest */ |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
92 static inline bool safesub(int src, int *dest) |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
93 { |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
94 if (((src > 0) && (*dest < INT_MIN + src)) || |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
95 ((src < 0) && (*dest > INT_MAX + src))) { |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
96 return false; |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
97 } |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
98 *dest -= src; |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
99 return true; |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
100 } |
b8b253aec953
mpatch: introduce a safesub() helper as well
Augie Fackler <augie@google.com>
parents:
38190
diff
changeset
|
101 |
72 | 102 /* move hunks in source that are less cut to dest, compensating |
103 for changes in offset. the last hunk may be split if necessary. | |
104 */ | |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
105 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut, |
34800
761355833867
mpatch: reformat function prototypes with clang-format
Augie Fackler <augie@google.com>
parents:
34634
diff
changeset
|
106 int offset) |
72 | 107 { |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
108 struct mpatch_frag *d = dest->tail, *s = src->head; |
72 | 109 int postend, c, l; |
110 | |
111 while (s != src->tail) { | |
38192
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
112 int soffset = s->start; |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
113 if (!safeadd(offset, &soffset)) |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
114 break; /* add would overflow, oh well */ |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
115 if (soffset >= cut) |
82 | 116 break; /* we've gone far enough */ |
72 | 117 |
38192
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
118 postend = offset; |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
119 if (!safeadd(s->start, &postend) || |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
120 !safeadd(s->len, &postend)) { |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
121 break; |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
122 } |
72 | 123 if (postend <= cut) { |
124 /* save this hunk */ | |
38192
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
125 int tmp = s->start; |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
126 if (!safesub(s->end, &tmp)) { |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
127 break; |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
128 } |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
129 if (!safeadd(s->len, &tmp)) { |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
130 break; |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
131 } |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
132 if (!safeadd(tmp, &offset)) { |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
133 break; /* add would overflow, oh well */ |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
134 } |
72 | 135 *d++ = *s++; |
34634
2e08b69bcd29
mpatch: reflow two oddly formatted else blocks with clang-format
Augie Fackler <augie@google.com>
parents:
34633
diff
changeset
|
136 } else { |
72 | 137 /* break up this hunk */ |
38192
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
138 c = cut; |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
139 if (!safesub(offset, &c)) { |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
140 break; |
0b208c13781c
mpatch: fix UB in int overflows in gather() (SEC)
Augie Fackler <augie@google.com>
parents:
38191
diff
changeset
|
141 } |
72 | 142 if (s->end < c) |
143 c = s->end; | |
144 l = cut - offset - s->start; | |
145 if (s->len < l) | |
146 l = s->len; | |
147 | |
148 offset += s->start + l - c; | |
149 | |
150 d->start = s->start; | |
151 d->end = c; | |
152 d->len = l; | |
153 d->data = s->data; | |
154 d++; | |
155 s->start = c; | |
156 s->len = s->len - l; | |
157 s->data = s->data + l; | |
158 | |
82 | 159 break; |
72 | 160 } |
161 } | |
162 | |
163 dest->tail = d; | |
164 src->head = s; | |
165 return offset; | |
166 } | |
167 | |
168 /* like gather, but with no output list */ | |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
169 static int discard(struct mpatch_flist *src, int cut, int offset) |
72 | 170 { |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
171 struct mpatch_frag *s = src->head; |
72 | 172 int postend, c, l; |
173 | |
174 while (s != src->tail) { | |
38193
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
175 int cmpcut = s->start; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
176 if (!safeadd(offset, &cmpcut)) { |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
177 break; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
178 } |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
179 if (cmpcut >= cut) |
82 | 180 break; |
72 | 181 |
38193
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
182 postend = offset; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
183 if (!safeadd(s->start, &postend)) { |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
184 break; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
185 } |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
186 if (!safeadd(s->len, &postend)) { |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
187 break; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
188 } |
72 | 189 if (postend <= cut) { |
38193
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
190 /* do the subtraction first to avoid UB integer overflow |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
191 */ |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
192 int tmp = s->start; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
193 if (!safesub(s->end, &tmp)) { |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
194 break; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
195 } |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
196 if (!safeadd(s->len, &tmp)) { |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
197 break; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
198 } |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
199 if (!safeadd(tmp, &offset)) { |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
200 break; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
201 } |
72 | 202 s++; |
34634
2e08b69bcd29
mpatch: reflow two oddly formatted else blocks with clang-format
Augie Fackler <augie@google.com>
parents:
34633
diff
changeset
|
203 } else { |
38193
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
204 c = cut; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
205 if (!safesub(offset, &c)) { |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
206 break; |
7f22ef3c0ee7
mpatch: fix UB integer overflows in discard() (SEC)
Augie Fackler <augie@google.com>
parents:
38192
diff
changeset
|
207 } |
72 | 208 if (s->end < c) |
209 c = s->end; | |
210 l = cut - offset - s->start; | |
211 if (s->len < l) | |
212 l = s->len; | |
213 | |
214 offset += s->start + l - c; | |
215 s->start = c; | |
216 s->len = s->len - l; | |
217 s->data = s->data + l; | |
218 | |
82 | 219 break; |
72 | 220 } |
221 } | |
222 | |
223 src->head = s; | |
224 return offset; | |
225 } | |
226 | |
227 /* combine hunk lists a and b, while adjusting b for offset changes in a/ | |
228 this deletes a and b and returns the resultant list. */ | |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
229 static struct mpatch_flist *combine(struct mpatch_flist *a, |
34800
761355833867
mpatch: reformat function prototypes with clang-format
Augie Fackler <augie@google.com>
parents:
34634
diff
changeset
|
230 struct mpatch_flist *b) |
72 | 231 { |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
232 struct mpatch_flist *c = NULL; |
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
233 struct mpatch_frag *bh, *ct; |
72 | 234 int offset = 0, post; |
235 | |
128 | 236 if (a && b) |
237 c = lalloc((lsize(a) + lsize(b)) * 2); | |
238 | |
239 if (c) { | |
72 | 240 |
128 | 241 for (bh = b->head; bh != b->tail; bh++) { |
242 /* save old hunks */ | |
243 offset = gather(c, a, bh->start, offset); | |
72 | 244 |
128 | 245 /* discard replaced hunks */ |
246 post = discard(a, bh->end, offset); | |
72 | 247 |
128 | 248 /* insert new hunk */ |
249 ct = c->tail; | |
38195
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
250 ct->start = bh->start; |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
251 ct->end = bh->end; |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
252 if (!safesub(offset, &(ct->start)) || |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
253 !safesub(post, &(ct->end))) { |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
254 /* It was already possible to exit |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
255 * this function with a return value |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
256 * of NULL before the safesub()s were |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
257 * added, so this should be fine. */ |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
258 mpatch_lfree(c); |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
259 c = NULL; |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
260 goto done; |
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
261 } |
128 | 262 ct->len = bh->len; |
263 ct->data = bh->data; | |
264 c->tail++; | |
265 offset = post; | |
266 } | |
267 | |
268 /* hold on to tail from a */ | |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
269 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a)); |
128 | 270 c->tail += lsize(a); |
72 | 271 } |
38195
9c5ced5276d6
mpatch: avoid integer overflow in combine() (SEC)
Augie Fackler <augie@google.com>
parents:
38194
diff
changeset
|
272 done: |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
273 mpatch_lfree(a); |
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
274 mpatch_lfree(b); |
72 | 275 return c; |
276 } | |
277 | |
278 /* decode a binary patch into a hunk list */ | |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
279 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res) |
72 | 280 { |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
281 struct mpatch_flist *l; |
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
282 struct mpatch_frag *lt; |
20167
09e41ac6289d
mpatch: rewrite pointer overflow checks
Matt Mackall <mpm@selenic.com>
parents:
16758
diff
changeset
|
283 int pos = 0; |
72 | 284 |
285 /* assume worst case size, we won't have many of these lists */ | |
28656
b6ed2505d6cf
parsers: fix list sizing rounding error (SEC)
Matt Mackall <mpm@selenic.com>
parents:
20167
diff
changeset
|
286 l = lalloc(len / 12 + 1); |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
287 if (!l) |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
288 return MPATCH_ERR_NO_MEM; |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
289 |
72 | 290 lt = l->tail; |
291 | |
38187
90a274965de7
mpatch: be more careful about parsing binary patch data (SEC)
Augie Fackler <augie@google.com>
parents:
34801
diff
changeset
|
292 /* We check against len-11 to ensure we have at least 12 bytes |
90a274965de7
mpatch: be more careful about parsing binary patch data (SEC)
Augie Fackler <augie@google.com>
parents:
34801
diff
changeset
|
293 left in the patch so we can read our three be32s out of it. */ |
90a274965de7
mpatch: be more careful about parsing binary patch data (SEC)
Augie Fackler <augie@google.com>
parents:
34801
diff
changeset
|
294 while (pos >= 0 && pos < (len - 11)) { |
20167
09e41ac6289d
mpatch: rewrite pointer overflow checks
Matt Mackall <mpm@selenic.com>
parents:
16758
diff
changeset
|
295 lt->start = getbe32(bin + pos); |
09e41ac6289d
mpatch: rewrite pointer overflow checks
Matt Mackall <mpm@selenic.com>
parents:
16758
diff
changeset
|
296 lt->end = getbe32(bin + pos + 4); |
09e41ac6289d
mpatch: rewrite pointer overflow checks
Matt Mackall <mpm@selenic.com>
parents:
16758
diff
changeset
|
297 lt->len = getbe32(bin + pos + 8); |
38194
59837a16896d
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler <augie@google.com>
parents:
38193
diff
changeset
|
298 if (lt->start < 0 || lt->start > lt->end || lt->len < 0) |
28657
b9714d958e89
parsers: detect short records (SEC)
Matt Mackall <mpm@selenic.com>
parents:
28656
diff
changeset
|
299 break; /* sanity check */ |
38194
59837a16896d
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler <augie@google.com>
parents:
38193
diff
changeset
|
300 if (!safeadd(12, &pos)) { |
59837a16896d
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler <augie@google.com>
parents:
38193
diff
changeset
|
301 break; |
59837a16896d
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler <augie@google.com>
parents:
38193
diff
changeset
|
302 } |
59837a16896d
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler <augie@google.com>
parents:
38193
diff
changeset
|
303 lt->data = bin + pos; |
59837a16896d
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler <augie@google.com>
parents:
38193
diff
changeset
|
304 if (!safeadd(lt->len, &pos)) { |
59837a16896d
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler <augie@google.com>
parents:
38193
diff
changeset
|
305 break; |
59837a16896d
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler <augie@google.com>
parents:
38193
diff
changeset
|
306 } |
72 | 307 lt++; |
308 } | |
309 | |
20167
09e41ac6289d
mpatch: rewrite pointer overflow checks
Matt Mackall <mpm@selenic.com>
parents:
16758
diff
changeset
|
310 if (pos != len) { |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
311 mpatch_lfree(l); |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
312 return MPATCH_ERR_CANNOT_BE_DECODED; |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
313 } |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
314 |
72 | 315 l->tail = lt; |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
316 *res = l; |
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
317 return 0; |
72 | 318 } |
319 | |
320 /* calculate the size of resultant text */ | |
29693
b9b9f9a92481
mpatch: split mpatch into two files
Maciej Fijalkowski <fijall@gmail.com>
parents:
29692
diff
changeset
|
321 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l) |
72 | 322 { |
29691
e9a0bcc9314d
mpatch: change Py_ssize_t to ssize_t in places that will be later copied
Maciej Fijalkowski <fijall@gmail.com>
parents:
29444
diff
changeset
|
323 ssize_t outlen = 0, last = 0; |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
324 struct mpatch_frag *f = l->head; |
72 | 325 |
326 while (f != l->tail) { | |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
327 if (f->start < last || f->end > len) { |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
328 return MPATCH_ERR_INVALID_PATCH; |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
329 } |
72 | 330 outlen += f->start - last; |
331 last = f->end; | |
332 outlen += f->len; | |
333 f++; | |
334 } | |
335 | |
336 outlen += len - last; | |
337 return outlen; | |
338 } | |
339 | |
29693
b9b9f9a92481
mpatch: split mpatch into two files
Maciej Fijalkowski <fijall@gmail.com>
parents:
29692
diff
changeset
|
340 int mpatch_apply(char *buf, const char *orig, ssize_t len, |
34800
761355833867
mpatch: reformat function prototypes with clang-format
Augie Fackler <augie@google.com>
parents:
34634
diff
changeset
|
341 struct mpatch_flist *l) |
72 | 342 { |
29692
6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
Maciej Fijalkowski <fijall@gmail.com>
parents:
29691
diff
changeset
|
343 struct mpatch_frag *f = l->head; |
72 | 344 int last = 0; |
345 char *p = buf; | |
346 | |
347 while (f != l->tail) { | |
38189
faa924469635
mpatch: ensure fragment start isn't past the end of orig (SEC)
Augie Fackler <augie@google.com>
parents:
38188
diff
changeset
|
348 if (f->start < last || f->start > len || f->end > len || |
faa924469635
mpatch: ensure fragment start isn't past the end of orig (SEC)
Augie Fackler <augie@google.com>
parents:
38188
diff
changeset
|
349 last < 0) { |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
350 return MPATCH_ERR_INVALID_PATCH; |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
351 } |
72 | 352 memcpy(p, orig + last, f->start - last); |
353 p += f->start - last; | |
354 memcpy(p, f->data, f->len); | |
355 last = f->end; | |
356 p += f->len; | |
357 f++; | |
358 } | |
38188
1acfc35d478c
mpatch: protect against underflow in mpatch_apply (SEC)
Augie Fackler <augie@google.com>
parents:
38187
diff
changeset
|
359 if (last < 0) { |
1acfc35d478c
mpatch: protect against underflow in mpatch_apply (SEC)
Augie Fackler <augie@google.com>
parents:
38187
diff
changeset
|
360 return MPATCH_ERR_INVALID_PATCH; |
1acfc35d478c
mpatch: protect against underflow in mpatch_apply (SEC)
Augie Fackler <augie@google.com>
parents:
38187
diff
changeset
|
361 } |
72 | 362 memcpy(p, orig + last, len - last); |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
363 return 0; |
72 | 364 } |
365 | |
366 /* recursively generate a patch of all bins between start and end */ | |
34800
761355833867
mpatch: reformat function prototypes with clang-format
Augie Fackler <augie@google.com>
parents:
34634
diff
changeset
|
367 struct mpatch_flist * |
761355833867
mpatch: reformat function prototypes with clang-format
Augie Fackler <augie@google.com>
parents:
34634
diff
changeset
|
368 mpatch_fold(void *bins, struct mpatch_flist *(*get_next_item)(void *, ssize_t), |
761355833867
mpatch: reformat function prototypes with clang-format
Augie Fackler <augie@google.com>
parents:
34634
diff
changeset
|
369 ssize_t start, ssize_t end) |
72 | 370 { |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
371 ssize_t len; |
72 | 372 |
373 if (start + 1 == end) { | |
374 /* trivial case, output a decoded list */ | |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
375 return get_next_item(bins, start); |
72 | 376 } |
377 | |
378 /* divide and conquer, memory management is elsewhere */ | |
379 len = (end - start) / 2; | |
29694
55dd12204b8e
mpatch: remove dependency on Python.h in mpatch.c
Maciej Fijalkowski <fijall@gmail.com>
parents:
29693
diff
changeset
|
380 return combine(mpatch_fold(bins, get_next_item, start, start + len), |
34801
1f4249c764f1
mpatch: switch alignment of wrapped line from tab to spaces with clang-format
Augie Fackler <augie@google.com>
parents:
34800
diff
changeset
|
381 mpatch_fold(bins, get_next_item, start + len, end)); |
72 | 382 } |