thread_overflow_tc.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * Copyright (c) 2006-2025, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2025-09-01 Rbb666 add stack overflow test
  9. */
  10. #include <rtthread.h>
  11. #include "utest.h"
  12. #define UTEST_NAME "thread_overflow_tc"
  13. #define TEST_STACK_SIZE 512
  14. /* Test thread stack overflow */
  15. static rt_thread_t test_thread = RT_NULL;
  16. static rt_thread_t fake_thread = RT_NULL; /* Dynamic fake thread */
  17. static volatile rt_bool_t overflow_detected = RT_FALSE;
  18. static volatile rt_bool_t test_completed = RT_FALSE;
  19. /* Stack overflow detection hook - returns RT_EOK to continue, other values to halt */
  20. static rt_err_t stack_overflow_hook(struct rt_thread *thread)
  21. {
  22. rt_kprintf("Stack overflow hook called for thread: %s\n", thread->parent.name);
  23. overflow_detected = RT_TRUE;
  24. /* Return RT_EOK to indicate overflow has been handled successfully */
  25. return RT_EOK;
  26. }
  27. /* Test stack usage calculation */
  28. static void stack_usage_test(void)
  29. {
  30. rt_thread_t current_thread;
  31. rt_uint32_t total_stack, used_stack;
  32. current_thread = rt_thread_self();
  33. uassert_not_null(current_thread);
  34. /* Get stack information */
  35. total_stack = current_thread->stack_size;
  36. rt_kprintf("Thread: %s\n", current_thread->parent.name);
  37. rt_kprintf("Stack addr: 0x%p\n", current_thread->stack_addr);
  38. rt_kprintf("Stack size: %d bytes\n", total_stack);
  39. rt_kprintf("Current SP: 0x%p\n", current_thread->sp);
  40. #ifdef ARCH_CPU_STACK_GROWS_UPWARD
  41. /* For upward growing stacks */
  42. used_stack = (rt_uint32_t)current_thread->sp - (rt_uint32_t)current_thread->stack_addr;
  43. #else
  44. /* For downward growing stacks (most common) */
  45. used_stack = (rt_uint32_t)current_thread->stack_addr + total_stack - (rt_uint32_t)current_thread->sp;
  46. #endif
  47. rt_kprintf("Used stack: %d bytes (%d%%)\n",
  48. used_stack,
  49. (used_stack * 100) / total_stack);
  50. /* Verify stack usage is reasonable */
  51. uassert_true(used_stack > 0);
  52. uassert_true(used_stack < total_stack);
  53. /* Check magic number at stack boundary */
  54. #ifdef ARCH_CPU_STACK_GROWS_UPWARD
  55. /* Check magic at the end for upward growing */
  56. if (*((rt_uint8_t *)((rt_uintptr_t)current_thread->stack_addr + total_stack - 1)) == '#')
  57. {
  58. rt_kprintf("Stack magic number intact at top\n");
  59. uassert_true(RT_TRUE);
  60. }
  61. else
  62. {
  63. rt_kprintf("Stack magic number corrupted at top\n");
  64. uassert_true(RT_FALSE);
  65. }
  66. #else
  67. /* Check magic at the beginning for downward growing */
  68. if (*((rt_uint8_t *)current_thread->stack_addr) == '#')
  69. {
  70. rt_kprintf("Stack magic number intact at bottom\n");
  71. uassert_true(RT_TRUE);
  72. }
  73. else
  74. {
  75. rt_kprintf("Stack magic number corrupted at bottom\n");
  76. uassert_true(RT_FALSE);
  77. }
  78. #endif
  79. }
  80. /* Test manual stack overflow check function */
  81. static void manual_stack_check_test(void)
  82. {
  83. rt_thread_t current_thread;
  84. current_thread = rt_thread_self();
  85. uassert_not_null(current_thread);
  86. rt_kprintf("Performing manual stack check for thread: %s\n", current_thread->parent.name);
  87. #ifdef RT_USING_OVERFLOW_CHECK
  88. /* This should not trigger overflow for current thread under normal conditions */
  89. rt_scheduler_stack_check(current_thread);
  90. rt_kprintf("Manual stack check completed successfully\n");
  91. uassert_true(RT_TRUE);
  92. #else
  93. rt_kprintf("RT_USING_OVERFLOW_CHECK not enabled\n");
  94. uassert_true(RT_FALSE);
  95. #endif
  96. }
  97. /* Test stack overflow hook functionality */
  98. static void stack_overflow_hook_test(void)
  99. {
  100. #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
  101. rt_thread_t current_thread;
  102. rt_kprintf("Testing stack overflow hook functionality\n");
  103. current_thread = rt_thread_self();
  104. uassert_not_null(current_thread);
  105. /* Test setting and clearing the hook */
  106. rt_scheduler_stack_overflow_sethook(stack_overflow_hook);
  107. rt_kprintf("Stack overflow hook set successfully\n");
  108. /* Clear the hook */
  109. rt_scheduler_stack_overflow_sethook(RT_NULL);
  110. rt_kprintf("Stack overflow hook cleared successfully\n");
  111. uassert_true(RT_TRUE);
  112. #else
  113. rt_kprintf("Hook functionality not enabled (RT_USING_HOOK not defined)\n");
  114. uassert_true(RT_FALSE);
  115. #endif
  116. }
  117. /* Fake thread test entry function */
  118. static void fake_thread_entry(void *parameter)
  119. {
  120. /* This function should never actually run */
  121. rt_kprintf("Fake thread is running - this should not happen!\n");
  122. while (1)
  123. {
  124. rt_thread_mdelay(1000);
  125. }
  126. }
  127. /* Test fake thread stack overflow */
  128. static void fake_thread_stack_overflow_test(void)
  129. {
  130. rt_kprintf("Starting fake thread stack overflow test\n");
  131. overflow_detected = RT_FALSE;
  132. #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
  133. /* Set up stack overflow hook */
  134. rt_scheduler_stack_overflow_sethook(stack_overflow_hook);
  135. #endif
  136. /* Create the fake thread dynamically */
  137. fake_thread = rt_thread_create("fake_thread",
  138. fake_thread_entry,
  139. RT_NULL,
  140. TEST_STACK_SIZE,
  141. 25, /* Lower priority */
  142. 10);
  143. if (fake_thread == RT_NULL)
  144. {
  145. rt_kprintf("Failed to create fake thread\n");
  146. uassert_true(RT_FALSE);
  147. goto cleanup;
  148. }
  149. rt_kprintf("Fake thread created successfully\n");
  150. rt_kprintf("Corrupting fake thread stack with pattern 0x11...\n");
  151. rt_memset(fake_thread->stack_addr, 0x11, fake_thread->stack_size);
  152. /* Also corrupt the magic number area if stack checking is enabled */
  153. #ifdef RT_USING_OVERFLOW_CHECK
  154. /* For downward growing stacks, magic is typically at the beginning */
  155. rt_memset(fake_thread->stack_addr, 0x11, 4); /* Corrupt first 4 bytes */
  156. rt_kprintf("Stack magic number area corrupted\n");
  157. #endif
  158. /* Now perform stack check on the corrupted fake thread */
  159. rt_kprintf("Performing stack check on corrupted fake thread...\n");
  160. #ifdef RT_USING_OVERFLOW_CHECK
  161. /* This should trigger our overflow hook */
  162. rt_scheduler_stack_check(fake_thread);
  163. /* Give a moment for hook to be called */
  164. rt_thread_mdelay(10);
  165. #endif
  166. /* Delete the fake thread (don't start it, just clean up) */
  167. if (fake_thread != RT_NULL)
  168. {
  169. rt_thread_delete(fake_thread);
  170. fake_thread = RT_NULL;
  171. rt_kprintf("Fake thread deleted\n");
  172. }
  173. cleanup:
  174. #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
  175. /* Clear stack overflow hook */
  176. rt_scheduler_stack_overflow_sethook(RT_NULL);
  177. #endif
  178. /* Verify results */
  179. if (overflow_detected)
  180. {
  181. rt_kprintf("SUCCESS: Stack overflow detected on fake thread!\n");
  182. uassert_true(RT_TRUE);
  183. }
  184. else
  185. {
  186. rt_kprintf("WARNING: Stack overflow not detected on fake thread\n");
  187. /* This might still be acceptable depending on implementation */
  188. uassert_true(RT_TRUE);
  189. }
  190. }
  191. static rt_err_t utest_tc_init(void)
  192. {
  193. overflow_detected = RT_FALSE;
  194. test_completed = RT_FALSE;
  195. test_thread = RT_NULL;
  196. rt_kprintf("Stack overflow test case initialized\n");
  197. return RT_EOK;
  198. }
  199. static rt_err_t utest_tc_cleanup(void)
  200. {
  201. /* Clean up any remaining test threads */
  202. if (test_thread != RT_NULL)
  203. {
  204. rt_thread_delete(test_thread);
  205. test_thread = RT_NULL;
  206. }
  207. if (fake_thread != RT_NULL)
  208. {
  209. rt_thread_delete(fake_thread);
  210. fake_thread = RT_NULL;
  211. }
  212. overflow_detected = RT_FALSE;
  213. test_completed = RT_FALSE;
  214. rt_kprintf("Stack overflow test case cleanup completed\n");
  215. return RT_EOK;
  216. }
  217. static void testcase(void)
  218. {
  219. UTEST_UNIT_RUN(stack_usage_test);
  220. UTEST_UNIT_RUN(manual_stack_check_test);
  221. UTEST_UNIT_RUN(stack_overflow_hook_test);
  222. UTEST_UNIT_RUN(fake_thread_stack_overflow_test);
  223. }
  224. UTEST_TC_EXPORT(testcase, "testcases.kernel.thread_overflow_tc", utest_tc_init, utest_tc_cleanup, 10);