| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /*
- * Copyright (c) 2006-2025, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2025-09-01 Rbb666 add stack overflow test
- */
- #include <rtthread.h>
- #include "utest.h"
- #define UTEST_NAME "thread_overflow_tc"
- #define TEST_STACK_SIZE 512
- /* Test thread stack overflow */
- static rt_thread_t test_thread = RT_NULL;
- static rt_thread_t fake_thread = RT_NULL; /* Dynamic fake thread */
- static volatile rt_bool_t overflow_detected = RT_FALSE;
- static volatile rt_bool_t test_completed = RT_FALSE;
- /* Stack overflow detection hook - returns RT_EOK to continue, other values to halt */
- static rt_err_t stack_overflow_hook(struct rt_thread *thread)
- {
- rt_kprintf("Stack overflow hook called for thread: %s\n", thread->parent.name);
- overflow_detected = RT_TRUE;
- /* Return RT_EOK to indicate overflow has been handled successfully */
- return RT_EOK;
- }
- /* Test stack usage calculation */
- static void stack_usage_test(void)
- {
- rt_thread_t current_thread;
- rt_uint32_t total_stack, used_stack;
- current_thread = rt_thread_self();
- uassert_not_null(current_thread);
- /* Get stack information */
- total_stack = current_thread->stack_size;
- rt_kprintf("Thread: %s\n", current_thread->parent.name);
- rt_kprintf("Stack addr: 0x%p\n", current_thread->stack_addr);
- rt_kprintf("Stack size: %d bytes\n", total_stack);
- rt_kprintf("Current SP: 0x%p\n", current_thread->sp);
- #ifdef ARCH_CPU_STACK_GROWS_UPWARD
- /* For upward growing stacks */
- used_stack = (rt_uint32_t)current_thread->sp - (rt_uint32_t)current_thread->stack_addr;
- #else
- /* For downward growing stacks (most common) */
- used_stack = (rt_uint32_t)current_thread->stack_addr + total_stack - (rt_uint32_t)current_thread->sp;
- #endif
- rt_kprintf("Used stack: %d bytes (%d%%)\n",
- used_stack,
- (used_stack * 100) / total_stack);
- /* Verify stack usage is reasonable */
- uassert_true(used_stack > 0);
- uassert_true(used_stack < total_stack);
- /* Check magic number at stack boundary */
- #ifdef ARCH_CPU_STACK_GROWS_UPWARD
- /* Check magic at the end for upward growing */
- if (*((rt_uint8_t *)((rt_uintptr_t)current_thread->stack_addr + total_stack - 1)) == '#')
- {
- rt_kprintf("Stack magic number intact at top\n");
- uassert_true(RT_TRUE);
- }
- else
- {
- rt_kprintf("Stack magic number corrupted at top\n");
- uassert_true(RT_FALSE);
- }
- #else
- /* Check magic at the beginning for downward growing */
- if (*((rt_uint8_t *)current_thread->stack_addr) == '#')
- {
- rt_kprintf("Stack magic number intact at bottom\n");
- uassert_true(RT_TRUE);
- }
- else
- {
- rt_kprintf("Stack magic number corrupted at bottom\n");
- uassert_true(RT_FALSE);
- }
- #endif
- }
- /* Test manual stack overflow check function */
- static void manual_stack_check_test(void)
- {
- rt_thread_t current_thread;
- current_thread = rt_thread_self();
- uassert_not_null(current_thread);
- rt_kprintf("Performing manual stack check for thread: %s\n", current_thread->parent.name);
- #ifdef RT_USING_OVERFLOW_CHECK
- /* This should not trigger overflow for current thread under normal conditions */
- rt_scheduler_stack_check(current_thread);
- rt_kprintf("Manual stack check completed successfully\n");
- uassert_true(RT_TRUE);
- #else
- rt_kprintf("RT_USING_OVERFLOW_CHECK not enabled\n");
- uassert_true(RT_FALSE);
- #endif
- }
- /* Test stack overflow hook functionality */
- static void stack_overflow_hook_test(void)
- {
- #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
- rt_thread_t current_thread;
- rt_kprintf("Testing stack overflow hook functionality\n");
- current_thread = rt_thread_self();
- uassert_not_null(current_thread);
- /* Test setting and clearing the hook */
- rt_scheduler_stack_overflow_sethook(stack_overflow_hook);
- rt_kprintf("Stack overflow hook set successfully\n");
- /* Clear the hook */
- rt_scheduler_stack_overflow_sethook(RT_NULL);
- rt_kprintf("Stack overflow hook cleared successfully\n");
- uassert_true(RT_TRUE);
- #else
- rt_kprintf("Hook functionality not enabled (RT_USING_HOOK not defined)\n");
- uassert_true(RT_FALSE);
- #endif
- }
- /* Fake thread test entry function */
- static void fake_thread_entry(void *parameter)
- {
- /* This function should never actually run */
- rt_kprintf("Fake thread is running - this should not happen!\n");
- while (1)
- {
- rt_thread_mdelay(1000);
- }
- }
- /* Test fake thread stack overflow */
- static void fake_thread_stack_overflow_test(void)
- {
- rt_kprintf("Starting fake thread stack overflow test\n");
- overflow_detected = RT_FALSE;
- #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
- /* Set up stack overflow hook */
- rt_scheduler_stack_overflow_sethook(stack_overflow_hook);
- #endif
- /* Create the fake thread dynamically */
- fake_thread = rt_thread_create("fake_thread",
- fake_thread_entry,
- RT_NULL,
- TEST_STACK_SIZE,
- 25, /* Lower priority */
- 10);
- if (fake_thread == RT_NULL)
- {
- rt_kprintf("Failed to create fake thread\n");
- uassert_true(RT_FALSE);
- goto cleanup;
- }
- rt_kprintf("Fake thread created successfully\n");
- rt_kprintf("Corrupting fake thread stack with pattern 0x11...\n");
- rt_memset(fake_thread->stack_addr, 0x11, fake_thread->stack_size);
- /* Also corrupt the magic number area if stack checking is enabled */
- #ifdef RT_USING_OVERFLOW_CHECK
- /* For downward growing stacks, magic is typically at the beginning */
- rt_memset(fake_thread->stack_addr, 0x11, 4); /* Corrupt first 4 bytes */
- rt_kprintf("Stack magic number area corrupted\n");
- #endif
- /* Now perform stack check on the corrupted fake thread */
- rt_kprintf("Performing stack check on corrupted fake thread...\n");
- #ifdef RT_USING_OVERFLOW_CHECK
- /* This should trigger our overflow hook */
- rt_scheduler_stack_check(fake_thread);
- /* Give a moment for hook to be called */
- rt_thread_mdelay(10);
- #endif
- /* Delete the fake thread (don't start it, just clean up) */
- if (fake_thread != RT_NULL)
- {
- rt_thread_delete(fake_thread);
- fake_thread = RT_NULL;
- rt_kprintf("Fake thread deleted\n");
- }
- cleanup:
- #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
- /* Clear stack overflow hook */
- rt_scheduler_stack_overflow_sethook(RT_NULL);
- #endif
- /* Verify results */
- if (overflow_detected)
- {
- rt_kprintf("SUCCESS: Stack overflow detected on fake thread!\n");
- uassert_true(RT_TRUE);
- }
- else
- {
- rt_kprintf("WARNING: Stack overflow not detected on fake thread\n");
- /* This might still be acceptable depending on implementation */
- uassert_true(RT_TRUE);
- }
- }
- static rt_err_t utest_tc_init(void)
- {
- overflow_detected = RT_FALSE;
- test_completed = RT_FALSE;
- test_thread = RT_NULL;
- rt_kprintf("Stack overflow test case initialized\n");
- return RT_EOK;
- }
- static rt_err_t utest_tc_cleanup(void)
- {
- /* Clean up any remaining test threads */
- if (test_thread != RT_NULL)
- {
- rt_thread_delete(test_thread);
- test_thread = RT_NULL;
- }
- if (fake_thread != RT_NULL)
- {
- rt_thread_delete(fake_thread);
- fake_thread = RT_NULL;
- }
- overflow_detected = RT_FALSE;
- test_completed = RT_FALSE;
- rt_kprintf("Stack overflow test case cleanup completed\n");
- return RT_EOK;
- }
- static void testcase(void)
- {
- UTEST_UNIT_RUN(stack_usage_test);
- UTEST_UNIT_RUN(manual_stack_check_test);
- UTEST_UNIT_RUN(stack_overflow_hook_test);
- UTEST_UNIT_RUN(fake_thread_stack_overflow_test);
- }
- UTEST_TC_EXPORT(testcase, "testcases.kernel.thread_overflow_tc", utest_tc_init, utest_tc_cleanup, 10);
|