From 2e5b80929c96c9627f44c6a8d2b5796a93f27fba Mon Sep 17 00:00:00 2001 From: Patrick McCarty Date: Wed, 13 Jun 2018 18:46:43 -0700 Subject: [PATCH] Make revised search algorithm thread safe In commit 85b1c5345b, I introduced a new "max_len" variable, used by the search() function to store the maximum match length found in course of the binary search. However, I overlooked the fact that the search() function then lost thread safety, as "max_len" would be shared by all threads of a process using libbsdiff. Fix the issue by not using a global variable, instead updating "max_len" via another pointer, just like the "pos" variable is handled already. Signed-off-by: Patrick McCarty --- src/diff.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/diff.c b/src/diff.c index 01cf4d5..7d0fbc3 100644 --- a/src/diff.c +++ b/src/diff.c @@ -88,24 +88,23 @@ static int64_t matchlen(u_char *old, int64_t oldsize, u_char *new, return i; } -int64_t max_len = 0; - /** * Finds the longest matching array of bytes between the OLD and NEW file. The * old file is suffix-sorted; the suffix-sorted array is stored at I, and - * indices to search between are indicated by ST (start) and EN (end). Returns - * the length of the match, and POS is updated to the position of the match - * within OLD. + * indices to search between are indicated by ST (start) and EN (end). The + * function does not return a value, but once a match is determined, POS is + * updated to the position of the match within OLD, and MAX_LEN is set to the + * match length. */ -static int64_t search(int64_t *I, u_char *old, int64_t oldsize, - u_char *new, int64_t newsize, int64_t st, int64_t en, - int64_t *pos) +static void search(int64_t *I, u_char *old, int64_t oldsize, + u_char *new, int64_t newsize, int64_t st, int64_t en, + int64_t *pos, int64_t *max_len) { int64_t x, y; /* Initialize max_len for the binary search */ if (st == 0 && en == oldsize) { - max_len = matchlen(old, oldsize, new, newsize); + *max_len = matchlen(old, oldsize, new, newsize); *pos = I[st]; } @@ -113,17 +112,17 @@ static int64_t search(int64_t *I, u_char *old, int64_t oldsize, * indices in the suffix-sorted array. */ if (en - st < 2) { x = matchlen(old + I[st], oldsize - I[st], new, newsize); - if (x > max_len) { - max_len = x; + if (x > *max_len) { + *max_len = x; *pos = I[st]; } y = matchlen(old + I[en], oldsize - I[en], new, newsize); - if (y > max_len) { - max_len = y; + if (y > *max_len) { + *max_len = y; *pos = I[en]; } - return max_len; + return; } x = st + (en - st) / 2; @@ -133,16 +132,16 @@ static int64_t search(int64_t *I, u_char *old, int64_t oldsize, /* This match *could* be the longest one, so check for that here */ int64_t tmp = matchlen(oldoffset, length, new, length); - if (tmp > max_len) { - max_len = tmp; + if (tmp > *max_len) { + *max_len = tmp; *pos = I[x]; } /* Determine how to continue the binary search */ if (memcmp(oldoffset, new, length) < 0) { - return search(I, old, oldsize, new, newsize, x, en, pos); + return search(I, old, oldsize, new, newsize, x, en, pos, max_len); } else { - return search(I, old, oldsize, new, newsize, st, x, pos); + return search(I, old, oldsize, new, newsize, st, x, pos, max_len); } } @@ -617,9 +616,8 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena oldscore = 0; for (scsc = scan += len; scan < newsize; scan++) { - len = - search(I, old_data, oldsize, new_data + scan, newsize - scan, - 0, oldsize, &pos); + search(I, old_data, oldsize, new_data + scan, newsize - scan, + 0, oldsize, &pos, &len); for (; scsc < scan + len; scsc++) { if ((scsc + lastoffset < oldsize) &&