aboutsummaryrefslogtreecommitdiffstats
path: root/object.h
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2025-10-23 09:16:20 +0200
committerJunio C Hamano <gitster@pobox.com>2025-11-04 07:32:25 -0800
commit7ec85185b197ce1cd28721a6f4415fb9db5cd42f (patch)
tree67e0b5b9b0fbd00025d78712868293d3f5bbe3c9 /object.h
parentrefs: drop infrastructure to peel via iterators (diff)
downloadgit-7ec85185b197ce1cd28721a6f4415fb9db5cd42f.tar.gz
git-7ec85185b197ce1cd28721a6f4415fb9db5cd42f.zip
object: add flag to `peel_object()` to verify object type
When peeling a tag to a non-tag object we repeatedly call `parse_object()` on the tagged object until we find the first object that isn't a tag. While this feels sensible at first, there is a big catch here: `parse_object()` doesn't actually verify the type of the tagged object. The relevant code path here eventually ends up in `parse_tag_buffer()`. Here, we parse the various fields of the tag, including the "type". Once we've figured out the type and the tagged object ID, we call one of the `lookup_${type}()` functions for whatever type we have found. There is two possible outcomes in the successful case: 1. The object is already part of our cached objects. In that case we double-check whether the type we're trying to look up matches the type that was cached. 2. The object is _not_ part of our cached objects. In that case, we simply create a new object with the expected type, but we don't parse that object. In the first case we might notice type mismatches, but only in the case where our cache has the object with the correct type. In the second case, we'll blindly assume that the type is correct and then go with it. We'll only notice that the type might be wrong when we try to parse the object at a later point. Now arguably, we could change `parse_tag_buffer()` to verify the tagged object's type for us. But that would have the effect that such a tag cannot be parsed at all anymore, and we have a small bunch of tests for exactly this case that assert we still can open such tags. So this change does not feel like something we can retroactively tighten, even though one shouldn't ever hit such corrupted tags. Instead, add a new `flags` field to `peel_object()` that allows the caller to opt in to strict object verification. This will be wired up at a subset of callsites over the next few commits. Note that this change also inlines `deref_tag_noverify()`. There's only been two callsites of that function, the one we're changing and one in our test helpers. The latter callsite can trivially use `deref_tag()` instead, so by inlining the function we avoid having to pass down the flag. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'object.h')
-rw-r--r--object.h15
1 files changed, 14 insertions, 1 deletions
diff --git a/object.h b/object.h
index 8c3c1c46e1..1499f63d50 100644
--- a/object.h
+++ b/object.h
@@ -287,6 +287,17 @@ enum peel_status {
PEEL_BROKEN = -4
};
+enum peel_object_flags {
+ /*
+ * Always verify the object type, even in the case where the looked-up
+ * object already has an object type. This can be useful when the
+ * stored object type may be invalid. One such case is when looking up
+ * objects via tags, where we blindly trust the object type declared by
+ * the tag.
+ */
+ PEEL_OBJECT_VERIFY_OBJECT_TYPE = (1 << 0),
+};
+
/*
* Peel the named object; i.e., if the object is a tag, resolve the
* tag recursively until a non-tag is found. If successful, store the
@@ -295,7 +306,9 @@ enum peel_status {
* and leave oid unchanged.
*/
enum peel_status peel_object(struct repository *r,
- const struct object_id *name, struct object_id *oid);
+ const struct object_id *name,
+ struct object_id *oid,
+ unsigned flags);
struct object_list *object_list_insert(struct object *item,
struct object_list **list_p);