revision: fix memory leak in prepare_show_merge()
PATCH 1/1 revision: fix memory leak in prepare_show_merge()
From: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since parse_pathspec is not responsible to free prune, we should add free(prune) in the end of prepare_show_merge().
---
revision: fix memory leak in prepare_show_merge()
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since parse_pathspec is not responsible to free prune, we should add free(prune) in the end of prepare_show_merge().
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1989%2Fbrandb97%2Ffix-revision-leak-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1989/brandb97/fix-revision-leak-v1
Pull-Request: https://github.com/git/git/pull/1989
revision.c | 1 + 1 file changed, 1 insertion(+)
revision.c +1 -0
@@ -2060,6 +2060,7 @@ static void prepare_show_merge(struct rev_info *revs)parse_pathspec (&revs->prune_data,PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL ,PATHSPEC_PREFER_FULL |PATHSPEC_LITERAL_PATH ,"" , prune); revs->limited =1 ; +free (prune); } static int dotdot_missing(const char *arg, char *dotdot,
base-commit: 7014b55638da979331baf8dc31c4e1d697cf2d67
Signature · 1 line
gitgitgadget
Quoted 5 lines · Lidong Yan via GitGitGadget
From: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since
parse_pathspecis not responsible to free prune, we should addfree(prune)in the end ofprepare_show_merge().
That is a rather obvious memory leak indeed. Do you know why we never detected the leak in our CI? Is this code path not exercised at all by our tests?
Patrick
Quoted 8 lines · 2025年6月4日 15:48,Patrick Steinhardt <[email protected]> 写道:
Quoted 5 lines · Lidong Yan via GitGitGadget
From: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since
parse_pathspecis not responsible to free prune, we should addfree(prune)in the end ofprepare_show_merge().
Quoted 6 lines
That is a rather obvious memory leak indeed. Do you know why we never detected the leak in our CI? Is this code path not exercised at all by our tests?
Patrick
I don’t know why CI test doesn’t cover this leak, but I am happy to add a prereq test for this case.
p.s. I also like to ask that it there anyway to run test locally? How do you developers normally run test without open an pull request.
Thanks,
Lidong
Quoted 13 lines · lidongyan
Quoted 12 lines · 2025年6月4日 15:48,Patrick Steinhardt <[email protected]> 写道:
Quoted 5 lines · Lidong Yan via GitGitGadget
From: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since
parse_pathspecis not responsible to free prune, we should addfree(prune)in the end ofprepare_show_merge().That is a rather obvious memory leak indeed. Do you know why we never detected the leak in our CI? Is this code path not exercised at all by our tests?
Quoted 8 lines
Quoted 2 lines
Patrick
I don’t know why CI test doesn’t cover this leak, but I am happy to add a prereq test for this case.
p.s. I also like to ask that it there anyway to run test locally? How do you developers normally run test without open an pull request.
Do you mean the test suite in general or leak tests in particular? In any case, you can of course run both of these locally. You can do so either by using Make:
# Run tests.
$ make test
# Run tests with the leak checking enabled.
$ make test SANITIZE=leak
Or with Meson:
# Create the build directory and execute tests. $ meson setup build
$ meson test -C build
# Create a second build directory, this time with leak checking # enabled.
$ meson setup build-leaks -Db_sanitize=leak
$ meson test -C build-leaks
Patrick
Quoted 39 lines · 2025年6月4日 16:06,Patrick Steinhardt <[email protected]> 写道:
Quoted 13 lines · lidongyan
Quoted 12 lines · 2025年6月4日 15:48,Patrick Steinhardt <[email protected]> 写道:
Quoted 5 lines · Lidong Yan via GitGitGadget
From: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since
parse_pathspecis not responsible to free prune, we should addfree(prune)in the end ofprepare_show_merge().That is a rather obvious memory leak indeed. Do you know why we never detected the leak in our CI? Is this code path not exercised at all by our tests?
Quoted 8 lines
Quoted 2 lines
Patrick
I don’t know why CI test doesn’t cover this leak, but I am happy to add a prereq test for this case.
p.s. I also like to ask that it there anyway to run test locally? How do you developers normally run test without open an pull request.
Do you mean the test suite in general or leak tests in particular? In any case, you can of course run both of these locally. You can do so either by using Make:
# Run tests.
$ make test # Run tests with the leak checking enabled. $ make test SANITIZE=leakOr with Meson:
# Create the build directory and execute tests.
$ meson setup build $ meson test -C build
Quoted 6 lines
# Create a second build directory, this time with leak checking
# enabled. $ meson setup build-leaks -Db_sanitize=leak $ meson test -C build-leaksPatrick
Got it, thank you
Lidong
Quoted 10 lines · Patrick Steinhardt
Quoted 5 lines · Lidong Yan via GitGitGadget
From: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since
parse_pathspecis not responsible to free prune, we should addfree(prune)in the end ofprepare_show_merge().That is a rather obvious memory leak indeed. Do you know why we never detected the leak in our CI? Is this code path not exercised at all by our tests?
I think we have no "show --merge" test. Something like this may be minimally sufficient.
t/t7007-show.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
t/t7007-show.sh +15 -0
@@ -167,4 +167,19 @@ test_expect_success 'show --graph is forbidden' ' test_must_fail git show --graph HEAD ' +test_expect_success 'unmerged index' ' + git reset --hard && + git commit --allow-empty -m initial && + git rev-parse HEAD >.git/MERGE_HEAD && + blob1=$(echo hello | git hash-object -w --stdin) && + blob2=$(echo goodbye | git hash-object -w --stdin) && + blob3=$(echo world | git hash-object -w --stdin) && + git update-index --add --index-info <<-EOF && + 100644 $blob1 1 conflicting + 100644 $blob2 2 conflicting + 100755 $blob3 3 conflicting + EOF + git show --merge HEAD +' + test_done
Quoted 43 lines · 2025年6月6日 04:56,Junio C Hamano <[email protected]> 写道:
Quoted 10 lines · Patrick Steinhardt
Quoted 5 lines · Lidong Yan via GitGitGadget
From: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since
parse_pathspecis not responsible to free prune, we should addfree(prune)in the end ofprepare_show_merge().That is a rather obvious memory leak indeed. Do you know why we never detected the leak in our CI? Is this code path not exercised at all by our tests?
I think we have no "show --merge" test. Something like this may be minimally sufficient.
t/t7007-show.sh| 15 +++++++++++++++1 file changed, 15 insertions(+)t/t7007-show.sh +0
-0@@ -167,4 +167,19 @@ test_expect_success 'show --graph is forbidden' ' test_must_fail git show --graph HEAD'
t/t7007-show.sh +15
-0+test_expect_success 'unmerged index' ' + git reset --hard && + git commit --allow-empty -m initial && + git rev-parse HEAD >.git/MERGE_HEAD && + blob1=$(echo hello | git hash-object -w --stdin) && + blob2=$(echo goodbye | git hash-object -w --stdin) && + blob3=$(echo world | git hash-object -w --stdin) && + git update-index --add --index-info <<-EOF && + 100644 $blob1 1 conflicting + 100644 $blob2 2 conflicting + 100755 $blob3 3 conflicting + EOF + git show --merge HEAD +' +
Quoted 2 lines
test_done
I could add this test case into my patch. Though I don’t understand
Quoted 1 line
+ git rev-parse HEAD >.git/MERGE_HEAD &&
If HEAD is equal to MERGE_HEAD. Would git show —merge still works as usual? How about something like this
t/t7007-show.sh +24 -0
@@ -167,4 +167,28 @@ test_expect_success 'show --graph is forbidden' ' test_must_fail git show --graph HEAD ' +test_expect_success 'unmerged index' ' + git reset --hard && + + git switch -C base && + echo "base" > conflicting && + git add conflicting && + git commit -m "base" && + + git branch hello && + git branch goodbye && + + git switch hello && + echo "hello" > conflicting && + git commit -am "hello" && + + git switch goodbye && + echo "goodbye" > conflicting && + git commit -am "goodbye" && + + git switch hello && + test_must_fail git merge goodbye && + git show --merge HEAD +' + test_done
Quoted 2 lines · lidongyan
I could add this test case into my patch. Though I don’t understand
Quoted 1 line
+ git rev-parse HEAD >.git/MERGE_HEAD &&
That was not about telling "show --merge" to work on any meaningful data and to produce any useful output. I knew the step to prepare for "show --merge" was leaky, so I gave a very minimum that can tickle that codepath. I wasn't of course proud of the direct manipulation of the filesystem (as recent "git update-ref MERGE_HEAD HEAD" would not even allow us to do this, sheesh, not very convenient).
If you came up with a sequence that produces a situation to use the "git show --merge" command in a more realistic way, like below, that is wonderful.
Quoted 36 lines
If HEAD is equal to
MERGE_HEAD. Would git show —merge still works as usual? How about something like thist/t7007-show.sh +24
-0@@ -167,4 +167,28 @@ test_expect_success 'show --graph is forbidden' ' test_must_fail git show --graph HEAD ' +test_expect_success 'unmerged index' ' + git reset --hard && + + git switch -C base && + echo "base" > conflicting && + git add conflicting && + git commit -m "base" && + + git branch hello && + git branch goodbye && + + git switch hello && + echo "hello" > conflicting && + git commit -am "hello" && + + git switch goodbye && + echo "goodbye" > conflicting && + git commit -am "goodbye" && + + git switch hello && + test_must_fail git merge goodbye && + git show --merge HEAD +' + test_done
Quoted 4 lines · 2025年6月7日 00:47,Junio C Hamano <[email protected]> 写道:
Quoted 1 line · lidongyan
I could add this test case into my patch. Though I don’t understand
Quoted 8 lines
Quoted 1 line
Quoted 1 line
+ git rev-parse HEAD >.git/MERGE_HEAD &&
That was not about telling "show --merge" to work on any meaningful data and to produce any useful output. I knew the step to prepare for "show --merge" was leaky, so I gave a very minimum that can tickle that codepath. I wasn't of course proud of the direct manipulation of the filesystem (as recent "git update-ref
MERGE_HEADHEAD" would not even allow us to do this, sheesh, not very convenient).
I understand. show —merge means the codepath must go through prepare_show_merge() And update-index with index which has stage greater than 0 let prepare_show_merge() go through loop and add index to prune. Thus cause a leak.
Quoted 42 lines
If you came up with a sequence that produces a situation to use the "git show --merge" command in a more realistic way, like below, that is wonderful.
Quoted 36 lines
If HEAD is equal to
MERGE_HEAD. Would git show —merge still works as usual? How about something like thist/t7007-show.sh +0
-0@@ -167,4 +167,28 @@ test_expect_success 'show --graph is forbidden' ' test_must_fail git show --graph HEAD'
t/t7007-show.sh +24
-0+test_expect_success 'unmerged index' ' + git reset --hard && + + git switch -C base && + echo "base" > conflicting && + git add conflicting && + git commit -m "base" && + + git branch hello && + git branch goodbye && + + git switch hello && + echo "hello" > conflicting && + git commit -am "hello" && + + git switch goodbye && + echo "goodbye" > conflicting && + git commit -am "goodbye" && + + git switch hello && + test_must_fail git merge goodbye && + git show --merge HEAD +' +
test_done
PATCH v2 1/1 revision: fix memory leak in prepare_show_merge()
In reply to Lidong Yan via GitGitGadgetFrom: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since parse_pathspec is not responsible to free prune, we should add free(prune) in the end of prepare_show_merge().
---
revision: fix memory leak in prepare_show_merge()
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since parse_pathspec is not responsible to free prune, we should add free(prune) in the end of prepare_show_merge().
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1989%2Fbrandb97%2Ffix-revision-leak-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1989/brandb97/fix-revision-leak-v2
Pull-Request: https://github.com/git/git/pull/1989
Range-diff vs v1:
1: 5d213e2c11c ! 1: 61a2d98dad9 revision: fix memory leak in prepare_show_merge()
@@ revision.c: static void prepare_show_merge(struct rev_info *revs)
}
static int dotdot_missing(const char *arg, char *dotdot,
+
+ ## t/t7007-show.sh ##
+@@ t/t7007-show.sh: test_expect_success 'show --graph is forbidden' '
+ test_must_fail git show --graph HEAD
+ '
+
++test_expect_success 'show unmerged index' '
++ git reset --hard &&
++
++ git switch -C base &&
++ echo "base" > conflicting &&
++ git add conflicting &&
++ git commit -m "base" &&
++
++ git branch hello &&
++ git branch goodbye &&
++
++ git switch hello &&
++ echo "hello" > conflicting &&
++ git commit -am "hello" &&
++
++ git switch goodbye &&
++ echo "goodbye" > conflicting &&
++ git commit -am "goodbye" &&
++
++ git switch hello &&
++ test_must_fail git merge goodbye &&
++ git show --merge HEAD
++'
++
+ test_donerevision.c | 1 + t/t7007-show.sh | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+)
revision.c +1 -0
@@ -2060,6 +2060,7 @@ static void prepare_show_merge(struct rev_info *revs)parse_pathspec (&revs->prune_data,PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL ,PATHSPEC_PREFER_FULL |PATHSPEC_LITERAL_PATH ,"" , prune); revs->limited =1 ; +free (prune); } static int dotdot_missing(const char *arg, char *dotdot,
t/t7007-show.sh +24 -0
@@ -167,4 +167,28 @@ test_expect_success 'show --graph is forbidden' ' test_must_fail git show --graph HEAD ' +test_expect_success 'show unmerged index' ' + git reset --hard && + + git switch -C base && + echo "base" > conflicting && + git add conflicting && + git commit -m "base" && + + git branch hello && + git branch goodbye && + + git switch hello && + echo "hello" > conflicting && + git commit -am "hello" && + + git switch goodbye && + echo "goodbye" > conflicting && + git commit -am "goodbye" && + + git switch hello && + test_must_fail git merge goodbye && + git show --merge HEAD +' + test_done
base-commit: 7014b55638da979331baf8dc31c4e1d697cf2d67
Signature · 1 line
gitgitgadget
t/t7007-show.sh test_expect_success 'show --graph is forbidden' ' · line 171
Quoted 2 lines · Lidong Yan via GitGitGadget
t/t7007-show.sh +2
-0+test_expect_success 'show unmerged index' ' + git reset --hard &&
We use tabs for indent.
t/t7007-show.sh test_expect_success 'show --graph is forbidden' ' · line 174
Quoted 3 lines
t/t7007-show.sh +3
-0+ + git switch -C base && + echo "base" > conflicting &&
Let's lose the SP between redirection operator ">" and its target "conflicting", i.e.
echo "base" >conflicting &&
Quoted 22 lines
t/t7007-show.sh +19
-0+ git add conflicting && + git commit -m "base" && + + git branch hello && + git branch goodbye && + + git switch hello && + echo "hello" > conflicting && + git commit -am "hello" && + + git switch goodbye && + echo "goodbye" > conflicting && + git commit -am "goodbye" && + + git switch hello && + test_must_fail git merge goodbye && + git show --merge HEAD +' + test_donebase-commit:
7014b55638da979331baf8dc31c4e1d697cf2d67
PATCH v3 1/1 revision: fix memory leak in prepare_show_merge()
In reply to Lidong Yan via GitGitGadgetFrom: Lidong Yan <[email protected]>
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since parse_pathspec is not responsible to free prune, we should add free(prune) in the end of prepare_show_merge().
---
revision: fix memory leak in prepare_show_merge()
In revision.c:prepare_show_merge(), we allocated an array in prune but forget to free it. Since parse_pathspec is not responsible to free prune, we should add free(prune) in the end of prepare_show_merge().
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1989%2Fbrandb97%2Ffix-revision-leak-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1989/brandb97/fix-revision-leak-v3
Pull-Request: https://github.com/git/git/pull/1989
Range-diff vs v2:
1: 61a2d98dad9 ! 1: 88795b33bbe revision: fix memory leak in prepare_show_merge()
@@ t/t7007-show.sh: test_expect_success 'show --graph is forbidden' '
'
+test_expect_success 'show unmerged index' '
-+ git reset --hard &&
++ git reset --hard &&
+
-+ git switch -C base &&
-+ echo "base" > conflicting &&
-+ git add conflicting &&
-+ git commit -m "base" &&
++ git switch -C base &&
++ echo "base" >conflicting &&
++ git add conflicting &&
++ git commit -m "base" &&
+
-+ git branch hello &&
-+ git branch goodbye &&
++ git branch hello &&
++ git branch goodbye &&
+
-+ git switch hello &&
-+ echo "hello" > conflicting &&
-+ git commit -am "hello" &&
++ git switch hello &&
++ echo "hello" >conflicting &&
++ git commit -am "hello" &&
+
-+ git switch goodbye &&
-+ echo "goodbye" > conflicting &&
-+ git commit -am "goodbye" &&
++ git switch goodbye &&
++ echo "goodbye" >conflicting &&
++ git commit -am "goodbye" &&
+
-+ git switch hello &&
-+ test_must_fail git merge goodbye &&
-+ git show --merge HEAD
++ git switch hello &&
++ test_must_fail git merge goodbye &&
++ git show --merge HEAD
+'
+
test_donerevision.c | 1 + t/t7007-show.sh | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+)
revision.c +1 -0
@@ -2060,6 +2060,7 @@ static void prepare_show_merge(struct rev_info *revs)parse_pathspec (&revs->prune_data,PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL ,PATHSPEC_PREFER_FULL |PATHSPEC_LITERAL_PATH ,"" , prune); revs->limited =1 ; +free (prune); } static int dotdot_missing(const char *arg, char *dotdot,
t/t7007-show.sh +24 -0
@@ -167,4 +167,28 @@ test_expect_success 'show --graph is forbidden' ' test_must_fail git show --graph HEAD ' +test_expect_success 'show unmerged index' ' + git reset --hard && + + git switch -C base && + echo "base" >conflicting && + git add conflicting && + git commit -m "base" && + + git branch hello && + git branch goodbye && + + git switch hello && + echo "hello" >conflicting && + git commit -am "hello" && + + git switch goodbye && + echo "goodbye" >conflicting && + git commit -am "goodbye" && + + git switch hello && + test_must_fail git merge goodbye && + git show --merge HEAD +' + test_done
base-commit: 7014b55638da979331baf8dc31c4e1d697cf2d67
Signature · 1 line
gitgitgadget