Skip to content

git_refspec_transform: Handle NULL dst#4699

Merged
pks-t merged 3 commits intolibgit2:masterfrom
nelhage:fetch-null-dst
Jul 6, 2018
Merged

git_refspec_transform: Handle NULL dst#4699
pks-t merged 3 commits intolibgit2:masterfrom
nelhage:fetch-null-dst

Conversation

@nelhage
Copy link
Copy Markdown
Contributor

@nelhage nelhage commented Jun 25, 2018

per

libgit2/src/refspec.c

Lines 85 to 90 in b121b7a

/*
* RHS
* - missing is ok, and is same as empty.
* - empty is ok; it means not to store.
* - otherwise it must be a valid looking ref.
*/
this is considered valid, so we should handle it downstream.

Found via triggering the assertion failure in git_buf_puts in my work-in-progress fuzzer.

Comment thread src/refspec.c

if (!spec->pattern)
return git_buf_puts(out, spec->dst);
return git_buf_puts(out, spec->dst ? spec->dst : "");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to write a test for it? I think it should be rather easy to do as there is already precedence of testing this function in "tests/network/refspecs.c".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Verified that this breaks before the fix and passes afterwards.
@pks-t
Copy link
Copy Markdown
Member

pks-t commented Jun 29, 2018

Thanks for the test!

I think I need a second opinion on the new behaviour. Thing is, when you parse a refspec "refs/heads/master:" with git_refspec_parse, you get a src of "refs/heads/master" and dst is NULL. But when you now transform such a refspec, you do not get NULL but instead you'd get an empty string (or rather a buffer containing an emtpy string). I can't help but feel that this is being inconsistent. The problem is obviously that you cannot return a NULL pointer via the git_buf out parameter.

Going a bit deeper: what would a caller of git_refspec_transform actually expect? He wants to transfor a source ref (potentially with globs) to a destination ref. But in case of "refs/heads/master:" there is no destination ref. Should we, instead of passing back an empty string, raise an error?

@ethomson, do you have some thoughts?

Comment thread tests/network/refspecs.c Outdated
assert_valid_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master");
}

void test_network_refspecs__no_dst(void) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The opening brace of functions should actually start on their own line :)

@nelhage
Copy link
Copy Markdown
Contributor Author

nelhage commented Jun 29, 2018

Backing up from the question of

what would a caller of git_refspec_transform actually expect?

We have the question of: “What would a caller of git_refspec__parse followed by git_refspec_transform expect?”

In that case, the input string of "refs/heads/master:" has an empty dst, so we would expect to get back an empty string. I read git_refspec__parse, and it appears to deliberately return NULL. Taking it as givens that both

  1. git_refspec__parse + git_refspec_transform should round-trip an empty dst
  2. git_refspec__parse (is allow to) returns NULL to mean an empty dst

We reach the conclusion that git_refspec_transform should accept NULL.

We could alternately relax (2) and make git_refspec__parse return "" instead of NULL.

@pks-t pks-t merged commit 8a00de0 into libgit2:master Jul 6, 2018
@pks-t
Copy link
Copy Markdown
Member

pks-t commented Jul 6, 2018

Thanks for your reasoning and this change!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants