Skip to content

Commit 6f3abb7

Browse files
committed
Merge branch 'jk/for-each-reflog-ent-reverse'
The code that reads the reflog from the newer to the older entries did not handle an entry that crosses a boundary of block it uses to read them correctly. * jk/for-each-reflog-ent-reverse: for_each_reflog_ent_reverse: turn leftover check into assertion for_each_reflog_ent_reverse: fix newlines on block boundaries
2 parents 12b9f08 + 69216bf commit 6f3abb7

2 files changed

Lines changed: 67 additions & 12 deletions

File tree

refs.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3413,29 +3413,54 @@ int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void
34133413

34143414
bp = find_beginning_of_line(buf, scanp);
34153415

3416-
if (*bp != '\n') {
3417-
strbuf_splice(&sb, 0, 0, buf, endp - buf);
3418-
if (pos)
3419-
break; /* need to fill another block */
3420-
scanp = buf - 1; /* leave loop */
3421-
} else {
3416+
if (*bp == '\n') {
34223417
/*
3423-
* (bp + 1) thru endp is the beginning of the
3424-
* current line we have in sb
3418+
* The newline is the end of the previous line,
3419+
* so we know we have complete line starting
3420+
* at (bp + 1). Prefix it onto any prior data
3421+
* we collected for the line and process it.
34253422
*/
34263423
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
34273424
scanp = bp;
34283425
endp = bp + 1;
3426+
ret = show_one_reflog_ent(&sb, fn, cb_data);
3427+
strbuf_reset(&sb);
3428+
if (ret)
3429+
break;
3430+
} else if (!pos) {
3431+
/*
3432+
* We are at the start of the buffer, and the
3433+
* start of the file; there is no previous
3434+
* line, and we have everything for this one.
3435+
* Process it, and we can end the loop.
3436+
*/
3437+
strbuf_splice(&sb, 0, 0, buf, endp - buf);
3438+
ret = show_one_reflog_ent(&sb, fn, cb_data);
3439+
strbuf_reset(&sb);
3440+
break;
34293441
}
3430-
ret = show_one_reflog_ent(&sb, fn, cb_data);
3431-
strbuf_reset(&sb);
3432-
if (ret)
3442+
3443+
if (bp == buf) {
3444+
/*
3445+
* We are at the start of the buffer, and there
3446+
* is more file to read backwards. Which means
3447+
* we are in the middle of a line. Note that we
3448+
* may get here even if *bp was a newline; that
3449+
* just means we are at the exact end of the
3450+
* previous line, rather than some spot in the
3451+
* middle.
3452+
*
3453+
* Save away what we have to be combined with
3454+
* the data from the next read.
3455+
*/
3456+
strbuf_splice(&sb, 0, 0, buf, endp - buf);
34333457
break;
3458+
}
34343459
}
34353460

34363461
}
34373462
if (!ret && sb.len)
3438-
ret = show_one_reflog_ent(&sb, fn, cb_data);
3463+
die("BUG: reverse reflog parser had leftover data");
34393464

34403465
fclose(logfp);
34413466
strbuf_release(&sb);

t/t1410-reflog.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,4 +287,34 @@ test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' '
287287
test_cmp expect actual
288288
'
289289

290+
# Triggering the bug detected by this test requires a newline to fall
291+
# exactly BUFSIZ-1 bytes from the end of the file. We don't know
292+
# what that value is, since it's platform dependent. However, if
293+
# we choose some value N, we also catch any D which divides N evenly
294+
# (since we will read backwards in chunks of D). So we choose 8K,
295+
# which catches glibc (with an 8K BUFSIZ) and *BSD (1K).
296+
#
297+
# Each line is 114 characters, so we need 75 to still have a few before the
298+
# last 8K. The 89-character padding on the final entry lines up our
299+
# newline exactly.
300+
test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' '
301+
git checkout -b reflogskip &&
302+
z38=00000000000000000000000000000000000000 &&
303+
ident="abc <xyz> 0000000001 +0000" &&
304+
for i in $(test_seq 1 75); do
305+
printf "$z38%02d $z38%02d %s\t" $i $(($i+1)) "$ident" &&
306+
if test $i = 75; then
307+
for j in $(test_seq 1 89); do
308+
printf X
309+
done
310+
else
311+
printf X
312+
fi &&
313+
printf "\n"
314+
done >.git/logs/refs/heads/reflogskip &&
315+
git rev-parse reflogskip@{73} >actual &&
316+
echo ${z38}03 >expect &&
317+
test_cmp expect actual
318+
'
319+
290320
test_done

0 commit comments

Comments
 (0)