From 10cffdfbd5d2c46079368adf0b7aeb1e4b1e8e7a Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 28 Dec 2025 18:06:29 +0100 Subject: [PATCH] test(espcoredump): fix test for corrupted TCB handling in coredump --- tools/test_apps/system/panic/CMakeLists.txt | 6 +----- .../test_apps/system/panic/main/test_panic.c | 17 +++++++++++---- tools/test_apps/system/panic/pytest_panic.py | 21 ++++++++++++++----- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/tools/test_apps/system/panic/CMakeLists.txt b/tools/test_apps/system/panic/CMakeLists.txt index 5eced74c454..faafff77bf0 100644 --- a/tools/test_apps/system/panic/CMakeLists.txt +++ b/tools/test_apps/system/panic/CMakeLists.txt @@ -22,7 +22,7 @@ if(CONFIG_TEST_MEMPROT) endif() endif() -if(NOT CONFIG_TEST_MEMPROT AND NOT CONFIG_ESP_COREDUMP_CAPTURE_DRAM) +if(NOT CONFIG_TEST_MEMPROT AND NOT CONFIG_ESP_COREDUMP_ENABLE) # Enable UBSAN checks # # shift-base sanitizer is disabled due to the following pattern found in register header files: @@ -40,10 +40,6 @@ if(NOT CONFIG_TEST_MEMPROT AND NOT CONFIG_ESP_COREDUMP_CAPTURE_DRAM) set(ubsan_components main esp_system spi_flash esp_common esp_hw_support soc hal freertos) - if(CONFIG_ESP_COREDUMP_ENABLE AND NOT CONFIG_IDF_TARGET_ESP32S2) - list(APPEND ubsan_components espcoredump) - endif() - if(CONFIG_IDF_TARGET_ESP32S2) # due to the ram limitation, freertos is removed from esp32s2 built list(REMOVE_ITEM ubsan_components freertos) diff --git a/tools/test_apps/system/panic/main/test_panic.c b/tools/test_apps/system/panic/main/test_panic.c index d3fe573b856..bdc3c00a49a 100644 --- a/tools/test_apps/system/panic/main/test_panic.c +++ b/tools/test_apps/system/panic/main/test_panic.c @@ -355,10 +355,19 @@ void test_coredump_summary(void) void test_tcb_corrupted(void) { - uint32_t volatile *tcb_ptr = (uint32_t *)xTaskGetIdleTaskHandleForCore(0); - for (size_t i = 0; i < sizeof(StaticTask_t) / sizeof(uint32_t); i++) { - tcb_ptr[i] = 0xDEADBEE0; - } + StaticTask_t *tcb = (StaticTask_t *)xTaskGetIdleTaskHandleForCore(0); + + // Corrupt critical fields that are read by xTaskGetNext() and vTaskGetSnapshot(). + tcb->pxDummy1 = (void *)0xDEADBEE0; // pxTopOfStack + tcb->xDummy3[0].pvDummy3[0] = (void *)0xDEADBEE1; // xStateListItem.pxNext + tcb->xDummy3[0].pvDummy3[1] = (void *)0xDEADBEE2; // xStateListItem.pxPrevious + tcb->xDummy3[0].pvDummy3[2] = (void *)0xDEADBEE3; // xStateListItem.pvOwner + tcb->pxDummy6 = (void *)0xDEADBEE6; // pxStack +#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) + tcb->pxDummy8 = (void *)0xDEADBEE8; // pxEndOfStack +#endif + + // Trigger a context switch. vTaskDelay(2); } diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index 01b0cf29995..c5d44032fd1 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -43,6 +43,18 @@ CONFIGS = list( ) ) +CONFIGS_UBSAN = list( + itertools.chain( + itertools.product( + [ + 'gdbstub', + 'panic', + ], + TARGETS_ALL, + ) + ) +) + CONFIG_PANIC = list(itertools.chain(itertools.product(['panic'], ['supported_targets']))) CONFIG_PANIC_DUAL_CORE = list(itertools.chain(itertools.product(['panic'], TARGETS_DUAL_CORE))) CONFIG_PANIC_HALT = list(itertools.chain(itertools.product(['panic_halt'], TARGETS_ALL))) @@ -464,7 +476,7 @@ def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None: @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@idf_parametrize('config, target', CONFIGS_UBSAN, indirect=['config', 'target']) def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) regex_pattern = rb'Undefined behavior of type out_of_bounds' @@ -476,7 +488,6 @@ def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.expect_elf_sha256() dut.expect_none(['Guru Meditation', 'Re-entered core dump']) - coredump_pattern = re.compile(PANIC_ABORT_PREFIX + regex_pattern.decode('utf-8')) common_test( dut, config, @@ -487,7 +498,6 @@ def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None: '__ubsan_handle_out_of_bounds', ] + get_default_backtrace(test_func_name), - expected_coredump=[coredump_pattern], ) @@ -1344,17 +1354,18 @@ def test_coredump_summary_flash_encrypted(dut: PanicTestDut, config: str) -> Non def test_tcb_corrupted(dut: PanicTestDut, target: str, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) if dut.is_xtensa: - dut.expect_gme('LoadProhibited') + dut.expect(re.compile(rb"Guru Meditation Error: Core\s+\d\s+panic'ed \((LoadProhibited|StoreProhibited)\)")) dut.expect_reg_dump() dut.expect_backtrace() else: - dut.expect_gme('Load access fault') + dut.expect(re.compile(rb"Guru Meditation Error: Core\s+\d\s+panic'ed \((Load|Store) access fault\)")) dut.expect_reg_dump() dut.expect_stack_dump() dut.expect_elf_sha256() dut.expect_none('Guru Meditation') + # Verify that valid tasks are captured in coredump despite IDLE task corruption # TCB NAME # ---------- ---------------- if dut.is_multi_core: