Skip to content

Some defensive programming #1890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
skip_prefix(orig_ref, "refs/heads/", &bare_ref);

branch = branch_get(bare_ref);
if (!branch)
BUG("could not get branch for '%s", bare_ref);
if (!branch->remote_name) {
warning(_("asked to inherit tracking from '%s', but no remote is set"),
bare_ref);
Expand Down
2 changes: 2 additions & 0 deletions builtin/describe.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
unsigned int unannotated_cnt = 0;

cmit = lookup_commit_reference(the_repository, oid);
if (!cmit)
die(_("could not look up commit '%s'"), oid_to_hex(oid));

n = find_commit_name(&cmit->object.oid);
if (n && (tags || all || n->prio == 2)) {
Expand Down
3 changes: 2 additions & 1 deletion builtin/fetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ static struct ref *get_ref_map(struct remote *remote,
if (remote &&
(remote->fetch.nr ||
/* Note: has_merge implies non-NULL branch->remote_name */
(has_merge && !strcmp(branch->remote_name, remote->name)))) {
(has_merge && branch && !strcmp(branch->remote_name, remote->name)))) {
for (i = 0; i < remote->fetch.nr; i++) {
get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0);
if (remote->fetch.items[i].dst &&
Expand All @@ -571,6 +571,7 @@ static struct ref *get_ref_map(struct remote *remote,
* Note: has_merge implies non-NULL branch->remote_name
*/
if (has_merge &&
branch &&
!strcmp(branch->remote_name, remote->name))
add_merge_config(&ref_map, remote_refs, branch, &tail);
} else if (!prefetch) {
Expand Down
2 changes: 1 addition & 1 deletion builtin/push.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static void refspec_append_mapped(struct refspec *refspec, const char *ref,
if (push_default == PUSH_DEFAULT_UPSTREAM &&
skip_prefix(matched->name, "refs/heads/", &branch_name)) {
struct branch *branch = branch_get(branch_name);
if (branch->merge_nr == 1 && branch->merge[0]->src) {
if (branch && branch->merge_nr == 1 && branch->merge[0]->src) {
refspec_appendf(refspec, "%s:%s",
ref, branch->merge[0]->src);
return;
Expand Down
7 changes: 6 additions & 1 deletion builtin/stash.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
memset(&opts, 0, sizeof(opts));

tree = parse_tree_indirect(i_tree);
if (parse_tree(tree))
if (!tree || parse_tree(tree))
return -1;

init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size);
Expand Down Expand Up @@ -1396,6 +1396,11 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
goto done;
} else {
head_commit = lookup_commit(the_repository, &info->b_commit);
if (!head_commit) {
ret = error(_("could not look up commit '%s'"),
oid_to_hex (&info->b_commit));
goto done;
}
}

if (!check_changes(ps, include_untracked, &untracked_files)) {
Expand Down
3 changes: 3 additions & 0 deletions builtin/submodule--helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1934,6 +1934,9 @@ static int determine_submodule_update_strategy(struct repository *r,
const char *val;
int ret;

if (!sub)
return error(_("could not retrieve submodule information for path '%s'"), path);

key = xstrfmt("submodule.%s.update", sub->name);

if (update) {
Expand Down
5 changes: 5 additions & 0 deletions commit-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -2786,6 +2786,11 @@ static int verify_one_commit_graph(struct repository *r,
the_repository->hash_algo);

graph_commit = lookup_commit(r, &cur_oid);
if (!graph_commit) {
graph_report(_("failed to look up commit %s for commit-graph"),
oid_to_hex(&cur_oid));
continue;
}
odb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));
if (repo_parse_commit_internal(r, odb_commit, 0, 0)) {
graph_report(_("failed to parse commit %s from object database for commit-graph"),
Expand Down
2 changes: 1 addition & 1 deletion commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ void unparse_commit(struct repository *r, const struct object_id *oid)
{
struct commit *c = lookup_commit(r, oid);

if (!c->object.parsed)
if (!c || !c->object.parsed)
return;
free_commit_list(c->parents);
c->parents = NULL;
Expand Down
2 changes: 1 addition & 1 deletion fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
struct tag *tag = (struct tag *)
Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Johannes Schindelin via GitGitGadget" <[email protected]>
writes:

> From: Johannes Schindelin <[email protected]>
>
> CodeQL points out that `parse_object()` can return NULL values.
>
> Signed-off-by: Johannes Schindelin <[email protected]>
> ---
>  fetch-pack.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fetch-pack.c b/fetch-pack.c
> index 1ed5e11dd568..4cbcb0c14c48 100644
> --- a/fetch-pack.c
> +++ b/fetch-pack.c
> @@ -155,7 +155,7 @@ static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
>  			struct tag *tag = (struct tag *)
>  				parse_object(the_repository, oid);
>  
> -			if (!tag->tagged)
> +			if (!tag || !tag->tagged)
>  				return NULL;

The "oid" can come from corruptible sources like commit graph file,
so I agree with your analysis that it may name a missing object in a
corrupt repository, leading "tag" being NULL.  Looks correct.


>  			if (mark_tags_complete_and_check_obj_db)
>  				tag->object.flags |= COMPLETE;

parse_object(the_repository, oid);

if (!tag->tagged)
if (!tag || !tag->tagged)
return NULL;
if (mark_tags_complete_and_check_obj_db)
tag->object.flags |= COMPLETE;
Expand Down
2 changes: 1 addition & 1 deletion object-name.c
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,7 @@ static enum get_oid_result get_parent(struct repository *r,
if (ret)
Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Johannes Schindelin via GitGitGadget" <[email protected]>
writes:

> From: Johannes Schindelin <[email protected]>
>
> CodeQL points out that `lookup_commit_reference()` can return NULL
> values.
>
> Signed-off-by: Johannes Schindelin <[email protected]>
> ---
>  object-name.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/object-name.c b/object-name.c
> index 76749fbfe652..ca54dad2f4c8 100644
> --- a/object-name.c
> +++ b/object-name.c
> @@ -1106,7 +1106,7 @@ static enum get_oid_result get_parent(struct repository *r,
>  	if (ret)
>  		return ret;
>  	commit = lookup_commit_reference(r, &oid);
> -	if (repo_parse_commit(r, commit))
> +	if (!commit || repo_parse_commit(r, commit))
>  		return MISSING_OBJECT;

Most of the time, the check for "ret" we see in the pre-context,
which is a result of get_oid_1(), would prevent an oid that is not a
valid name for a committish to even reach this code, I would think,
but with possible repository corruption, we may fail to "lookup" the
commit, so this is a good correction, I would think.

Thanks.


>  	if (!idx) {
>  		oidcpy(result, &commit->object.oid);

Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Jeff King wrote (reply to this):

On Thu, May 15, 2025 at 12:45:27PM +0000, Johannes Schindelin via GitGitGadget wrote:

> CodeQL points out that `lookup_commit_reference()` can return NULL
> values.
> [...]
>  	commit = lookup_commit_reference(r, &oid);
> -	if (repo_parse_commit(r, commit))
> +	if (!commit || repo_parse_commit(r, commit))
>  		return MISSING_OBJECT;

Sure, but repo_parse_commit() can also handle NULL values. It returns
"-1" in that case. I think CodeQL is not smart enough to know that.

-Peff

return ret;
commit = lookup_commit_reference(r, &oid);
if (repo_parse_commit(r, commit))
if (!commit || repo_parse_commit(r, commit))
return MISSING_OBJECT;
if (!idx) {
oidcpy(result, &commit->object.oid);
Expand Down
3 changes: 3 additions & 0 deletions revision.c
Original file line number Diff line number Diff line change
Expand Up @@ -3359,6 +3359,9 @@ static int leave_one_treesame_to_parent(struct rev_info *revs, struct commit *co
struct commit_list *p;
Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Johannes Schindelin via GitGitGadget" <[email protected]>
writes:

> From: Johannes Schindelin <[email protected]>
>
> On the off chance that `lookup_decoration()` cannot find anything, let
> `leave_one_treesame_to_parent()` return gracefully instead of crashing.

But wouldn't it be a BUG("") worthy event for the treesame
decoration not to exist for the commit object in question at this
point of the code?  Is it really defensive to silently pretend that
nothing bad happened and to move forward?

> Pointed out by CodeQL.
>
> Signed-off-by: Johannes Schindelin <[email protected]>
> ---
>  revision.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/revision.c b/revision.c
> index c4390f0938cb..59eae4eb8ba8 100644
> --- a/revision.c
> +++ b/revision.c
> @@ -3359,6 +3359,9 @@ static int leave_one_treesame_to_parent(struct rev_info *revs, struct commit *co
>  	struct commit_list *p;
>  	unsigned n;
>  
> +	if (!ts)
> +		return 0;
> +
>  	for (p = commit->parents, n = 0; p; p = p->next, n++) {
>  		if (ts->treesame[n]) {
>  			if (p->item->object.flags & TMP_MARK) {

unsigned n;

if (!ts)
return 0;

for (p = commit->parents, n = 0; p; p = p->next, n++) {
if (ts->treesame[n]) {
if (p->item->object.flags & TMP_MARK) {
Expand Down
3 changes: 2 additions & 1 deletion shallow.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,8 @@ void assign_shallow_commits_to_refs(struct shallow_info *info,
for (i = 0; i < nr_shallow; i++) {
struct commit *c = lookup_commit(the_repository,
&oid[shallow[i]]);
c->object.flags |= BOTTOM;
if (c)
c->object.flags |= BOTTOM;
}

for (i = 0; i < ref->nr; i++)
Expand Down
2 changes: 2 additions & 0 deletions t/helper/test-repository.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
repo_set_hash_algo(the_repository, hash_algo_by_ptr(r.hash_algo));

c = lookup_commit(&r, commit_oid);
if (!c)
die("Could not look up %s", oid_to_hex(commit_oid));

if (!parse_commit_in_graph(&r, c))
die("Couldn't parse commit");
Expand Down
Loading