Skip to content

Commit a987a90

Browse files
committed
tests/ports/unix: Add backward traversal test for tracked realloc.
Verifies that prev pointers in the tracked allocation doubly-linked list are correctly maintained after reallocs by walking backward from tail. Signed-off-by: Andrew Leech <[email protected]>
1 parent 6a40372 commit a987a90

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

ports/unix/coverage.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@
2020
#include "py/binary.h"
2121
#include "py/bc.h"
2222

23+
// Forward declaration for tracked allocation testing
24+
typedef struct _m_tracked_node_t {
25+
struct _m_tracked_node_t *prev;
26+
struct _m_tracked_node_t *next;
27+
#if !MICROPY_ENABLE_GC
28+
uintptr_t size;
29+
#endif
30+
uint8_t data[];
31+
} m_tracked_node_t;
32+
2333
// expected output of this file is found in extra_coverage.py.exp
2434

2535
#if defined(MICROPY_UNIX_COVERAGE)
@@ -368,6 +378,87 @@ static mp_obj_t extra_coverage(void) {
368378
}
369379

370380
mp_printf(&mp_plat_print, "m_tracked_head = %p\n", MP_STATE_VM(m_tracked_head));
381+
382+
// Test realloc at head/tail of list (exercises NULL prev/next handling)
383+
mp_printf(&mp_plat_print, "# tracked realloc list positions\n");
384+
385+
// Allocate 3 nodes to create a list
386+
uint8_t *nodes[3];
387+
for (int i = 0; i < 3; ++i) {
388+
nodes[i] = m_tracked_calloc(1, 32);
389+
nodes[i][0] = 'A' + i; // Mark each with A, B, C
390+
}
391+
392+
// Verify initial list has 3 items (head should be nodes[2], the last allocated)
393+
int count = 0;
394+
for (m_tracked_node_t *n = MP_STATE_VM(m_tracked_head); n != NULL; n = n->next) {
395+
++count;
396+
}
397+
mp_printf(&mp_plat_print, "list count: %d\n", count);
398+
399+
// Realloc the tail (first allocated, nodes[0]) - tests next==NULL case
400+
nodes[0] = m_tracked_realloc(nodes[0], 64);
401+
mp_printf(&mp_plat_print, "tail realloc marker: %c\n", nodes[0][0]);
402+
403+
// Realloc the head (last allocated, nodes[2]) - tests prev==NULL case
404+
nodes[2] = m_tracked_realloc(nodes[2], 64);
405+
mp_printf(&mp_plat_print, "head realloc marker: %c\n", nodes[2][0]);
406+
407+
// Realloc middle node - tests both prev and next non-NULL
408+
nodes[1] = m_tracked_realloc(nodes[1], 64);
409+
mp_printf(&mp_plat_print, "middle realloc marker: %c\n", nodes[1][0]);
410+
411+
// Verify list still has 3 items and is traversable
412+
count = 0;
413+
for (m_tracked_node_t *n = MP_STATE_VM(m_tracked_head); n != NULL; n = n->next) {
414+
++count;
415+
}
416+
mp_printf(&mp_plat_print, "list count after reallocs: %d\n", count);
417+
418+
// Verify backward traversal (prev pointers correct)
419+
// Find tail by walking forward
420+
m_tracked_node_t *tail = MP_STATE_VM(m_tracked_head);
421+
while (tail != NULL && tail->next != NULL) {
422+
tail = tail->next;
423+
}
424+
// Walk backward and count
425+
count = 0;
426+
for (m_tracked_node_t *n = tail; n != NULL; n = n->prev) {
427+
++count;
428+
}
429+
mp_printf(&mp_plat_print, "backward traversal count: %d\n", count);
430+
431+
// Test pure allocation via realloc (NULL ptr)
432+
uint8_t *new_alloc = m_tracked_realloc(NULL, 32);
433+
new_alloc[0] = 'X';
434+
mp_printf(&mp_plat_print, "realloc(NULL) marker: %c\n", new_alloc[0]);
435+
436+
// Test pure free via realloc (size 0)
437+
void *result = m_tracked_realloc(new_alloc, 0);
438+
mp_printf(&mp_plat_print, "realloc(ptr, 0) result: %d\n", result == NULL ? 1 : 0);
439+
440+
// Test shrinking realloc (64->32) - may return same pointer
441+
nodes[1] = m_tracked_realloc(nodes[1], 32);
442+
mp_printf(&mp_plat_print, "shrink realloc marker: %c\n", nodes[1][0]);
443+
444+
// Clean up - free in reverse order to stress list operations
445+
for (int i = 2; i >= 0; --i) {
446+
m_tracked_free(nodes[i]);
447+
}
448+
449+
// Test single-node list realloc (prev==NULL && next==NULL simultaneously)
450+
uint8_t *single = m_tracked_calloc(1, 32);
451+
single[0] = 'S';
452+
single = m_tracked_realloc(single, 64);
453+
mp_printf(&mp_plat_print, "single node realloc marker: %c\n", single[0]);
454+
count = 0;
455+
for (m_tracked_node_t *n = MP_STATE_VM(m_tracked_head); n != NULL; n = n->next) {
456+
++count;
457+
}
458+
mp_printf(&mp_plat_print, "single node list count: %d\n", count);
459+
m_tracked_free(single);
460+
461+
mp_printf(&mp_plat_print, "m_tracked_head after cleanup: %p\n", MP_STATE_VM(m_tracked_head));
371462
}
372463

373464
// vstr

tests/ports/unix/extra_coverage.py.exp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,19 @@ m_tracked_head = 0
5555
6 1
5656
7 1
5757
m_tracked_head = 0
58+
# tracked realloc list positions
59+
list count: 3
60+
tail realloc marker: A
61+
head realloc marker: C
62+
middle realloc marker: B
63+
list count after reallocs: 3
64+
backward traversal count: 3
65+
realloc(NULL) marker: X
66+
realloc(ptr, 0) result: 1
67+
shrink realloc marker: B
68+
single node realloc marker: S
69+
single node list count: 1
70+
m_tracked_head after cleanup: 0
5871
# vstr
5972
tests
6073
sts

0 commit comments

Comments
 (0)