Skip to content

Commit 6a40372

Browse files
committed
py/malloc: Add m_tracked_realloc.
Signed-off-by: Andrew Leech <[email protected]>
1 parent e6a7dc1 commit 6a40372

File tree

5 files changed

+66
-5
lines changed

5 files changed

+66
-5
lines changed

ports/unix/coverage.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,13 @@ static mp_obj_t extra_coverage(void) {
343343
gc_collect();
344344
}
345345

346+
// resize one of the blocks
347+
void *before = ptrs[1];
348+
ptrs[1] = FLIP_POINTER(m_tracked_realloc(FLIP_POINTER(ptrs[1]), 2 * NUM_BYTES));
349+
void *after = ptrs[1];
350+
bool location_changed = before != after;
351+
mp_printf(&mp_plat_print, "%d\n", location_changed);
352+
346353
// check the memory blocks have the correct content
347354
for (size_t i = 0; i < NUM_PTRS; ++i) {
348355
bool correct_contents = true;

py/malloc.c

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,15 @@ typedef struct _m_tracked_node_t {
245245
uint8_t data[];
246246
} m_tracked_node_t;
247247

248+
// Helper to get data size of a tracked node, abstracting MICROPY_TRACKED_ALLOC_STORE_SIZE.
249+
static inline size_t get_tracked_node_size(m_tracked_node_t *node) {
250+
#if MICROPY_TRACKED_ALLOC_STORE_SIZE
251+
return node->size;
252+
#else
253+
return gc_nbytes(node) - sizeof(m_tracked_node_t);
254+
#endif
255+
}
256+
248257
#if MICROPY_DEBUG_VERBOSE
249258
static size_t m_tracked_count_links(size_t *nb) {
250259
m_tracked_node_lock();
@@ -292,18 +301,57 @@ void *m_tracked_calloc(size_t nmemb, size_t size) {
292301
return &node->data[0];
293302
}
294303

304+
void *m_tracked_realloc(void *ptr_in, size_t n_bytes) {
305+
// check for pure allocation
306+
if (ptr_in == NULL) {
307+
return m_tracked_calloc(1, n_bytes);
308+
}
309+
// check for pure free
310+
if (n_bytes == 0) {
311+
m_tracked_free(ptr_in);
312+
return NULL;
313+
}
314+
m_tracked_node_t *node = (m_tracked_node_t *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t));
315+
#if MICROPY_MALLOC_USES_ALLOCATED_SIZE || MICROPY_DEBUG_VERBOSE
316+
size_t prev_bytes;
317+
prev_bytes = get_tracked_node_size(node);
318+
#if MICROPY_DEBUG_VERBOSE
319+
size_t nb;
320+
size_t n = m_tracked_count_links(&nb);
321+
DEBUG_printf("m_tracked_realloc(%p, [%p, %p], pbytes=%u, nbytes=%u, links=%u;%u)\n", node, node->prev, node->next, (int)prev_bytes, (int)n_bytes, (int)n, (int)nb);
322+
#endif
323+
#endif
324+
node = m_realloc(node,
325+
#if MICROPY_MALLOC_USES_ALLOCATED_SIZE
326+
sizeof(m_tracked_node_t) + prev_bytes,
327+
#endif
328+
sizeof(m_tracked_node_t) + n_bytes
329+
);
330+
// m_realloc raises on failure (never returns NULL), so no error handling needed.
331+
#if MICROPY_TRACKED_ALLOC_STORE_SIZE
332+
node->size = n_bytes;
333+
#endif
334+
m_tracked_node_lock();
335+
if (node->next != NULL) {
336+
node->next->prev = node;
337+
}
338+
if (node->prev != NULL) {
339+
node->prev->next = node;
340+
} else {
341+
MP_STATE_VM(m_tracked_head) = node;
342+
}
343+
m_tracked_node_unlock();
344+
return &node->data[0];
345+
}
346+
295347
void m_tracked_free(void *ptr_in) {
296348
if (ptr_in == NULL) {
297349
return;
298350
}
299351
m_tracked_node_t *node = (m_tracked_node_t *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t));
300352
#if MICROPY_DEBUG_VERBOSE
301353
size_t data_bytes;
302-
#if MICROPY_TRACKED_ALLOC_STORE_SIZE
303-
data_bytes = node->size;
304-
#else
305-
data_bytes = gc_nbytes(node);
306-
#endif
354+
data_bytes = get_tracked_node_size(node);
307355
size_t nb;
308356
size_t n = m_tracked_count_links(&nb);
309357
DEBUG_printf("m_tracked_free(%p, [%p, %p], nbytes=%u, links=%u;%u)\n", node, node->prev, node->next, (int)data_bytes, (int)n, (int)nb);

py/misc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ MP_NORETURN void m_malloc_fail(size_t num_bytes);
137137
// These alloc/free functions track the pointers in a linked list so the GC does not reclaim
138138
// them. They can be used by code that requires traditional C malloc/free semantics.
139139
void *m_tracked_calloc(size_t nmemb, size_t size);
140+
void *m_tracked_realloc(void *ptr_in, size_t n_bytes);
140141
void m_tracked_free(void *ptr_in);
141142
#endif
142143

tests/ports/unix/extra_coverage.py.exp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ m_tracked_head = 0
4545
5 1
4646
6 1
4747
7 1
48+
1
4849
0 1
4950
1 1
5051
2 1

tests/run-tests.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,10 @@ def main():
13821382
run-tests.py -i async - exclude all, then include tests containing "async" anywhere
13831383
run-tests.py -e '/big.+int' - include all, then exclude by regex
13841384
run-tests.py -e async -i async_foo - include all, exclude async, yet still include async_foo
1385+
1386+
For tests that use cpython, unix micropython and mpy-cross, the default executables
1387+
vcan be overridden with the environment variables MICROPY_CPYTHON3, MICROPY_MICROPYTHON and
1388+
MICROPY_MPYCROSS respectively.
13851389
""",
13861390
)
13871391
cmd_parser.add_argument(

0 commit comments

Comments
 (0)