Skip to content

Commit e02ab4d

Browse files
committed
fast-get: fix crash by freeing buffer before removing partition
Fix crash in fast_put() when freeing large buffers (>2048 bytes) by freeing the heap memory BEFORE removing the memory domain partition. The previous code removed the partition first, making the memory inaccessible to the current thread. When sof_heap_free() then tried to access the heap metadata, it caused a load prohibited exception. The fix reorders operations: 1. Free the buffer while partition still grants access 2. Remove the partition to prevent partition table leaks This crash manifested during pipeline deletion with 44.1kHz family sample rates (88200, 44100, etc.) which use large SRC coefficient buffers requiring userspace partition management. Fixes: b927092 ("fast-get: enable sharing between userspace threads") Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
1 parent 359584a commit e02ab4d

File tree

1 file changed

+28
-13
lines changed

1 file changed

+28
-13
lines changed

zephyr/lib/fast-get.c

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -279,21 +279,36 @@ void fast_put(struct k_heap *heap, const void *sram_ptr)
279279
}
280280
entry->refcount--;
281281

282+
if (!entry->refcount) {
282283
#if CONFIG_USERSPACE
283-
if (entry->size > FAST_GET_MAX_COPY_SIZE && entry->thread) {
284-
struct k_mem_partition part = {
285-
.start = (uintptr_t)entry->sram_ptr,
286-
.size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE),
287-
.attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB,
288-
};
289-
290-
LOG_DBG("remove %#zx @ %p", part.size, entry->sram_ptr);
291-
k_mem_domain_remove_partition(entry->thread->mem_domain_info.mem_domain, &part);
292-
}
293-
#endif
284+
/* For large buffers, we need to:
285+
* 1. Free the heap buffer FIRST (while partition still grants us access)
286+
* 2. Then remove the partition (to prevent partition leaks)
287+
* This order is critical - we must free while we still have access.
288+
*/
289+
if (entry->size > FAST_GET_MAX_COPY_SIZE) {
290+
struct k_mem_partition part;
291+
struct k_mem_domain *domain = entry->thread->mem_domain_info.mem_domain;
292+
void *addr = entry->sram_ptr;
293+
294+
sof_heap_free(heap, addr);
295+
296+
part.start = (uintptr_t)addr;
297+
part.size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE);
298+
part.attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB;
299+
300+
int err = k_mem_domain_remove_partition(domain, &part);
301+
302+
if (err < 0)
303+
LOG_WRN("partition removal failed err=%d", err);
304+
305+
} else
306+
#endif /* CONFIG_USERSPACE */
307+
{
308+
/* Small buffers have no partitions, just free */
309+
sof_heap_free(heap, entry->sram_ptr);
310+
}
294311

295-
if (!entry->refcount) {
296-
sof_heap_free(heap, entry->sram_ptr);
297312
memset(entry, 0, sizeof(*entry));
298313
}
299314
out:

0 commit comments

Comments
 (0)