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