SingingCat 0
application
umm_integrity.c
1/* integrity check (UMM_INTEGRITY_CHECK) {{{ */
2#ifdef UMM_INTEGRITY_CHECK
3
4#include <stdint.h>
5#include <stdbool.h>
6
7/*
8 * Perform integrity check of the whole heap data. Returns 1 in case of
9 * success, 0 otherwise.
10 *
11 * First of all, iterate through all free blocks, and check that all backlinks
12 * match (i.e. if block X has next free block Y, then the block Y should have
13 * previous free block set to X).
14 *
15 * Additionally, we check that each free block is correctly marked with
16 * `UMM_FREELIST_MASK` on the `next` pointer: during iteration through free
17 * list, we mark each free block by the same flag `UMM_FREELIST_MASK`, but
18 * on `prev` pointer. We'll check and unmark it later.
19 *
20 * Then, we iterate through all blocks in the heap, and similarly check that
21 * all backlinks match (i.e. if block X has next block Y, then the block Y
22 * should have previous block set to X).
23 *
24 * But before checking each backlink, we check that the `next` and `prev`
25 * pointers are both marked with `UMM_FREELIST_MASK`, or both unmarked.
26 * This way, we ensure that the free flag is in sync with the free pointers
27 * chain.
28 */
29bool umm_integrity_check(void) {
30 UMM_CRITICAL_DECL(id_integrity);
31 bool ok = true;
32 uint16_t prev;
33 uint16_t cur;
34
35 UMM_CHECK_INITIALIZED();
36
37 /* Iterate through all free blocks */
38 prev = 0;
39 UMM_CRITICAL_ENTRY(id_integrity);
40 while (1) {
41 cur = UMM_NFREE(prev);
42
43 /* Check that next free block number is valid */
44 if (cur >= UMM_NUMBLOCKS) {
45 DBGLOG_CRITICAL("Heap integrity broken: too large next free num: %d "
46 "(in block %d, addr 0x%08x)\n",
47 cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev)));
48 ok = false;
49 goto clean;
50 }
51 if (cur == 0) {
52 /* No more free blocks */
53 break;
54 }
55
56 /* Check if prev free block number matches */
57 if (UMM_PFREE(cur) != prev) {
58 DBGLOG_CRITICAL("Heap integrity broken: free links don't match: "
59 "%d -> %d, but %d -> %d\n",
60 prev, cur, cur, UMM_PFREE(cur));
61 ok = false;
62 goto clean;
63 }
64
65 UMM_PBLOCK(cur) |= UMM_FREELIST_MASK;
66
67 prev = cur;
68 }
69
70 /* Iterate through all blocks */
71 prev = 0;
72 while (1) {
73 cur = UMM_NBLOCK(prev) & UMM_BLOCKNO_MASK;
74
75 /* Check that next block number is valid */
76 if (cur >= UMM_NUMBLOCKS) {
77 DBGLOG_CRITICAL("Heap integrity broken: too large next block num: %d "
78 "(in block %d, addr 0x%08x)\n",
79 cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev)));
80 ok = false;
81 goto clean;
82 }
83 if (cur == 0) {
84 /* No more blocks */
85 break;
86 }
87
88 /* make sure the free mark is appropriate, and unmark it */
89 if ((UMM_NBLOCK(cur) & UMM_FREELIST_MASK)
90 != (UMM_PBLOCK(cur) & UMM_FREELIST_MASK)) {
91 DBGLOG_CRITICAL("Heap integrity broken: mask wrong at addr 0x%08x: n=0x%x, p=0x%x\n",
92 DBGLOG_32_BIT_PTR(&UMM_NBLOCK(cur)),
93 (UMM_NBLOCK(cur) & UMM_FREELIST_MASK),
94 (UMM_PBLOCK(cur) & UMM_FREELIST_MASK));
95 ok = false;
96 goto clean;
97 }
98
99 /* make sure the block list is sequential */
100 if (cur <= prev) {
101 DBGLOG_CRITICAL("Heap integrity broken: next block %d is before prev this one "
102 "(in block %d, addr 0x%08x)\n",
103 cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev)));
104 ok = false;
105 goto clean;
106 }
107
108/* unmark */
109 UMM_PBLOCK(cur) &= UMM_BLOCKNO_MASK;
110
111 /* Check if prev block number matches */
112 if (UMM_PBLOCK(cur) != prev) {
113 DBGLOG_CRITICAL("Heap integrity broken: block links don't match: "
114 "%d -> %d, but %d -> %d\n",
115 prev, cur, cur, UMM_PBLOCK(cur));
116 ok = false;
117 goto clean;
118 }
119
120 prev = cur;
121 }
122
123clean:
124 UMM_CRITICAL_EXIT(id_integrity);
125 if (!ok) {
126 UMM_HEAP_CORRUPTION_CB();
127 }
128 return ok;
129}
130
131#endif
132/* }}} */