mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-08 12:46:14 +00:00
Add compilation flag to enable/disable heap corruption check (#2766)
Heap corruption check in ems memory allocator is enabled by default to improve the security, but it may impact the performance a lot, this PR adds cmake variable and compiler flag to enable/disable it.
This commit is contained in:
parent
fc03bc073e
commit
40d33d806b
|
@ -315,6 +315,11 @@
|
|||
#define BH_ENABLE_GC_VERIFY 0
|
||||
#endif
|
||||
|
||||
/* Heap corruption check, enabled by default */
|
||||
#ifndef BH_ENABLE_GC_CORRUPTION_CHECK
|
||||
#define BH_ENABLE_GC_CORRUPTION_CHECK 1
|
||||
#endif
|
||||
|
||||
/* Enable global heap pool if heap verification is enabled */
|
||||
#if BH_ENABLE_GC_VERIFY != 0
|
||||
#define WASM_ENABLE_GLOBAL_HEAP_POOL 1
|
||||
|
|
|
@ -24,19 +24,23 @@ hmu_is_in_heap(void *hmu, gc_uint8 *heap_base_addr, gc_uint8 *heap_end_addr)
|
|||
static bool
|
||||
remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
|
||||
{
|
||||
hmu_tree_node_t *q = NULL, **slot = NULL, *parent;
|
||||
hmu_tree_node_t *root = heap->kfc_tree_root;
|
||||
hmu_tree_node_t *q = NULL, **slot = NULL;
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
hmu_tree_node_t *root = heap->kfc_tree_root, *parent;
|
||||
gc_uint8 *base_addr = heap->base_addr;
|
||||
gc_uint8 *end_addr = base_addr + heap->current_size;
|
||||
#endif
|
||||
|
||||
bh_assert(p);
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
parent = p->parent;
|
||||
if (!parent || p == root /* p can not be the ROOT node */
|
||||
|| !hmu_is_in_heap(p, base_addr, end_addr)
|
||||
|| (parent != root && !hmu_is_in_heap(parent, base_addr, end_addr))) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* get the slot which holds pointer to node p */
|
||||
if (p == p->parent->right) {
|
||||
|
@ -67,9 +71,11 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
|
|||
/* move right child up*/
|
||||
*slot = p->right;
|
||||
if (p->right) {
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(p->right, base_addr, end_addr)) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
p->right->parent = p->parent;
|
||||
}
|
||||
|
||||
|
@ -80,9 +86,11 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
|
|||
if (!p->right) {
|
||||
/* move left child up*/
|
||||
*slot = p->left;
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(p->left, base_addr, end_addr)) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
/* p->left can never be NULL unless it is corrupted. */
|
||||
p->left->parent = p->parent;
|
||||
|
||||
|
@ -92,14 +100,18 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
|
|||
|
||||
/* both left & right exist, find p's predecessor at first*/
|
||||
q = p->left;
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(q, base_addr, end_addr)) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
while (q->right) {
|
||||
q = q->right;
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(q, base_addr, end_addr)) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* remove from the tree*/
|
||||
|
@ -111,15 +123,19 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
|
|||
q->left = p->left;
|
||||
q->right = p->right;
|
||||
if (q->left) {
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(q->left, base_addr, end_addr)) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
q->left->parent = q;
|
||||
}
|
||||
if (q->right) {
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(q->right, base_addr, end_addr)) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
q->right->parent = q;
|
||||
}
|
||||
|
||||
|
@ -127,27 +143,35 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
|
|||
|
||||
return true;
|
||||
fail:
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
heap->is_heap_corrupted = true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
unlink_hmu(gc_heap_t *heap, hmu_t *hmu)
|
||||
{
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
gc_uint8 *base_addr, *end_addr;
|
||||
#endif
|
||||
gc_size_t size;
|
||||
|
||||
bh_assert(gci_is_heap_valid(heap));
|
||||
bh_assert(hmu && (gc_uint8 *)hmu >= heap->base_addr
|
||||
&& (gc_uint8 *)hmu < heap->base_addr + heap->current_size);
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (hmu_get_ut(hmu) != HMU_FC) {
|
||||
heap->is_heap_corrupted = true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
base_addr = heap->base_addr;
|
||||
end_addr = base_addr + heap->current_size;
|
||||
#endif
|
||||
size = hmu_get_size(hmu);
|
||||
|
||||
if (HMU_IS_FC_NORMAL(size)) {
|
||||
|
@ -156,10 +180,12 @@ unlink_hmu(gc_heap_t *heap, hmu_t *hmu)
|
|||
hmu_normal_node_t *node = heap->kfc_normal_list[node_idx].next;
|
||||
|
||||
while (node) {
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(node, base_addr, end_addr)) {
|
||||
heap->is_heap_corrupted = true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
node_next = get_hmu_normal_node_next(node);
|
||||
if ((hmu_t *)node == hmu) {
|
||||
if (!node_prev) /* list head */
|
||||
|
@ -205,7 +231,9 @@ hmu_set_free_size(hmu_t *hmu)
|
|||
bool
|
||||
gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
|
||||
{
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
gc_uint8 *base_addr, *end_addr;
|
||||
#endif
|
||||
hmu_normal_node_t *np = NULL;
|
||||
hmu_tree_node_t *root = NULL, *tp = NULL, *node = NULL;
|
||||
uint32 node_idx;
|
||||
|
@ -219,8 +247,10 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
|
|||
<= heap->base_addr + heap->current_size);
|
||||
bh_assert(!(size & 7));
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
base_addr = heap->base_addr;
|
||||
end_addr = base_addr + heap->current_size;
|
||||
#endif
|
||||
|
||||
hmu_set_ut(hmu, HMU_FC);
|
||||
hmu_set_size(hmu, size);
|
||||
|
@ -228,10 +258,12 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
|
|||
|
||||
if (HMU_IS_FC_NORMAL(size)) {
|
||||
np = (hmu_normal_node_t *)hmu;
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(np, base_addr, end_addr)) {
|
||||
heap->is_heap_corrupted = true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
node_idx = size >> 3;
|
||||
set_hmu_normal_node_next(np, heap->kfc_normal_list[node_idx].next);
|
||||
|
@ -265,10 +297,12 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
|
|||
}
|
||||
tp = tp->left;
|
||||
}
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(tp, base_addr, end_addr)) {
|
||||
heap->is_heap_corrupted = true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -321,15 +355,19 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size)
|
|||
bh_assert(node_idx >= init_node_idx);
|
||||
|
||||
p = normal_head->next;
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(p, base_addr, end_addr)) {
|
||||
heap->is_heap_corrupted = true;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
normal_head->next = get_hmu_normal_node_next(p);
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (((gc_int32)(uintptr_t)hmu_to_obj(p) & 7) != 0) {
|
||||
heap->is_heap_corrupted = true;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((gc_size_t)node_idx != (uint32)init_node_idx
|
||||
/* with bigger size*/
|
||||
|
@ -365,10 +403,12 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size)
|
|||
bh_assert(root);
|
||||
tp = root->right;
|
||||
while (tp) {
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (!hmu_is_in_heap(tp, base_addr, end_addr)) {
|
||||
heap->is_heap_corrupted = true;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tp->size < size) {
|
||||
tp = tp->right;
|
||||
|
@ -462,10 +502,12 @@ gc_alloc_vo_internal(void *vheap, gc_size_t size, const char *file, int line)
|
|||
/* integer overflow */
|
||||
return NULL;
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (heap->is_heap_corrupted) {
|
||||
os_printf("[GC_ERROR]Heap is corrupted, allocate memory failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
os_mutex_lock(&heap->lock);
|
||||
|
||||
|
@ -522,10 +564,12 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, const char *file,
|
|||
/* integer overflow */
|
||||
return NULL;
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (heap->is_heap_corrupted) {
|
||||
os_printf("[GC_ERROR]Heap is corrupted, allocate memory failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (obj_old) {
|
||||
hmu_old = obj_to_hmu(obj_old);
|
||||
|
@ -647,10 +691,12 @@ gc_free_vo_internal(void *vheap, gc_object_t obj, const char *file, int line)
|
|||
return GC_SUCCESS;
|
||||
}
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (heap->is_heap_corrupted) {
|
||||
os_printf("[GC_ERROR]Heap is corrupted, free memory failed.\n");
|
||||
return GC_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
hmu = obj_to_hmu(obj);
|
||||
|
||||
|
@ -767,11 +813,13 @@ gci_dump(gc_heap_t *heap)
|
|||
else if (ut == HMU_FC)
|
||||
inuse = 'F';
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (size == 0 || size > (uint32)((uint8 *)end - (uint8 *)cur)) {
|
||||
os_printf("[GC_ERROR]Heap is corrupted, heap dump failed.\n");
|
||||
heap->is_heap_corrupted = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
os_printf("#%d %08" PRIx32 " %" PRIx32 " %d %d"
|
||||
" %c %" PRId32 "\n",
|
||||
|
@ -788,8 +836,12 @@ gci_dump(gc_heap_t *heap)
|
|||
i++;
|
||||
}
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (cur != end) {
|
||||
os_printf("[GC_ERROR]Heap is corrupted, heap dump failed.\n");
|
||||
heap->is_heap_corrupted = true;
|
||||
}
|
||||
#else
|
||||
bh_assert(cur == end);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -271,9 +271,11 @@ typedef struct gc_heap_struct {
|
|||
size[left] <= size[cur] < size[right] */
|
||||
hmu_tree_node_t *kfc_tree_root;
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
/* whether heap is corrupted, e.g. the hmu nodes are modified
|
||||
by user */
|
||||
bool is_heap_corrupted;
|
||||
#endif
|
||||
|
||||
gc_size_t init_size;
|
||||
gc_size_t highmark_size;
|
||||
|
|
|
@ -83,7 +83,9 @@ hmu_verify(void *vheap, hmu_t *hmu)
|
|||
os_printf("Invalid padding for object created at %s:%d\n",
|
||||
(prefix->file_name ? prefix->file_name : ""),
|
||||
prefix->line_no);
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
heap->is_heap_corrupted = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,8 +133,11 @@ gc_destroy_with_pool(gc_handle_t handle)
|
|||
hmu_t *cur = (hmu_t *)heap->base_addr;
|
||||
hmu_t *end = (hmu_t *)((char *)heap->base_addr + heap->current_size);
|
||||
|
||||
if (!heap->is_heap_corrupted
|
||||
&& (hmu_t *)((char *)cur + hmu_get_size(cur)) != end) {
|
||||
if (
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
!heap->is_heap_corrupted &&
|
||||
#endif
|
||||
(hmu_t *)((char *)cur + hmu_get_size(cur)) != end) {
|
||||
os_printf("Memory leak detected:\n");
|
||||
gci_dump(heap);
|
||||
ret = GC_ERROR;
|
||||
|
@ -186,10 +189,12 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size)
|
|||
if (offset == 0)
|
||||
return 0;
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (heap->is_heap_corrupted) {
|
||||
os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n");
|
||||
return GC_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
heap->base_addr = (uint8 *)base_addr_new;
|
||||
|
||||
|
@ -211,11 +216,13 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size)
|
|||
while (cur < end) {
|
||||
size = hmu_get_size(cur);
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (size <= 0 || size > (uint32)((uint8 *)end - (uint8 *)cur)) {
|
||||
os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n");
|
||||
heap->is_heap_corrupted = true;
|
||||
return GC_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hmu_get_ut(cur) == HMU_FC && !HMU_IS_FC_NORMAL(size)) {
|
||||
tree_node = (hmu_tree_node_t *)cur;
|
||||
|
@ -238,11 +245,15 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size)
|
|||
cur = (hmu_t *)((char *)cur + size);
|
||||
}
|
||||
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
if (cur != end) {
|
||||
os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n");
|
||||
heap->is_heap_corrupted = true;
|
||||
return GC_ERROR;
|
||||
}
|
||||
#else
|
||||
bh_assert(cur == end);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -250,9 +261,13 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size)
|
|||
bool
|
||||
gc_is_heap_corrupted(gc_handle_t handle)
|
||||
{
|
||||
#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
|
||||
gc_heap_t *heap = (gc_heap_t *)handle;
|
||||
|
||||
return heap->is_heap_corrupted ? true : false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BH_ENABLE_GC_VERIFY != 0
|
||||
|
|
|
@ -10,6 +10,14 @@ if (WAMR_BUILD_GC_VERIFY EQUAL 1)
|
|||
add_definitions (-DBH_ENABLE_GC_VERIFY=1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_GC_CORRUPTION_CHECK)
|
||||
set (WAMR_BUILD_GC_CORRUPTION_CHECK 1)
|
||||
endif ()
|
||||
|
||||
if (WAMR_BUILD_GC_CORRUPTION_CHECK EQUAL 0)
|
||||
add_definitions (-DBH_ENABLE_GC_CORRUPTION_CHECK=0)
|
||||
endif ()
|
||||
|
||||
file (GLOB_RECURSE source_all
|
||||
${MEM_ALLOC_DIR}/ems/*.c
|
||||
${MEM_ALLOC_DIR}/tlsf/*.c
|
||||
|
|
Loading…
Reference in New Issue
Block a user