mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-26 02:37:01 +08:00
fix(cache): align node size to avoid unaligned access runtime errors (#9913)
This commit is contained in:
Vendored
+12
-7
@@ -10,11 +10,14 @@
|
||||
#include "../../stdlib/lv_sprintf.h"
|
||||
#include "../lv_assert.h"
|
||||
#include "lv_cache_entry_private.h"
|
||||
#include "../../misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_CACHE_ENTRY_ALIGN_NODE_SIZE(size) (LV_ALIGN_UP(size, sizeof(void *)))
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
@@ -87,7 +90,8 @@ bool lv_cache_entry_is_invalid(lv_cache_entry_t * entry)
|
||||
void * lv_cache_entry_get_data(lv_cache_entry_t * entry)
|
||||
{
|
||||
LV_ASSERT_NULL(entry);
|
||||
return (uint8_t *)entry - entry->node_size;
|
||||
|
||||
return (uint8_t *)entry - LV_CACHE_ENTRY_ALIGN_NODE_SIZE(entry->node_size);
|
||||
}
|
||||
|
||||
void * lv_cache_entry_acquire_data(lv_cache_entry_t * entry)
|
||||
@@ -114,7 +118,7 @@ void lv_cache_entry_release_data(lv_cache_entry_t * entry, void * user_data)
|
||||
lv_cache_entry_t * lv_cache_entry_get_entry(void * data, const uint32_t node_size)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return (lv_cache_entry_t *)((uint8_t *)data + node_size);
|
||||
return (lv_cache_entry_t *)((uint8_t *)data + LV_CACHE_ENTRY_ALIGN_NODE_SIZE(node_size));
|
||||
}
|
||||
|
||||
void lv_cache_entry_set_cache(lv_cache_entry_t * entry, const lv_cache_t * cache)
|
||||
@@ -131,23 +135,24 @@ const lv_cache_t * lv_cache_entry_get_cache(const lv_cache_entry_t * entry)
|
||||
|
||||
uint32_t lv_cache_entry_get_size(const uint32_t node_size)
|
||||
{
|
||||
return node_size + sizeof(lv_cache_entry_t);
|
||||
return LV_CACHE_ENTRY_ALIGN_NODE_SIZE(node_size) + sizeof(lv_cache_entry_t);
|
||||
}
|
||||
|
||||
lv_cache_entry_t * lv_cache_entry_alloc(const uint32_t node_size, const lv_cache_t * cache)
|
||||
lv_cache_entry_t * lv_cache_entry_alloc(uint32_t node_size, const lv_cache_t * cache)
|
||||
{
|
||||
/* Align node_size so that accessing the entry data afterwards is done on an aligned byte address */
|
||||
void * res = lv_malloc_zeroed(lv_cache_entry_get_size(node_size));
|
||||
LV_ASSERT_MALLOC(res)
|
||||
if(res == NULL) {
|
||||
if(!res) {
|
||||
LV_LOG_ERROR("malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
lv_cache_entry_t * entry = (lv_cache_entry_t *)((uint8_t *)res + node_size);
|
||||
lv_cache_entry_t * entry = (lv_cache_entry_t *)((uint8_t *)res + LV_CACHE_ENTRY_ALIGN_NODE_SIZE(node_size));
|
||||
lv_cache_entry_init(entry, cache, node_size);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void lv_cache_entry_init(lv_cache_entry_t * entry, const lv_cache_t * cache, const uint32_t node_size)
|
||||
void lv_cache_entry_init(lv_cache_entry_t * entry, const lv_cache_t * cache, uint32_t node_size)
|
||||
{
|
||||
LV_ASSERT_NULL(entry);
|
||||
LV_ASSERT_NULL(cache);
|
||||
|
||||
+40
@@ -320,5 +320,45 @@ void test_cache_entry_alloc(void)
|
||||
lv_cache_entry_delete(entry);
|
||||
lv_cache_destroy(cache, NULL);
|
||||
}
|
||||
void test_cache_entry_alloc_unaligned_node_size(void)
|
||||
{
|
||||
const uint32_t unaligned_sizes[] = { 3, 13 };
|
||||
|
||||
for(size_t s = 0; s < sizeof(unaligned_sizes) / sizeof(unaligned_sizes[0]); ++s) {
|
||||
uint32_t node_size = unaligned_sizes[s];
|
||||
|
||||
lv_cache_t * cache = create_cache(&lv_cache_class_lru_rb_size, CACHE_SIZE_BYTES);
|
||||
TEST_ASSERT_NOT_NULL(cache);
|
||||
|
||||
lv_cache_entry_t * entry = lv_cache_entry_alloc(node_size, cache);
|
||||
TEST_ASSERT_NOT_NULL(entry);
|
||||
|
||||
TEST_ASSERT_EQUAL_MESSAGE(
|
||||
0, ((uintptr_t)entry) % sizeof(void *),
|
||||
"lv_cache_entry_t * must be pointer-aligned regardless of node_size");
|
||||
|
||||
void * data = lv_cache_entry_get_data(entry);
|
||||
TEST_ASSERT_NOT_NULL(data);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(
|
||||
0, ((uintptr_t)data) % sizeof(void *),
|
||||
"lv_cache_entry_get_data() must be pointer-aligned regardless of node_size");
|
||||
|
||||
lv_cache_entry_t * roundtripped = lv_cache_entry_get_entry(data, node_size);
|
||||
TEST_ASSERT_EQUAL_PTR_MESSAGE(
|
||||
entry, roundtripped,
|
||||
"lv_cache_entry_get_entry(lv_cache_entry_get_data(e), node_size) "
|
||||
"must recover the original entry pointer");
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
||||
node_size, lv_cache_entry_get_node_size(entry),
|
||||
"get_node_size() must return the original unaligned node_size");
|
||||
|
||||
TEST_ASSERT_TRUE_MESSAGE(
|
||||
(uintptr_t)data < (uintptr_t)entry,
|
||||
"data pointer must lie before the entry header in the allocation block");
|
||||
|
||||
lv_cache_entry_delete(entry);
|
||||
lv_cache_destroy(cache, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user