Merge pull request #2527 from jacquesg/refspec-crash Check if the refspec matches before transforming
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
diff --git a/src/refspec.c b/src/refspec.c
index 77c58c8..9f0df35 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -223,7 +223,13 @@ static int refspec_transform(
int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *name)
{
- git_buf_sanitize(out);
+ assert(out && spec && name);
+ git_buf_sanitize(out);
+
+ if (!git_refspec_src_matches(spec, name)) {
+ giterr_set(GITERR_INVALID, "ref '%s' doesn't match the source", name);
+ return -1;
+ }
if (!spec->pattern)
return git_buf_puts(out, spec->dst);
@@ -233,7 +239,13 @@ int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *nam
int git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name)
{
- git_buf_sanitize(out);
+ assert(out && spec && name);
+ git_buf_sanitize(out);
+
+ if (!git_refspec_dst_matches(spec, name)) {
+ giterr_set(GITERR_INVALID, "ref '%s' doesn't match the destination", name);
+ return -1;
+ }
if (!spec->pattern)
return git_buf_puts(out, spec->src);
diff --git a/tests/network/refspecs.c b/tests/network/refspecs.c
index aa9b36e..c6bcb10 100644
--- a/tests/network/refspecs.c
+++ b/tests/network/refspecs.c
@@ -88,7 +88,7 @@ void test_network_refspecs__parsing(void)
assert_refspec(GIT_DIRECTION_FETCH, "refs/pull/*/head:refs/remotes/origin/pr/*", true);
}
-void assert_transform(const char *refspec, const char *name, const char *result)
+static void assert_valid_transform(const char *refspec, const char *name, const char *result)
{
git_refspec spec;
git_buf buf = GIT_BUF_INIT;
@@ -103,8 +103,46 @@ void assert_transform(const char *refspec, const char *name, const char *result)
void test_network_refspecs__transform_mid_star(void)
{
- assert_transform("refs/pull/*/head:refs/remotes/origin/pr/*", "refs/pull/23/head", "refs/remotes/origin/pr/23");
- assert_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/master", "refs/remotes/origin/master");
- assert_transform("refs/heads/*:refs/heads/*", "refs/heads/master", "refs/heads/master");
- assert_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master");
+ assert_valid_transform("refs/pull/*/head:refs/remotes/origin/pr/*", "refs/pull/23/head", "refs/remotes/origin/pr/23");
+ assert_valid_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/master", "refs/remotes/origin/master");
+ assert_valid_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/user/feature", "refs/remotes/origin/user/feature");
+ assert_valid_transform("refs/heads/*:refs/heads/*", "refs/heads/master", "refs/heads/master");
+ assert_valid_transform("refs/heads/*:refs/heads/*", "refs/heads/user/feature", "refs/heads/user/feature");
+ assert_valid_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master");
+}
+
+static void assert_invalid_transform(const char *refspec, const char *name)
+{
+ git_refspec spec;
+ git_buf buf = GIT_BUF_INIT;
+
+ git_refspec__parse(&spec, refspec, true);
+ cl_git_fail(git_refspec_transform(&buf, &spec, name));
+
+ git_buf_free(&buf);
+ git_refspec__free(&spec);
+}
+
+void test_network_refspecs__invalid(void)
+{
+ assert_invalid_transform("refs/heads/*:refs/remotes/origin/*", "master");
+ assert_invalid_transform("refs/heads/*:refs/remotes/origin/*", "refs/headz/master");
+}
+
+static void assert_invalid_rtransform(const char *refspec, const char *name)
+{
+ git_refspec spec;
+ git_buf buf = GIT_BUF_INIT;
+
+ git_refspec__parse(&spec, refspec, true);
+ cl_git_fail(git_refspec_rtransform(&buf, &spec, name));
+
+ git_buf_free(&buf);
+ git_refspec__free(&spec);
+}
+
+void test_network_refspecs__invalid_reverse(void)
+{
+ assert_invalid_rtransform("refs/heads/*:refs/remotes/origin/*", "master");
+ assert_invalid_rtransform("refs/heads/*:refs/remotes/origin/*", "refs/remotes/o/master");
}