Skip to content

Commit 8616a2d

Browse files
jamillgitster
authored andcommitted
block alloc: add validations around cache_entry lifecyle
Add an option (controlled by an environment variable) perform extra validations on mem_pool allocated cache entries. When set: 1) Invalidate cache_entry memory when discarding cache_entry. 2) When discarding index_state struct, verify that all cache_entries were allocated from expected mem_pool. 3) When discarding mem_pools, invalidate mem_pool memory. This should provide extra checks that mem_pools and their allocated cache_entries are being used as expected. Signed-off-by: Jameson Miller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8e72d67 commit 8616a2d

File tree

5 files changed

+68
-4
lines changed

5 files changed

+68
-4
lines changed

cache.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,12 @@ struct cache_entry *make_empty_transient_cache_entry(size_t name_len);
380380
*/
381381
void discard_cache_entry(struct cache_entry *ce);
382382

383+
/*
384+
* Check configuration if we should perform extra validation on cache
385+
* entries.
386+
*/
387+
int should_validate_cache_entries(void);
388+
383389
/*
384390
* Duplicate a cache_entry. Allocate memory for the new entry from a
385391
* memory_pool. Takes into account cache_entry fields that are meant

git.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,10 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
414414

415415
trace_argv_printf(argv, "trace: built-in: git");
416416

417+
validate_cache_entries(&the_index);
417418
status = p->fn(argc, argv, prefix);
419+
validate_cache_entries(&the_index);
420+
418421
if (status)
419422
return status;
420423

mem-pool.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)
5050
*mem_pool = pool;
5151
}
5252

53-
void mem_pool_discard(struct mem_pool *mem_pool)
53+
void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)
5454
{
5555
struct mp_block *block, *block_to_free;
5656

@@ -59,6 +59,10 @@ void mem_pool_discard(struct mem_pool *mem_pool)
5959
{
6060
block_to_free = block;
6161
block = block->next_block;
62+
63+
if (invalidate_memory)
64+
memset(block_to_free->space, 0xDD, ((char *)block_to_free->end) - ((char *)block_to_free->space));
65+
6266
free(block_to_free);
6367
}
6468

mem-pool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size);
2929
/*
3030
* Discard a memory pool and free all the memory it is responsible for.
3131
*/
32-
void mem_pool_discard(struct mem_pool *mem_pool);
32+
void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);
3333

3434
/*
3535
* Alloc memory from the mem_pool.

read-cache.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,8 +2050,10 @@ int discard_index(struct index_state *istate)
20502050
* Cache entries in istate->cache[] should have been allocated
20512051
* from the memory pool associated with this index, or from an
20522052
* associated split_index. There is no need to free individual
2053-
* cache entries.
2053+
* cache entries. validate_cache_entries can detect when this
2054+
* assertion does not hold.
20542055
*/
2056+
validate_cache_entries(istate);
20552057

20562058
resolve_undo_clear_index(istate);
20572059
istate->cache_nr = 0;
@@ -2068,13 +2070,45 @@ int discard_index(struct index_state *istate)
20682070
istate->untracked = NULL;
20692071

20702072
if (istate->ce_mem_pool) {
2071-
mem_pool_discard(istate->ce_mem_pool);
2073+
mem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());
20722074
istate->ce_mem_pool = NULL;
20732075
}
20742076

20752077
return 0;
20762078
}
20772079

2080+
/*
2081+
* Validate the cache entries of this index.
2082+
* All cache entries associated with this index
2083+
* should have been allocated by the memory pool
2084+
* associated with this index, or by a referenced
2085+
* split index.
2086+
*/
2087+
void validate_cache_entries(const struct index_state *istate)
2088+
{
2089+
int i;
2090+
2091+
if (!should_validate_cache_entries() ||!istate || !istate->initialized)
2092+
return;
2093+
2094+
for (i = 0; i < istate->cache_nr; i++) {
2095+
if (!istate) {
2096+
die("internal error: cache entry is not allocated from expected memory pool");
2097+
} else if (!istate->ce_mem_pool ||
2098+
!mem_pool_contains(istate->ce_mem_pool, istate->cache[i])) {
2099+
if (!istate->split_index ||
2100+
!istate->split_index->base ||
2101+
!istate->split_index->base->ce_mem_pool ||
2102+
!mem_pool_contains(istate->split_index->base->ce_mem_pool, istate->cache[i])) {
2103+
die("internal error: cache entry is not allocated from expected memory pool");
2104+
}
2105+
}
2106+
}
2107+
2108+
if (istate->split_index)
2109+
validate_cache_entries(istate->split_index->base);
2110+
}
2111+
20782112
int unmerged_index(const struct index_state *istate)
20792113
{
20802114
int i;
@@ -2878,8 +2912,25 @@ struct cache_entry *dup_cache_entry(const struct cache_entry *ce,
28782912

28792913
void discard_cache_entry(struct cache_entry *ce)
28802914
{
2915+
if (ce && should_validate_cache_entries())
2916+
memset(ce, 0xCD, cache_entry_size(ce->ce_namelen));
2917+
28812918
if (ce && ce->mem_pool_allocated)
28822919
return;
28832920

28842921
free(ce);
28852922
}
2923+
2924+
int should_validate_cache_entries(void)
2925+
{
2926+
static int validate_index_cache_entries = -1;
2927+
2928+
if (validate_index_cache_entries < 0) {
2929+
if (getenv("GIT_TEST_VALIDATE_INDEX_CACHE_ENTRIES"))
2930+
validate_index_cache_entries = 1;
2931+
else
2932+
validate_index_cache_entries = 0;
2933+
}
2934+
2935+
return validate_index_cache_entries;
2936+
}

0 commit comments

Comments
 (0)