From: Johannes Schindelin <johannes.schindelin@xxxxxx> When traversing commits and adjusting the ranges, things can get really tricky. For example, when the line range of interest encloses several hunks of a commit, the line range can actually shrink. Currently, range_set_shift_diff() does not anticipate that scenario and blindly adjusts start and end by the same offset ("shift" the range). This can lead to a couple of surprising issues, such as assertions in range_set_append() (when the end of a given range is not adjusted properly, it can point after the start of the next range) or even segmentation faults (when t_end in the loop of dump_diff_hacky_one() points outside the valid line range). Let's fix this by adjusting the start and the end offsets individually. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- line-log.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/line-log.c b/line-log.c index 72a5fed66..d8d09b5ee 100644 --- a/line-log.c +++ b/line-log.c @@ -427,7 +427,7 @@ static void range_set_shift_diff(struct range_set *out, struct diff_ranges *diff) { unsigned int i, j = 0; - long offset = 0; + long offset = 0, start_offset; struct range *src = rs->ranges; struct range *target = diff->target.ranges; struct range *parent = diff->parent.ranges; @@ -438,7 +438,13 @@ static void range_set_shift_diff(struct range_set *out, - (target[j].end-target[j].start); j++; } - range_set_append(out, src[i].start+offset, src[i].end+offset); + start_offset = offset; + while (j < diff->target.nr && src[i].end > target[j].end) { + offset += (parent[j].end-parent[j].start) + - (target[j].end-target[j].start); + j++; + } + range_set_append(out, src[i].start+start_offset, src[i].end+offset); } } -- gitgitgadget