Skip to content

Commit 5699d17

Browse files
kbleesgitster
authored andcommitted
read-cache.c: fix memory leaks caused by removed cache entries
When cache_entry structs are removed from index_state.cache, they are not properly freed. Freeing those entries wasn't possible before because we couldn't remove them from index_state.name_hash. Now that we _do_ remove the entries from name_hash, we can also free them. Add 'free(cache_entry)' to all call sites of name-hash.c::remove_name_hash in read-cache.c (we could free() directly in remove_name_hash(), but name-hash.c isn't concerned with cache_entry allocation at all). Accessing a cache_entry after removing it from the index is now no longer allowed, as the memory has been freed. The following functions need minor fixes (typically by copying ce->name before use): - builtin/rm.c::cmd_rm - builtin/update-index.c::do_reupdate - read-cache.c::read_index_unmerged - resolve-undo.c::unmerge_index_entry_at Signed-off-by: Karsten Blees <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6bb6907 commit 5699d17

File tree

4 files changed

+16
-6
lines changed

4 files changed

+16
-6
lines changed

builtin/rm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
311311
if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), 0, seen))
312312
continue;
313313
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
314-
list.entry[list.nr].name = ce->name;
314+
list.entry[list.nr].name = xstrdup(ce->name);
315315
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
316316
if (list.entry[list.nr++].is_submodule &&
317317
!is_staging_gitmodules_ok())

builtin/update-index.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ static int do_reupdate(int ac, const char **av,
559559
const struct cache_entry *ce = active_cache[pos];
560560
struct cache_entry *old = NULL;
561561
int save_nr;
562+
char *path;
562563

563564
if (ce_stage(ce) || !ce_path_match(ce, &pathspec))
564565
continue;
@@ -575,7 +576,9 @@ static int do_reupdate(int ac, const char **av,
575576
* or worse yet 'allow_replace', active_nr may decrease.
576577
*/
577578
save_nr = active_nr;
578-
update_one(ce->name);
579+
path = xstrdup(ce->name);
580+
update_one(path);
581+
free(path);
579582
if (save_nr != active_nr)
580583
goto redo;
581584
}

read-cache.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache
4747
struct cache_entry *old = istate->cache[nr];
4848

4949
remove_name_hash(istate, old);
50+
free(old);
5051
set_index_entry(istate, nr, ce);
5152
istate->cache_changed = 1;
5253
}
@@ -478,6 +479,7 @@ int remove_index_entry_at(struct index_state *istate, int pos)
478479

479480
record_resolve_undo(istate, ce);
480481
remove_name_hash(istate, ce);
482+
free(ce);
481483
istate->cache_changed = 1;
482484
istate->cache_nr--;
483485
if (pos >= istate->cache_nr)
@@ -499,8 +501,10 @@ void remove_marked_cache_entries(struct index_state *istate)
499501
unsigned int i, j;
500502

501503
for (i = j = 0; i < istate->cache_nr; i++) {
502-
if (ce_array[i]->ce_flags & CE_REMOVE)
504+
if (ce_array[i]->ce_flags & CE_REMOVE) {
503505
remove_name_hash(istate, ce_array[i]);
506+
free(ce_array[i]);
507+
}
504508
else
505509
ce_array[j++] = ce_array[i];
506510
}
@@ -1894,7 +1898,7 @@ int read_index_unmerged(struct index_state *istate)
18941898
new_ce->ce_mode = ce->ce_mode;
18951899
if (add_index_entry(istate, new_ce, 0))
18961900
return error("%s: cannot drop to stage #0",
1897-
ce->name);
1901+
new_ce->name);
18981902
i = index_name_pos(istate, new_ce->name, len);
18991903
}
19001904
return unmerged;

resolve-undo.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
119119
struct string_list_item *item;
120120
struct resolve_undo_info *ru;
121121
int i, err = 0, matched;
122+
char *name;
122123

123124
if (!istate->resolve_undo)
124125
return pos;
@@ -138,20 +139,22 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
138139
if (!ru)
139140
return pos;
140141
matched = ce->ce_flags & CE_MATCHED;
142+
name = xstrdup(ce->name);
141143
remove_index_entry_at(istate, pos);
142144
for (i = 0; i < 3; i++) {
143145
struct cache_entry *nce;
144146
if (!ru->mode[i])
145147
continue;
146148
nce = make_cache_entry(ru->mode[i], ru->sha1[i],
147-
ce->name, i + 1, 0);
149+
name, i + 1, 0);
148150
if (matched)
149151
nce->ce_flags |= CE_MATCHED;
150152
if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
151153
err = 1;
152-
error("cannot unmerge '%s'", ce->name);
154+
error("cannot unmerge '%s'", name);
153155
}
154156
}
157+
free(name);
155158
if (err)
156159
return pos;
157160
free(ru);

0 commit comments

Comments
 (0)