object: clear grafts when clearing parsed object pool

We do not clear grafts part of the parsed object pool when clearing the pool itself, which can lead to memory leaks when a repository is being cleared. Fix this by moving `reset_commit_grafts()` into "object.c" and making it part of the `struct parsed_object_pool` interface such that we can call it from `parsed_object_pool_clear()`. Adapt `parsed_object_pool_new()` to take and store a reference to its owning repository, which is needed by `unparse_commit()`. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Sep 5, 2024 at 12:09 UTC 0d1d22f5a385d05bde40303c17483db2eec499b3
6 files changed +21 -18
commit.c
+1 -13
@@ -177,7 +177,7 @@ int commit_graft_pos(struct repository *r, const struct object_id *oid)
177 commit_graft_oid_access);
178 }
179
180 -static void unparse_commit(struct repository *r, const struct object_id *oid)
180 +void unparse_commit(struct repository *r, const struct object_id *oid)
181 {
182 struct commit *c = lookup_commit(r, oid);
183
@@ -318,18 +318,6 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
318 return ret;
319 }
320
321 -void reset_commit_grafts(struct repository *r)
322 -{
323 - int i;
324 -
325 - for (i = 0; i < r->parsed_objects->grafts_nr; i++) {
326 - unparse_commit(r, &r->parsed_objects->grafts[i]->oid);
327 - free(r->parsed_objects->grafts[i]);
328 - }
329 - r->parsed_objects->grafts_nr = 0;
330 - r->parsed_objects->commit_graft_prepared = 0;
331 -}
332 -
321 struct commit_buffer {
322 void *buffer;
323 unsigned long size;
commit.h
+2 -1
@@ -108,6 +108,8 @@ static inline int repo_parse_commit_no_graph(struct repository *r,
108
109 void parse_commit_or_die(struct commit *item);
110
111 +void unparse_commit(struct repository *r, const struct object_id *oid);
112 +
113 struct buffer_slab;
114 struct buffer_slab *allocate_commit_buffer_slab(void);
115 void free_commit_buffer_slab(struct buffer_slab *bs);
@@ -240,7 +242,6 @@ int commit_graft_pos(struct repository *r, const struct object_id *oid);
242 int register_commit_graft(struct repository *r, struct commit_graft *, int);
243 void prepare_commit_graft(struct repository *r);
244 struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
243 -void reset_commit_grafts(struct repository *r);
245
246 struct commit *get_fork_point(const char *refname, struct commit *commit);
247
object.c
+13 -1
@@ -545,11 +545,12 @@ void repo_clear_commit_marks(struct repository *r, unsigned int flags)
545 }
546 }
547
548 -struct parsed_object_pool *parsed_object_pool_new(void)
548 +struct parsed_object_pool *parsed_object_pool_new(struct repository *repo)
549 {
550 struct parsed_object_pool *o = xmalloc(sizeof(*o));
551 memset(o, 0, sizeof(*o));
552
553 + o->repo = repo;
554 o->blob_state = allocate_alloc_state();
555 o->tree_state = allocate_alloc_state();
556 o->commit_state = allocate_alloc_state();
@@ -628,6 +629,16 @@ void raw_object_store_clear(struct raw_object_store *o)
629 hashmap_clear(&o->pack_map);
630 }
631
632 +void parsed_object_pool_reset_commit_grafts(struct parsed_object_pool *o)
633 +{
634 + for (int i = 0; i < o->grafts_nr; i++) {
635 + unparse_commit(o->repo, &o->grafts[i]->oid);
636 + free(o->grafts[i]);
637 + }
638 + o->grafts_nr = 0;
639 + o->commit_graft_prepared = 0;
640 +}
641 +
642 void parsed_object_pool_clear(struct parsed_object_pool *o)
643 {
644 /*
@@ -659,6 +670,7 @@ void parsed_object_pool_clear(struct parsed_object_pool *o)
670 free_commit_buffer_slab(o->buffer_slab);
671 o->buffer_slab = NULL;
672
673 + parsed_object_pool_reset_commit_grafts(o);
674 clear_alloc_state(o->blob_state);
675 clear_alloc_state(o->tree_state);
676 clear_alloc_state(o->commit_state);
object.h
+3 -1
@@ -7,6 +7,7 @@ struct buffer_slab;
7 struct repository;
8
9 struct parsed_object_pool {
10 + struct repository *repo;
11 struct object **obj_hash;
12 int nr_objs, obj_hash_size;
13
@@ -31,8 +32,9 @@ struct parsed_object_pool {
32 struct buffer_slab *buffer_slab;
33 };
34
34 -struct parsed_object_pool *parsed_object_pool_new(void);
35 +struct parsed_object_pool *parsed_object_pool_new(struct repository *repo);
36 void parsed_object_pool_clear(struct parsed_object_pool *o);
37 +void parsed_object_pool_reset_commit_grafts(struct parsed_object_pool *o);
38
39 struct object_list {
40 struct object *item;
repository.c
+1 -1
@@ -54,7 +54,7 @@ void initialize_repository(struct repository *repo)
54 {
55 repo->objects = raw_object_store_new();
56 repo->remote_state = remote_state_new();
57 - repo->parsed_objects = parsed_object_pool_new();
57 + repo->parsed_objects = parsed_object_pool_new(repo);
58 ALLOC_ARRAY(repo->index, 1);
59 index_state_init(repo->index, repo);
60
shallow.c
+1 -1
@@ -97,7 +97,7 @@ static void reset_repository_shallow(struct repository *r)
97 {
98 r->parsed_objects->is_shallow = -1;
99 stat_validity_clear(r->parsed_objects->shallow_stat);
100 - reset_commit_grafts(r);
100 + parsed_object_pool_reset_commit_grafts(r->parsed_objects);
101 }
102
103 int commit_shallow_file(struct repository *r, struct shallow_lock *lk)