Skip to content

Commit 4806c55

Browse files
pks-tgitster
authored andcommitted
apply: fix leaking string in match_fragment()
Before calling `update_pre_post_images()`, we call `strbuf_detach()` to put its buffer into a new string variable that we then pass to that function. Besides being rather pointless, it also causes us to leak memory of that variable because we never free it. Get rid of the variable altogether and instead reach into the `strbuf` directly. While at it, refactor the code to have a common exit path and mark string that do not contain allocated memory as constant. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1e5c160 commit 4806c55

File tree

2 files changed

+56
-32
lines changed

2 files changed

+56
-32
lines changed

apply.c

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2494,18 +2494,21 @@ static int match_fragment(struct apply_state *state,
24942494
int match_beginning, int match_end)
24952495
{
24962496
int i;
2497-
char *fixed_buf, *buf, *orig, *target;
2498-
struct strbuf fixed;
2499-
size_t fixed_len, postlen;
2497+
const char *orig, *target;
2498+
struct strbuf fixed = STRBUF_INIT;
2499+
size_t postlen;
25002500
int preimage_limit;
2501+
int ret;
25012502

25022503
if (preimage->nr + current_lno <= img->nr) {
25032504
/*
25042505
* The hunk falls within the boundaries of img.
25052506
*/
25062507
preimage_limit = preimage->nr;
2507-
if (match_end && (preimage->nr + current_lno != img->nr))
2508-
return 0;
2508+
if (match_end && (preimage->nr + current_lno != img->nr)) {
2509+
ret = 0;
2510+
goto out;
2511+
}
25092512
} else if (state->ws_error_action == correct_ws_error &&
25102513
(ws_rule & WS_BLANK_AT_EOF)) {
25112514
/*
@@ -2522,17 +2525,23 @@ static int match_fragment(struct apply_state *state,
25222525
* we are not removing blanks at the end, so we
25232526
* should reject the hunk at this position.
25242527
*/
2525-
return 0;
2528+
ret = 0;
2529+
goto out;
25262530
}
25272531

2528-
if (match_beginning && current_lno)
2529-
return 0;
2532+
if (match_beginning && current_lno) {
2533+
ret = 0;
2534+
goto out;
2535+
}
25302536

25312537
/* Quick hash check */
2532-
for (i = 0; i < preimage_limit; i++)
2538+
for (i = 0; i < preimage_limit; i++) {
25332539
if ((img->line[current_lno + i].flag & LINE_PATCHED) ||
2534-
(preimage->line[i].hash != img->line[current_lno + i].hash))
2535-
return 0;
2540+
(preimage->line[i].hash != img->line[current_lno + i].hash)) {
2541+
ret = 0;
2542+
goto out;
2543+
}
2544+
}
25362545

25372546
if (preimage_limit == preimage->nr) {
25382547
/*
@@ -2545,8 +2554,10 @@ static int match_fragment(struct apply_state *state,
25452554
if ((match_end
25462555
? (current + preimage->len == img->len)
25472556
: (current + preimage->len <= img->len)) &&
2548-
!memcmp(img->buf + current, preimage->buf, preimage->len))
2549-
return 1;
2557+
!memcmp(img->buf + current, preimage->buf, preimage->len)) {
2558+
ret = 1;
2559+
goto out;
2560+
}
25502561
} else {
25512562
/*
25522563
* The preimage extends beyond the end of img, so
@@ -2555,7 +2566,7 @@ static int match_fragment(struct apply_state *state,
25552566
* There must be one non-blank context line that match
25562567
* a line before the end of img.
25572568
*/
2558-
char *buf_end;
2569+
const char *buf, *buf_end;
25592570

25602571
buf = preimage->buf;
25612572
buf_end = buf;
@@ -2565,21 +2576,27 @@ static int match_fragment(struct apply_state *state,
25652576
for ( ; buf < buf_end; buf++)
25662577
if (!isspace(*buf))
25672578
break;
2568-
if (buf == buf_end)
2569-
return 0;
2579+
if (buf == buf_end) {
2580+
ret = 0;
2581+
goto out;
2582+
}
25702583
}
25712584

25722585
/*
25732586
* No exact match. If we are ignoring whitespace, run a line-by-line
25742587
* fuzzy matching. We collect all the line length information because
25752588
* we need it to adjust whitespace if we match.
25762589
*/
2577-
if (state->ws_ignore_action == ignore_ws_change)
2578-
return line_by_line_fuzzy_match(img, preimage, postimage,
2579-
current, current_lno, preimage_limit);
2590+
if (state->ws_ignore_action == ignore_ws_change) {
2591+
ret = line_by_line_fuzzy_match(img, preimage, postimage,
2592+
current, current_lno, preimage_limit);
2593+
goto out;
2594+
}
25802595

2581-
if (state->ws_error_action != correct_ws_error)
2582-
return 0;
2596+
if (state->ws_error_action != correct_ws_error) {
2597+
ret = 0;
2598+
goto out;
2599+
}
25832600

25842601
/*
25852602
* The hunk does not apply byte-by-byte, but the hash says
@@ -2608,7 +2625,7 @@ static int match_fragment(struct apply_state *state,
26082625
* but in this loop we will only handle the part of the
26092626
* preimage that falls within the file.
26102627
*/
2611-
strbuf_init(&fixed, preimage->len + 1);
2628+
strbuf_grow(&fixed, preimage->len + 1);
26122629
orig = preimage->buf;
26132630
target = img->buf + current;
26142631
for (i = 0; i < preimage_limit; i++) {
@@ -2644,8 +2661,10 @@ static int match_fragment(struct apply_state *state,
26442661
postlen += tgtfix.len;
26452662

26462663
strbuf_release(&tgtfix);
2647-
if (!match)
2648-
goto unmatch_exit;
2664+
if (!match) {
2665+
ret = 0;
2666+
goto out;
2667+
}
26492668

26502669
orig += oldlen;
26512670
target += tgtlen;
@@ -2666,9 +2685,13 @@ static int match_fragment(struct apply_state *state,
26662685
/* Try fixing the line in the preimage */
26672686
ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
26682687

2669-
for (j = fixstart; j < fixed.len; j++)
2670-
if (!isspace(fixed.buf[j]))
2671-
goto unmatch_exit;
2688+
for (j = fixstart; j < fixed.len; j++) {
2689+
if (!isspace(fixed.buf[j])) {
2690+
ret = 0;
2691+
goto out;
2692+
}
2693+
}
2694+
26722695

26732696
orig += oldlen;
26742697
}
@@ -2678,16 +2701,16 @@ static int match_fragment(struct apply_state *state,
26782701
* has whitespace breakages unfixed, and fixing them makes the
26792702
* hunk match. Update the context lines in the postimage.
26802703
*/
2681-
fixed_buf = strbuf_detach(&fixed, &fixed_len);
26822704
if (postlen < postimage->len)
26832705
postlen = 0;
26842706
update_pre_post_images(preimage, postimage,
2685-
fixed_buf, fixed_len, postlen);
2686-
return 1;
2707+
fixed.buf, fixed.len, postlen);
26872708

2688-
unmatch_exit:
2709+
ret = 1;
2710+
2711+
out:
26892712
strbuf_release(&fixed);
2690-
return 0;
2713+
return ret;
26912714
}
26922715

26932716
static int find_pos(struct apply_state *state,

t/t3417-rebase-whitespace-fix.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ test_description='git rebase --whitespace=fix
55
This test runs git rebase --whitespace=fix and make sure that it works.
66
'
77

8+
TEST_PASSES_SANITIZE_LEAK=true
89
. ./test-lib.sh
910

1011
# prepare initial revision of "file" with a blank line at the end

0 commit comments

Comments
 (0)