Skip to content

Commit

Permalink
WIP: Add Valgrind "max address space" option.
Browse files Browse the repository at this point in the history
This option prevents the Python heap from reusing freed memory addresses
for new allocations (obviously only viable for some workloads!)

Advantage is that valgrind will be able to catch any use-after-free, that
might have been missed if the freed memory address was reallocated for
another use.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
  • Loading branch information
projectgus committed Mar 27, 2024
1 parent 7bfcc10 commit 02e3968
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 0 deletions.
9 changes: 9 additions & 0 deletions py/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,9 +643,11 @@ void gc_collect_end(void) {
#if MICROPY_GC_SPLIT_HEAP
MP_STATE_MEM(gc_last_free_area) = &MP_STATE_MEM(area);
#endif
#if !MICROPY_DEBUG_VALGRIND_MAX_ADDRSPACE
for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) {
area->gc_last_free_atb_index = 0;
}
#endif
MP_STATE_THREAD(gc_lock_depth)--;
GC_EXIT();
}
Expand Down Expand Up @@ -832,6 +834,9 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {
#endif
area->gc_last_free_atb_index = (i + 1) / BLOCKS_PER_ATB;
}
#if MICROPY_DEBUG_VALGRIND_MAX_ADDRSPACE
area->gc_last_free_atb_index = (i + 1) / BLOCKS_PER_ATB;
#endif

area->gc_last_used_block = MAX(area->gc_last_used_block, end_block);

Expand Down Expand Up @@ -960,10 +965,12 @@ void gc_free(void *ptr) {
}
#endif

#if !MICROPY_DEBUG_VALGRIND_MAX_ADDRSPACE
// set the last_free pointer to this block if it's earlier in the heap
if (block / BLOCKS_PER_ATB < area->gc_last_free_atb_index) {
area->gc_last_free_atb_index = block / BLOCKS_PER_ATB;
}
#endif

// free head and all of its tail blocks
do {
Expand Down Expand Up @@ -1127,10 +1134,12 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
}
#endif

#if !MICROPY_DEBUG_VALGRIND_MAX_ADDRSPACE
// set the last_free pointer to end of this block if it's earlier in the heap
if ((block + new_blocks) / BLOCKS_PER_ATB < area->gc_last_free_atb_index) {
area->gc_last_free_atb_index = (block + new_blocks) / BLOCKS_PER_ATB;
}
#endif

VALGRIND_MP_RESIZE_BLOCK(ptr, n_blocks, n_bytes);

Expand Down
6 changes: 6 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,12 @@
#define MICROPY_DEBUG_VALGRIND (0)
#endif

// Whether valgrind should always use new memory addresses for allocations,
// making it easier to find use-after-free bugs.
#ifndef MICROPY_DEBUG_VALGRIND_MAX_ADDRSPACE
#define MICROPY_DEBUG_VALGRIND_MAX_ADDRSPACE (MICROPY_DEBUG_VALGRIND)
#endif

/*****************************************************************************/
/* Optimisations */

Expand Down

0 comments on commit 02e3968

Please sign in to comment.