Skip to content

Commit 22df47c

Browse files
committed
Fix segfault if gitmodules is invalid
The reload_all call could end up dereferencing a NULL pointer if there was an error while attempting to load the submodules config data (i.e. invalid content in the gitmodules file). This fixes it.
1 parent f4afcaa commit 22df47c

File tree

3 files changed

+101
-5
lines changed

3 files changed

+101
-5
lines changed

include/git2/submodule.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ typedef enum {
115115
*
116116
* - The submodule is not mentioned in the HEAD, the index, and the config,
117117
* but does "exist" in the working directory (i.e. there is a subdirectory
118-
* that is a valid self-contained git repo). In this case, this function
119-
* returns GIT_EEXISTS to indicate the the submodule exists but not in a
118+
* that appears to be a Git repository). In this case, this function
119+
* returns GIT_EEXISTS to indicate a sub-repository exists but not in a
120120
* state where a git_submodule can be instantiated.
121121
* - The submodule is not mentioned in the HEAD, index, or config and the
122122
* working directory doesn't contain a value git repo at that path.
@@ -129,7 +129,7 @@ typedef enum {
129129
* @param repo The parent repository
130130
* @param name The name of or path to the submodule; trailing slashes okay
131131
* @return 0 on success, GIT_ENOTFOUND if submodule does not exist,
132-
* GIT_EEXISTS if submodule exists in working directory only,
132+
* GIT_EEXISTS if a repository is found in working directory only,
133133
* -1 on other errors.
134134
*/
135135
GIT_EXTERN(int) git_submodule_lookup(

src/submodule.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ int git_submodule_lookup(
156156
if (git_buf_joinpath(&path, git_repository_workdir(repo), name) < 0)
157157
return -1;
158158

159-
if (git_path_contains_dir(&path, DOT_GIT))
159+
if (git_path_contains(&path, DOT_GIT))
160160
error = GIT_EEXISTS;
161161

162162
git_buf_free(&path);
@@ -846,7 +846,8 @@ int git_submodule_reload_all(git_repository *repo, int force)
846846
if (repo->submodules)
847847
git_strmap_foreach_value(repo->submodules, sm, { sm->flags = 0; });
848848

849-
error = load_submodule_config(repo, true);
849+
if ((error = load_submodule_config(repo, true)) < 0)
850+
return error;
850851

851852
git_strmap_foreach_value(repo->submodules, sm, {
852853
git_strmap *cache = repo->submodules;

tests/submodule/nosubs.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/* test the submodule APIs on repositories where there are no submodules */
2+
3+
#include "clar_libgit2.h"
4+
#include "posix.h"
5+
6+
void test_submodule_nosubs__cleanup(void)
7+
{
8+
cl_git_sandbox_cleanup();
9+
}
10+
11+
void test_submodule_nosubs__lookup(void)
12+
{
13+
git_repository *repo = cl_git_sandbox_init("status");
14+
git_submodule *sm = NULL;
15+
16+
p_mkdir("status/subrepo", 0777);
17+
cl_git_mkfile("status/subrepo/.git", "gitdir: ../.git");
18+
19+
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, repo, "subdir"));
20+
21+
cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, repo, "subrepo"));
22+
23+
cl_git_pass(git_submodule_reload_all(repo, 0));
24+
25+
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, repo, "subdir"));
26+
27+
cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, repo, "subrepo"));
28+
}
29+
30+
void test_submodule_nosubs__immediate_reload(void)
31+
{
32+
git_repository *repo = cl_git_sandbox_init("status");
33+
cl_git_pass(git_submodule_reload_all(repo, 0));
34+
}
35+
36+
static int fake_submod_cb(git_submodule *sm, const char *n, void *p)
37+
{
38+
GIT_UNUSED(sm); GIT_UNUSED(n); GIT_UNUSED(p);
39+
return 0;
40+
}
41+
42+
void test_submodule_nosubs__foreach(void)
43+
{
44+
git_repository *repo = cl_git_sandbox_init("status");
45+
cl_git_pass(git_submodule_foreach(repo, fake_submod_cb, NULL));
46+
}
47+
48+
void test_submodule_nosubs__add(void)
49+
{
50+
git_repository *repo = cl_git_sandbox_init("status");
51+
git_submodule *sm, *sm2;
52+
53+
cl_git_pass(git_submodule_add_setup(&sm, repo, "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
54+
55+
cl_git_pass(git_submodule_lookup(&sm2, repo, "submodules/libgit2"));
56+
git_submodule_free(sm2);
57+
58+
cl_git_pass(git_submodule_foreach(repo, fake_submod_cb, NULL));
59+
cl_git_pass(git_submodule_reload_all(repo, 0));
60+
61+
git_submodule_free(sm);
62+
}
63+
64+
void test_submodule_nosubs__reload_add_reload(void)
65+
{
66+
git_repository *repo = cl_git_sandbox_init("status");
67+
git_submodule *sm;
68+
69+
cl_git_pass(git_submodule_reload_all(repo, 0));
70+
71+
cl_git_pass(git_submodule_add_setup(&sm, repo, "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
72+
73+
cl_git_pass(git_submodule_reload_all(repo, 0));
74+
75+
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
76+
git_submodule_free(sm);
77+
78+
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
79+
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
80+
git_submodule_free(sm);
81+
}
82+
83+
void test_submodule_nosubs__bad_gitmodules(void)
84+
{
85+
git_repository *repo = cl_git_sandbox_init("status");
86+
87+
cl_git_mkfile("status/.gitmodules", "[submodule \"foobar\"]\tpath=blargle\n\turl=\n\tbranch=\n\tupdate=flooble\n\n");
88+
cl_git_fail(git_submodule_reload_all(repo, 0));
89+
90+
cl_git_rewritefile("status/.gitmodules", "[submodule \"foobar\"]\tpath=blargle\n\turl=\n\tbranch=\n\tupdate=rebase\n\n");
91+
cl_git_pass(git_submodule_reload_all(repo, 0));
92+
93+
cl_git_pass(git_submodule_lookup(NULL, repo, "foobar"));
94+
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(NULL, repo, "subdir"));
95+
}

0 commit comments

Comments
 (0)