cleanup: fix possible overflow errors in binary search

A common mistake when writing binary search is to allow possible integer overflow by using the simple average: mid = (min + max) / 2; Instead, use the overflow-safe version: mid = min + (max - min) / 2; This translation is safe since the operation occurs inside a loop conditioned on "min < max". The included changes were found using the following git grep: git grep '/ *2;' '*.c' Making this cleanup will prevent future review friction when a new binary search is contructed based on existing code. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Oct 8, 2017 at 14:29 UTC 19716b21a4255ecc7148b54ab2c78039c59f25bf
12 files changed +15 -15
builtin/index-pack.c
+2 -2
@@ -633,7 +633,7 @@ static int find_ofs_delta(const off_t offset, enum object_type type)
633 int first = 0, last = nr_ofs_deltas;
634
635 while (first < last) {
636 - int next = (first + last) / 2;
636 + int next = first + (last - first) / 2;
637 struct ofs_delta_entry *delta = &ofs_deltas[next];
638 int cmp;
639
@@ -687,7 +687,7 @@ static int find_ref_delta(const unsigned char *sha1, enum object_type type)
687 int first = 0, last = nr_ref_deltas;
688
689 while (first < last) {
690 - int next = (first + last) / 2;
690 + int next = first + (last - first) / 2;
691 struct ref_delta_entry *delta = &ref_deltas[next];
692 int cmp;
693
builtin/pack-objects.c
+1 -1
@@ -1277,7 +1277,7 @@ static int done_pbase_path_pos(unsigned hash)
1277 int lo = 0;
1278 int hi = done_pbase_paths_num;
1279 while (lo < hi) {
1280 - int mi = (hi + lo) / 2;
1280 + int mi = lo + (hi - lo) / 2;
1281 if (done_pbase_paths[mi] == hash)
1282 return mi;
1283 if (done_pbase_paths[mi] < hash)
builtin/unpack-objects.c
+1 -1
@@ -394,7 +394,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
394 lo = 0;
395 hi = nr;
396 while (lo < hi) {
397 - mid = (lo + hi)/2;
397 + mid = lo + (hi - lo) / 2;
398 if (base_offset < obj_list[mid].offset) {
399 hi = mid;
400 } else if (base_offset > obj_list[mid].offset) {
cache-tree.c
+1 -1
@@ -49,7 +49,7 @@ static int subtree_pos(struct cache_tree *it, const char *path, int pathlen)
49 lo = 0;
50 hi = it->subtree_nr;
51 while (lo < hi) {
52 - int mi = (lo + hi) / 2;
52 + int mi = lo + (hi - lo) / 2;
53 struct cache_tree_sub *mdl = down[mi];
54 int cmp = subtree_name_cmp(path, pathlen,
55 mdl->name, mdl->namelen);
compat/regex/regex_internal.c
+2 -2
@@ -613,7 +613,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags)
613 int low = 0, high = pstr->valid_len, mid;
614 do
615 {
616 - mid = (high + low) / 2;
616 + mid = low + (high - low) / 2;
617 if (pstr->offsets[mid] > offset)
618 high = mid;
619 else if (pstr->offsets[mid] < offset)
@@ -1394,7 +1394,7 @@ re_node_set_contains (const re_node_set *set, int elem)
1394 right = set->nelem - 1;
1395 while (idx < right)
1396 {
1397 - mid = (idx + right) / 2;
1397 + mid = idx + (right - idx) / 2;
1398 if (set->elems[mid] < elem)
1399 idx = mid + 1;
1400 else
compat/regex/regexec.c
+1 -1
@@ -4284,7 +4284,7 @@ search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
4284 last = right = mctx->nbkref_ents;
4285 for (left = 0; left < right;)
4286 {
4287 - mid = (left + right) / 2;
4287 + mid = left + (right - left) / 2;
4288 if (mctx->bkref_ents[mid].str_idx < str_idx)
4289 left = mid + 1;
4290 else
packfile.c
+1 -1
@@ -1743,7 +1743,7 @@ off_t find_pack_entry_one(const unsigned char *sha1,
1743 sha1[0], sha1[1], sha1[2], lo, hi, p->num_objects);
1744
1745 while (lo < hi) {
1746 - unsigned mi = (lo + hi) / 2;
1746 + unsigned mi = lo + (hi - lo) / 2;
1747 int cmp = hashcmp(index + mi * stride, sha1);
1748
1749 if (debug_lookup)
sha1-lookup.c
+2 -2
@@ -10,7 +10,7 @@ static uint32_t take2(const unsigned char *sha1)
10 * Conventional binary search loop looks like this:
11 *
12 * do {
13 - * int mi = (lo + hi) / 2;
13 + * int mi = lo + (hi - lo) / 2;
14 * int cmp = "entry pointed at by mi" minus "target";
15 * if (!cmp)
16 * return (mi is the wanted one)
@@ -95,7 +95,7 @@ int sha1_pos(const unsigned char *sha1, void *table, size_t nr,
95 hi = mi;
96 else
97 lo = mi + 1;
98 - mi = (hi + lo) / 2;
98 + mi = lo + (hi - lo) / 2;
99 } while (lo < hi);
100 return -lo-1;
101 }
sha1_name.c
+1 -1
@@ -157,7 +157,7 @@ static void unique_in_pack(struct packed_git *p,
157 num = p->num_objects;
158 last = num;
159 while (first < last) {
160 - uint32_t mid = (first + last) / 2;
160 + uint32_t mid = first + (last - first) / 2;
161 const unsigned char *current;
162 int cmp;
163
string-list.c
+1 -1
@@ -16,7 +16,7 @@ static int get_entry_index(const struct string_list *list, const char *string,
16 compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;
17
18 while (left + 1 < right) {
19 - int middle = (left + right) / 2;
19 + int middle = left + (right - left) / 2;
20 int compare = cmp(string, list->items[middle].string);
21 if (compare < 0)
22 right = middle;
utf8.c
+1 -1
@@ -32,7 +32,7 @@ static int bisearch(ucs_char_t ucs, const struct interval *table, int max)
32 if (ucs < table[0].first || ucs > table[max].last)
33 return 0;
34 while (max >= min) {
35 - mid = (min + max) / 2;
35 + mid = min + (max - min) / 2;
36 if (ucs > table[mid].last)
37 min = mid + 1;
38 else if (ucs < table[mid].first)
xdiff/xpatience.c
+1 -1
@@ -166,7 +166,7 @@ static int binary_search(struct entry **sequence, int longest,
166 int left = -1, right = longest;
167
168 while (left + 1 < right) {
169 - int middle = (left + right) / 2;
169 + int middle = left + (right - left) / 2;
170 /* by construction, no two entries can be equal */
171 if (sequence[middle]->line2 > entry->line2)
172 right = middle;