Commit 34ef011
committed
diffcore-rename: fix BUG when break detection and --follow used together
Prior to commit 9db2ac5 (diffcore-rename: accelerate rename_dst
setup, 2020-12-11), the function add_rename_dst() resulted in quadratic
runtime since each call inserted the new entry into the array in sorted
order. The reason for the sorted order requirement was so that
locate_rename_dst(), used when break detection is turned on, could find
the appropriate entry in logarithmic time via bisection on string
comparisons. (It's better to be quadratic in moving pointers than
quadratic in string comparisons, so this made some sense.) However,
since break detection always sticks the broken pairs adjacent to each
other, that commit decided to simply append entries to rename_dst, and
record the mapping of (filename) -> (index within rename_dst) via a
strintmap. Doing this relied on the fact that when adding the source of
a broken pair via register_rename_src(), that the next item we'd process
was the other half of the same broken pair and would be added to
rename_dst via add_rename_dst(). This assumption was fine under break
detection alone, but the combination of break detection and
single_follow violated that assumption because of this code:
else if (options->single_follow &&
strcmp(options->single_follow, p->two->path))
continue; /* not interested */
which would end up skipping calling add_rename_dst() below that point.
Since I knew I was making this assumption, I added a new BUG() directive
in that commit that would check my assumptions held. That BUG() didn't
trip for nearly 4 years...which sadly meant I had long since forgotten
the related details. Anyway...
When the dst half of a broken pair is skipped like this, it means that
not only could my recorded index be invalid (just past the end of the
array), it could also point to some unrelated dst that just happened to
be the next one added to the array. So, to fix this, we need to add a
little more safety around the checks for the recorded break_idx.
It turns out that making a testcase to trigger this is a bit challenging
too. I added a simple testcase which tickles the necessary area, but
running it normally actually passes for me. However, running it under
valgrind shows that it is depending upon uninitialized memory. I
suspect that to get a reliable reproduction case, I might need to have
several more paths involved, but that might make the testcase more
difficult to understand. So, I instead just embedded a warning within
the testname that the test triggered uninitialized memory use.
In short, when these two rare options are used together, fix the
accidental find of the wrong dst entry (which would often be
uninitialized memory just past the end of the array), by adding a little
more care around the recorded indices for break_idx.
Reported-by: Olaf Hering <[email protected]>
Signed-off-by: Elijah Newren <[email protected]>1 parent f93ff17 commit 34ef011
2 files changed
+23
-4
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| |||
1668 | 1668 | | |
1669 | 1669 | | |
1670 | 1670 | | |
1671 | | - | |
1672 | | - | |
1673 | | - | |
| 1671 | + | |
| 1672 | + | |
| 1673 | + | |
| 1674 | + | |
1674 | 1675 | | |
1675 | 1676 | | |
1676 | 1677 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
57 | 75 | | |
0 commit comments