From: "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Johannes Schindelin <johannes.schindelin@gmx.de>,
Johannes Schindelin <johannes.schindelin@gmx.de>
Subject: [PATCH v2 08/12] revision: avoid dereferencing NULL in `add_parents_only()`
Date: Fri, 10 Jul 2026 11:39:32 +0000 [thread overview]
Message-ID: <41285dd8e1df9d010648459d5ff93db72bff7c1a.1783683577.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2174.v2.git.1783683577.gitgitgadget@gmail.com>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
This function resolves revision suffixes like commit^@ (all parents),
commit^! (commit minus parents), and commit^-N (exclude Nth parent). It
calls `get_reference()` in a loop to peel through tag objects until it
reaches a commit.
The existing NULL check after `get_reference()` only handles the
ignore_missing case, but get_reference() can return NULL through three
distinct paths:
1. revs->ignore_missing: the caller asked to silently skip missing
objects.
2. revs->exclude_promisor_objects: the object is a lazy promisor
object that should be excluded from the walk.
3. revs->do_not_die_on_missing_objects: the caller wants to record
missing OIDs for later reporting (used by `git rev-list
--missing=print`) rather than dying.
In the latter two instances, the code falls through to dereference the
NULL pointer.
Handle all three cases explicitly:
- ignore_missing: return 0, matching the existing behavior and
the pattern in `handle_revision_arg()`.
- do_not_die_on_missing_objects: return 0. The missing OID has already
been recorded in `revs->missing_commits` by `get_reference()`.
Returning 0 is consistent with `handle_revision_arg()` and
`process_parents()`, both of which continue without error when this flag
is set. The broader codebase pattern for this flag is "record and
continue": list-objects.c, builtin/rev-list.c, and process_parents
all skip the die/error and keep walking.
- everything else (only the `exclude_promisor_objects` case in
practice): return -1, consistent with `handle_revision_arg()` where
the condition only matches `ignore_missing` or
`do_not_die_on_missing_objects`, falling through to ret = -1 for the
promisor case.
Note: the callers of `add_parents_only()` in
`handle_revision_pseudo_opt()` treat any nonzero return as "handled"
(`if (add_parents_only(...)) { ret = 0; }`), so the -1 for the promisor
case is indistinguishable from success there. This means a
promisor-excluded tag target referenced via commit^@ would be silently
skipped rather than producing an error. This is a pre-existing
limitation of the caller's return value handling and not made worse by
this change; the alternative (a NULL dereference crash) _would be_
strictly worse.
Pointed out by Coverity.
Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
revision.c | 9 +++++++--
t/t0410-partial-clone.sh | 18 ++++++++++++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/revision.c b/revision.c
index e91d7e1f11..7f3999b551 100644
--- a/revision.c
+++ b/revision.c
@@ -1903,8 +1903,13 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
return 0;
while (1) {
it = get_reference(revs, arg, &oid, 0);
- if (!it && revs->ignore_missing)
- return 0;
+ if (!it) {
+ if (revs->ignore_missing)
+ return 0;
+ if (revs->do_not_die_on_missing_objects)
+ return 0;
+ return -1;
+ }
if (it->type != OBJ_TAG)
break;
if (!((struct tag*)it)->tagged)
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index dff442da20..cc070019be 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -489,6 +489,24 @@ test_expect_success 'rev-list dies for missing objects on cmd line' '
done
'
+test_expect_success '--exclude-promisor-objects with ^@ on missing object' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo foo &&
+ test_commit -C repo bar &&
+
+ COMMIT=$(git -C repo rev-parse foo) &&
+ promise_and_delete "$COMMIT" &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+
+ # Ensure that "$COMMIT^@" is handled gracefully even though the
+ # actual commits are missing.
+ git -C repo rev-list --exclude-promisor-objects "$COMMIT^@" >out &&
+ test_must_be_empty out
+'
+
test_expect_success 'single promisor remote can be re-initialized gracefully' '
# ensure one promisor is in the promisors list
rm -rf repo &&
--
gitgitgadget
next prev parent reply other threads:[~2026-07-10 11:39 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 9:42 [PATCH 00/11] coverity: avoid dereferencing NULL Johannes Schindelin via GitGitGadget
2026-07-09 9:42 ` [PATCH 01/11] diffcore-break: guard against NULLed queue entries in merge loop Johannes Schindelin via GitGitGadget
2026-07-10 3:11 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 02/11] diff: handle NULL return from repo_get_commit_tree() Johannes Schindelin via GitGitGadget
2026-07-10 3:11 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 03/11] remote: guard `remote_tracking()` against NULL remote Johannes Schindelin via GitGitGadget
2026-07-10 3:21 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 04/11] reftable/stack: guard against NULL list_file in stack_destroy Johannes Schindelin via GitGitGadget
2026-07-10 3:21 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 05/11] mailsplit: move NULL check before first use of file handle Johannes Schindelin via GitGitGadget
2026-07-10 3:31 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 06/11] bisect: handle NULL commit in `bisect_successful()` Johannes Schindelin via GitGitGadget
2026-07-10 3:31 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 07/11] replay: die when --onto does not peel to a commit Johannes Schindelin via GitGitGadget
2026-07-09 9:42 ` [PATCH 08/11] revision: avoid dereferencing NULL in `add_parents_only()` Johannes Schindelin via GitGitGadget
2026-07-10 3:41 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 09/11] pack-bitmap: handle missing bitmap for base MIDX Johannes Schindelin via GitGitGadget
2026-07-10 3:41 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 10/11] bisect: ensure non-NULL `head` before using it Johannes Schindelin via GitGitGadget
2026-07-10 4:01 ` Junio C Hamano
2026-07-09 9:42 ` [PATCH 11/11] shallow: fix NULL dereference Johannes Schindelin via GitGitGadget
2026-07-09 20:10 ` Junio C Hamano
2026-07-10 11:39 ` [PATCH v2 00/12] coverity: avoid dereferencing NULL Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 01/12] diffcore-break: guard against NULLed queue entries in merge loop Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 02/12] diff: handle NULL return from repo_get_commit_tree() Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 03/12] remote: guard `remote_tracking()` against NULL remote Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 04/12] reftable/stack: guard against NULL list_file in stack_destroy Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 05/12] mailsplit: move NULL check before first use of file handle Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 06/12] bisect: handle NULL commit in `bisect_successful()` Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 07/12] replay: die when --onto does not peel to a commit Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` Johannes Schindelin via GitGitGadget [this message]
2026-07-10 11:39 ` [PATCH v2 09/12] pack-bitmap: handle missing bitmap for base MIDX Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 10/12] bisect: ensure non-NULL `head` before using it Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 11/12] shallow: fix NULL dereference Johannes Schindelin via GitGitGadget
2026-07-10 11:39 ` [PATCH v2 12/12] shallow: give write_one_shallow() its own hex buffer Johannes Schindelin via GitGitGadget
2026-07-10 15:46 ` [PATCH v2 00/12] coverity: avoid dereferencing NULL Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=41285dd8e1df9d010648459d5ff93db72bff7c1a.1783683577.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=johannes.schindelin@gmx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.