/* integrity check (UMM_INTEGRITY_CHECK) {{{ */ #ifdef UMM_INTEGRITY_CHECK #include #include /* * Perform integrity check of the whole heap data. Returns 1 in case of * success, 0 otherwise. * * First of all, iterate through all free blocks, and check that all backlinks * match (i.e. if block X has next free block Y, then the block Y should have * previous free block set to X). * * Additionally, we check that each free block is correctly marked with * `UMM_FREELIST_MASK` on the `next` pointer: during iteration through free * list, we mark each free block by the same flag `UMM_FREELIST_MASK`, but * on `prev` pointer. We'll check and unmark it later. * * Then, we iterate through all blocks in the heap, and similarly check that * all backlinks match (i.e. if block X has next block Y, then the block Y * should have previous block set to X). * * But before checking each backlink, we check that the `next` and `prev` * pointers are both marked with `UMM_FREELIST_MASK`, or both unmarked. * This way, we ensure that the free flag is in sync with the free pointers * chain. */ bool umm_integrity_check(void) { bool ok = true; uint16_t prev; uint16_t cur; UMM_CHECK_INITIALIZED(); /* Iterate through all free blocks */ prev = 0; while (1) { cur = UMM_NFREE(prev); /* Check that next free block number is valid */ if (cur >= UMM_NUMBLOCKS) { DBGLOG_CRITICAL("Heap integrity broken: too large next free num: %d " "(in block %d, addr 0x%08x)\n", cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev))); ok = false; goto clean; } if (cur == 0) { /* No more free blocks */ break; } /* Check if prev free block number matches */ if (UMM_PFREE(cur) != prev) { DBGLOG_CRITICAL("Heap integrity broken: free links don't match: " "%d -> %d, but %d -> %d\n", prev, cur, cur, UMM_PFREE(cur)); ok = false; goto clean; } UMM_PBLOCK(cur) |= UMM_FREELIST_MASK; prev = cur; } /* Iterate through all blocks */ prev = 0; while (1) { cur = UMM_NBLOCK(prev) & UMM_BLOCKNO_MASK; /* Check that next block number is valid */ if (cur >= UMM_NUMBLOCKS) { DBGLOG_CRITICAL("Heap integrity broken: too large next block num: %d " "(in block %d, addr 0x%08x)\n", cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev))); ok = false; goto clean; } if (cur == 0) { /* No more blocks */ break; } /* make sure the free mark is appropriate, and unmark it */ if ((UMM_NBLOCK(cur) & UMM_FREELIST_MASK) != (UMM_PBLOCK(cur) & UMM_FREELIST_MASK)) { DBGLOG_CRITICAL("Heap integrity broken: mask wrong at addr 0x%08x: n=0x%x, p=0x%x\n", DBGLOG_32_BIT_PTR(&UMM_NBLOCK(cur)), (UMM_NBLOCK(cur) & UMM_FREELIST_MASK), (UMM_PBLOCK(cur) & UMM_FREELIST_MASK)); ok = false; goto clean; } /* make sure the block list is sequential */ if (cur <= prev) { DBGLOG_CRITICAL("Heap integrity broken: next block %d is before prev this one " "(in block %d, addr 0x%08x)\n", cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev))); ok = false; goto clean; } /* unmark */ UMM_PBLOCK(cur) &= UMM_BLOCKNO_MASK; /* Check if prev block number matches */ if (UMM_PBLOCK(cur) != prev) { DBGLOG_CRITICAL("Heap integrity broken: block links don't match: " "%d -> %d, but %d -> %d\n", prev, cur, cur, UMM_PBLOCK(cur)); ok = false; goto clean; } prev = cur; } clean: if (!ok) { UMM_HEAP_CORRUPTION_CB(); } return ok; } #endif /* }}} */