File: | /home/joel/rtems-4.11-work/build/rtems/c/src/../../cpukit/libmisc/stackchk/check.c |
Location: | line 222, column 24 |
Description: | Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption |
1 | /* | ||
2 | * Stack Overflow Check User Extension Set | ||
3 | * | ||
4 | * NOTE: This extension set automatically determines at | ||
5 | * initialization time whether the stack for this | ||
6 | * CPU grows up or down and installs the correct | ||
7 | * extension routines for that direction. | ||
8 | * | ||
9 | * COPYRIGHT (c) 1989-2010. | ||
10 | * On-Line Applications Research Corporation (OAR). | ||
11 | * | ||
12 | * The license and distribution terms for this file may be | ||
13 | * found in the file LICENSE in this distribution or at | ||
14 | * http://www.rtems.com/license/LICENSE. | ||
15 | * | ||
16 | * $Id: check.c,v 1.72 2010/08/25 20:29:41 joel Exp $ | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #ifdef HAVE_CONFIG_H1 | ||
21 | #include "config.h" | ||
22 | #endif | ||
23 | |||
24 | #include <rtems.h> | ||
25 | #include <inttypes.h> | ||
26 | |||
27 | /* | ||
28 | * The stack dump information may be printed by a "fatal" extension. | ||
29 | * Fatal extensions only get called via rtems_fatal_error_occurred() | ||
30 | * and not when rtems_shutdown_executive() is called. | ||
31 | * When that happens, this #define should be deleted and all the code | ||
32 | * it marks. | ||
33 | */ | ||
34 | #define DONT_USE_FATAL_EXTENSION | ||
35 | |||
36 | #include <string.h> | ||
37 | #include <stdlib.h> | ||
38 | |||
39 | #include <rtems/bspIo.h> | ||
40 | #include <rtems/stackchk.h> | ||
41 | #include "internal.h" | ||
42 | |||
43 | /* | ||
44 | * Variable to indicate when the stack checker has been initialized. | ||
45 | */ | ||
46 | static int Stack_check_Initialized = 0; | ||
47 | |||
48 | /* | ||
49 | * The "magic pattern" used to mark the end of the stack. | ||
50 | */ | ||
51 | Stack_check_Control Stack_check_Pattern; | ||
52 | |||
53 | /* | ||
54 | * Helper function to report if the actual stack pointer is in range. | ||
55 | * | ||
56 | * NOTE: This uses a GCC specific method. | ||
57 | */ | ||
58 | static inline bool_Bool Stack_check_Frame_pointer_in_range( | ||
59 | Stack_Control *the_stack | ||
60 | ) | ||
61 | { | ||
62 | #if defined(__GNUC__4) | ||
63 | void *sp = __builtin_frame_address(0); | ||
64 | |||
65 | if ( sp < the_stack->area ) { | ||
66 | return false0; | ||
67 | } | ||
68 | if ( sp > (the_stack->area + the_stack->size) ) { | ||
69 | return false0; | ||
70 | } | ||
71 | #else | ||
72 | #error "How do I check stack bounds on a non-GNU compiler?" | ||
73 | #endif | ||
74 | return true1; | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Where the pattern goes in the stack area is dependent upon | ||
79 | * whether the stack grow to the high or low area of the memory. | ||
80 | */ | ||
81 | #if (CPU_STACK_GROWS_UP0 == TRUE1) | ||
82 | #define Stack_check_Get_pattern_area( _the_stack )((Stack_check_Control *) ((char *)(_the_stack)->area + sizeof (Heap_Block) - (2 * sizeof(uintptr_t) + 0))) \ | ||
83 | ((Stack_check_Control *) ((char *)(_the_stack)->area + \ | ||
84 | (_the_stack)->size - sizeof( Stack_check_Control ) )) | ||
85 | |||
86 | #define Stack_check_Calculate_used( _low, _size, _high_water )( ((char *)(_low) + (_size)) - (char *)(_high_water) ) \ | ||
87 | ((char *)(_high_water) - (char *)(_low)) | ||
88 | |||
89 | #define Stack_check_usable_stack_start(_the_stack)((char *)(_the_stack)->area + sizeof(Stack_check_Control)) \ | ||
90 | ((_the_stack)->area) | ||
91 | |||
92 | #else | ||
93 | /* | ||
94 | * We need this magic offset because during a task delete the task stack will | ||
95 | * be freed before we enter the task switch extension which checks the stack. | ||
96 | * The task stack free operation will write the next and previous pointers | ||
97 | * for the free list into this area. | ||
98 | */ | ||
99 | #define Stack_check_Get_pattern_area( _the_stack )((Stack_check_Control *) ((char *)(_the_stack)->area + sizeof (Heap_Block) - (2 * sizeof(uintptr_t) + 0))) \ | ||
100 | ((Stack_check_Control *) ((char *)(_the_stack)->area \ | ||
101 | + sizeof(Heap_Block) - HEAP_BLOCK_HEADER_SIZE(2 * sizeof(uintptr_t) + 0))) | ||
102 | |||
103 | #define Stack_check_Calculate_used( _low, _size, _high_water)( ((char *)(_low) + (_size)) - (char *)(_high_water) ) \ | ||
104 | ( ((char *)(_low) + (_size)) - (char *)(_high_water) ) | ||
105 | |||
106 | #define Stack_check_usable_stack_start(_the_stack)((char *)(_the_stack)->area + sizeof(Stack_check_Control)) \ | ||
107 | ((char *)(_the_stack)->area + sizeof(Stack_check_Control)) | ||
108 | |||
109 | #endif | ||
110 | |||
111 | /* | ||
112 | * The assumption is that if the pattern gets overwritten, the task | ||
113 | * is too close. This defines the usable stack memory. | ||
114 | */ | ||
115 | #define Stack_check_usable_stack_size(_the_stack)((_the_stack)->size - sizeof(Stack_check_Control)) \ | ||
116 | ((_the_stack)->size - sizeof(Stack_check_Control)) | ||
117 | |||
118 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||
119 | /* | ||
120 | * Did RTEMS allocate the interrupt stack? If so, put it in | ||
121 | * Stack_Control format. | ||
122 | */ | ||
123 | Stack_Control Stack_check_Interrupt_stack; | ||
124 | #endif | ||
125 | |||
126 | /* | ||
127 | * Fill an entire stack area with BYTE_PATTERN. This will be used | ||
128 | * to check for amount of actual stack used. | ||
129 | */ | ||
130 | #define Stack_check_Dope_stack(_stack)memset((_stack)->area, 0xA5, (_stack)->size) \ | ||
131 | memset((_stack)->area, BYTE_PATTERN0xA5, (_stack)->size) | ||
132 | |||
133 | /* | ||
134 | * Stack_check_Initialize | ||
135 | */ | ||
136 | void Stack_check_Initialize( void ) | ||
137 | { | ||
138 | int i; | ||
139 | uint32_t *p; | ||
140 | static uint32_t pattern[ 4 ] = { | ||
141 | 0xFEEDF00D, 0x0BAD0D06, /* FEED FOOD to BAD DOG */ | ||
142 | 0xDEADF00D, 0x600D0D06 /* DEAD FOOD but GOOD DOG */ | ||
143 | }; | ||
144 | |||
145 | if ( Stack_check_Initialized ) | ||
146 | return; | ||
147 | |||
148 | /* | ||
149 | * Dope the pattern and fill areas | ||
150 | */ | ||
151 | p = Stack_check_Pattern.pattern; | ||
152 | for ( i = 0; i < PATTERN_SIZE_WORDS(4); i++ ) { | ||
153 | p[i] = pattern[ i%4 ]; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * If appropriate, setup the interrupt stack for high water testing | ||
158 | * also. | ||
159 | */ | ||
160 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||
161 | if (_CPU_Interrupt_stack_low_Per_CPU_Information.interrupt_stack_low && _CPU_Interrupt_stack_high_Per_CPU_Information.interrupt_stack_high) { | ||
162 | Stack_check_Interrupt_stack.area = _CPU_Interrupt_stack_low_Per_CPU_Information.interrupt_stack_low; | ||
163 | Stack_check_Interrupt_stack.size = (char *) _CPU_Interrupt_stack_high_Per_CPU_Information.interrupt_stack_high - | ||
164 | (char *) _CPU_Interrupt_stack_low_Per_CPU_Information.interrupt_stack_low; | ||
165 | Stack_check_Dope_stack(&Stack_check_Interrupt_stack)memset((&Stack_check_Interrupt_stack)->area, 0xA5, (& Stack_check_Interrupt_stack)->size); | ||
166 | } | ||
167 | #endif | ||
168 | |||
169 | Stack_check_Initialized = 1; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * rtems_stack_checker_create_extension | ||
174 | */ | ||
175 | bool_Bool rtems_stack_checker_create_extension( | ||
176 | Thread_Control *running __attribute__((unused)), | ||
177 | Thread_Control *the_thread | ||
178 | ) | ||
179 | { | ||
180 | Stack_check_Initialize(); | ||
181 | |||
182 | if (the_thread) | ||
183 | Stack_check_Dope_stack(&the_thread->Start.Initial_stack)memset((&the_thread->Start.Initial_stack)->area, 0xA5 , (&the_thread->Start.Initial_stack)->size); | ||
184 | |||
185 | return true1; | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * rtems_stack_checker_Begin_extension | ||
190 | */ | ||
191 | void rtems_stack_checker_begin_extension( | ||
192 | Thread_Control *the_thread | ||
193 | ) | ||
194 | { | ||
195 | Stack_check_Control *the_pattern; | ||
196 | |||
197 | if ( the_thread->Object.id == 0 ) /* skip system tasks */ | ||
198 | return; | ||
199 | |||
200 | the_pattern = Stack_check_Get_pattern_area(&the_thread->Start.Initial_stack)((Stack_check_Control *) ((char *)(&the_thread->Start. Initial_stack)->area + sizeof(Heap_Block) - (2 * sizeof(uintptr_t ) + 0))); | ||
201 | |||
202 | *the_pattern = Stack_check_Pattern; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Stack_check_report_blown_task | ||
207 | * | ||
208 | * Report a blown stack. Needs to be a separate routine | ||
209 | * so that interrupt handlers can use this too. | ||
210 | * | ||
211 | * NOTE: The system is in a questionable state... we may not get | ||
212 | * the following message out. | ||
213 | */ | ||
214 | void Stack_check_report_blown_task( | ||
215 | Thread_Control *running, | ||
216 | bool_Bool pattern_ok | ||
217 | ) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE__attribute__ ((noreturn)); | ||
218 | |||
219 | void Stack_check_report_blown_task(Thread_Control *running, bool_Bool pattern_ok) | ||
220 | { | ||
221 | Stack_Control *stack = &running->Start.Initial_stack; | ||
222 | void *pattern_area = Stack_check_Get_pattern_area(stack)((Stack_check_Control *) ((char *)(stack)->area + sizeof(Heap_Block ) - (2 * sizeof(uintptr_t) + 0))); | ||
Within the expansion of the macro 'Stack_check_Get_pattern_area':
| |||
223 | char name [32]; | ||
224 | |||
225 | printk("BLOWN STACK!!!\n"); | ||
226 | printk("task control block: 0x%08" PRIxPTR"x" "\n", running); | ||
227 | printk("task ID: 0x%08lx\n", (unsigned long) running->Object.id); | ||
228 | printk( | ||
229 | "task name: 0x%08" PRIx32"x" "\n", | ||
230 | running->Object.name.name_u32 | ||
231 | ); | ||
232 | printk( | ||
233 | "task name string: %s\n", | ||
234 | rtems_object_get_name(running->Object.id, sizeof(name), name) | ||
235 | ); | ||
236 | printk( | ||
237 | "task stack area (%lu Bytes): 0x%08" PRIxPTR"x" " .. 0x%08" PRIxPTR"x" "\n", | ||
238 | (unsigned long) stack->size, | ||
239 | stack->area, | ||
240 | ((char *) stack->area + stack->size) | ||
241 | ); | ||
242 | if (!pattern_ok) { | ||
243 | printk( | ||
244 | "damaged pattern area (%lu Bytes): 0x%08" PRIxPTR"x" " .. 0x%08" PRIxPTR"x" "\n", | ||
245 | (unsigned long) PATTERN_SIZE_BYTES((4) * sizeof(uint32_t)), | ||
246 | pattern_area, | ||
247 | (pattern_area + PATTERN_SIZE_BYTES((4) * sizeof(uint32_t))) | ||
248 | ); | ||
249 | } | ||
250 | |||
251 | #if defined(RTEMS_MULTIPROCESSING) | ||
252 | if (rtems_configuration_get_user_multiprocessing_table()((void*)0)) { | ||
253 | printk( | ||
254 | "node: 0x%08" PRIxPTR"x" "\n", | ||
255 | rtems_configuration_get_user_multiprocessing_table()((void*)0)->node | ||
256 | ); | ||
257 | } | ||
258 | #endif | ||
259 | |||
260 | rtems_fatal_error_occurred(0x81); | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * rtems_stack_checker_switch_extension | ||
265 | */ | ||
266 | void rtems_stack_checker_switch_extension( | ||
267 | Thread_Control *running __attribute__((unused)), | ||
268 | Thread_Control *heir __attribute__((unused)) | ||
269 | ) | ||
270 | { | ||
271 | Stack_Control *the_stack = &running->Start.Initial_stack; | ||
272 | void *pattern; | ||
273 | bool_Bool sp_ok; | ||
274 | bool_Bool pattern_ok = true1; | ||
275 | |||
276 | pattern = (void *) Stack_check_Get_pattern_area(the_stack)((Stack_check_Control *) ((char *)(the_stack)->area + sizeof (Heap_Block) - (2 * sizeof(uintptr_t) + 0)))->pattern; | ||
277 | |||
278 | /* | ||
279 | * Check for an out of bounds stack pointer or an overwrite | ||
280 | */ | ||
281 | sp_ok = Stack_check_Frame_pointer_in_range( the_stack ); | ||
282 | |||
283 | pattern_ok = (!memcmp( pattern, | ||
284 | (void *) Stack_check_Pattern.pattern, PATTERN_SIZE_BYTES((4) * sizeof(uint32_t)))); | ||
285 | |||
286 | if ( !sp_ok || !pattern_ok ) { | ||
287 | Stack_check_report_blown_task( running, pattern_ok ); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Check if blown | ||
293 | */ | ||
294 | bool_Bool rtems_stack_checker_is_blown( void ) | ||
295 | { | ||
296 | Stack_Control *the_stack = &_Thread_Executing_Per_CPU_Information.executing->Start.Initial_stack; | ||
297 | bool_Bool sp_ok; | ||
298 | bool_Bool pattern_ok = true1; | ||
299 | |||
300 | /* | ||
301 | * Check for an out of bounds stack pointer | ||
302 | */ | ||
303 | |||
304 | sp_ok = Stack_check_Frame_pointer_in_range( the_stack ); | ||
305 | |||
306 | /* | ||
307 | * The stack checker must be initialized before the pattern is there | ||
308 | * to check. | ||
309 | */ | ||
310 | if ( Stack_check_Initialized ) { | ||
311 | pattern_ok = (!memcmp( | ||
312 | (void *) Stack_check_Get_pattern_area(the_stack)((Stack_check_Control *) ((char *)(the_stack)->area + sizeof (Heap_Block) - (2 * sizeof(uintptr_t) + 0)))->pattern, | ||
313 | (void *) Stack_check_Pattern.pattern, | ||
314 | PATTERN_SIZE_BYTES((4) * sizeof(uint32_t)) | ||
315 | )); | ||
316 | } | ||
317 | |||
318 | |||
319 | /* | ||
320 | * Let's report as much as we can. | ||
321 | */ | ||
322 | if ( !sp_ok || !pattern_ok ) { | ||
323 | Stack_check_report_blown_task( _Thread_Executing_Per_CPU_Information.executing, pattern_ok ); | ||
324 | /* DOES NOT RETURN */ | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * The Stack Pointer and the Pattern Area are OK so return false. | ||
329 | */ | ||
330 | return false0; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Stack_check_find_high_water_mark | ||
335 | */ | ||
336 | static inline void *Stack_check_find_high_water_mark( | ||
337 | const void *s, | ||
338 | size_t n | ||
339 | ) | ||
340 | { | ||
341 | const uint32_t *base, *ebase; | ||
342 | uint32_t length; | ||
343 | |||
344 | base = s; | ||
345 | length = n/4; | ||
346 | |||
347 | #if ( CPU_STACK_GROWS_UP0 == TRUE1 ) | ||
348 | /* | ||
349 | * start at higher memory and find first word that does not | ||
350 | * match pattern | ||
351 | */ | ||
352 | |||
353 | base += length - 1; | ||
354 | for (ebase = s; base > ebase; base--) | ||
355 | if (*base != U32_PATTERN0xA5A5A5A5) | ||
356 | return (void *) base; | ||
357 | #else | ||
358 | /* | ||
359 | * start at lower memory and find first word that does not | ||
360 | * match pattern | ||
361 | */ | ||
362 | |||
363 | base += PATTERN_SIZE_WORDS(4); | ||
364 | for (ebase = base + length; base < ebase; base++) | ||
365 | if (*base != U32_PATTERN0xA5A5A5A5) | ||
366 | return (void *) base; | ||
367 | #endif | ||
368 | |||
369 | return (void *)0; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * Stack_check_Dump_threads_usage | ||
374 | * | ||
375 | * Try to print out how much stack was actually used by the task. | ||
376 | */ | ||
377 | static void *print_context; | ||
378 | static rtems_printk_plugin_t print_handler; | ||
379 | |||
380 | void Stack_check_Dump_threads_usage( | ||
381 | Thread_Control *the_thread | ||
382 | ) | ||
383 | { | ||
384 | uint32_t size, used; | ||
385 | void *low; | ||
386 | void *high_water_mark; | ||
387 | void *current; | ||
388 | Stack_Control *stack; | ||
389 | char name[5]; | ||
390 | |||
391 | /* | ||
392 | * The pointer passed in for the_thread is guaranteed to be non-NULL from | ||
393 | * rtems_iterate_over_all_threads() so no need to check it here. | ||
394 | */ | ||
395 | |||
396 | /* | ||
397 | * Obtain interrupt stack information | ||
398 | */ | ||
399 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||
400 | if (the_thread == (Thread_Control *) -1) { | ||
401 | if (!Stack_check_Interrupt_stack.area) | ||
402 | return; | ||
403 | stack = &Stack_check_Interrupt_stack; | ||
404 | the_thread = 0; | ||
405 | current = 0; | ||
406 | } else | ||
407 | #endif | ||
408 | { | ||
409 | stack = &the_thread->Start.Initial_stack; | ||
410 | current = (void *)_CPU_Context_Get_SP( &the_thread->Registers )(&the_thread->Registers)->o6_sp; | ||
411 | } | ||
412 | |||
413 | low = Stack_check_usable_stack_start(stack)((char *)(stack)->area + sizeof(Stack_check_Control)); | ||
414 | size = Stack_check_usable_stack_size(stack)((stack)->size - sizeof(Stack_check_Control)); | ||
415 | |||
416 | high_water_mark = Stack_check_find_high_water_mark(low, size); | ||
417 | |||
418 | if ( high_water_mark ) | ||
419 | used = Stack_check_Calculate_used( low, size, high_water_mark )( ((char *)(low) + (size)) - (char *)(high_water_mark) ); | ||
420 | else | ||
421 | used = 0; | ||
422 | |||
423 | |||
424 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||
425 | if ( the_thread ) | ||
426 | #endif | ||
427 | { | ||
428 | (*print_handler)( | ||
429 | print_context, | ||
430 | "0x%08" PRIx32"x" " %4s", | ||
431 | the_thread->Object.id, | ||
432 | rtems_object_get_name( the_thread->Object.id, sizeof(name), name ) | ||
433 | ); | ||
434 | } | ||
435 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||
436 | else { | ||
437 | (*print_handler)( print_context, "0x%08" PRIx32"x" " INTR", ~0 ); | ||
438 | } | ||
439 | #endif | ||
440 | |||
441 | (*print_handler)( | ||
442 | print_context, | ||
443 | " %010p - %010p %010p %8" PRId32"d" " ", | ||
444 | stack->area, | ||
445 | stack->area + stack->size - 1, | ||
446 | current, | ||
447 | size | ||
448 | ); | ||
449 | |||
450 | if (Stack_check_Initialized == 0) { | ||
451 | (*print_handler)( print_context, "Unavailable\n" ); | ||
452 | } else { | ||
453 | (*print_handler)( print_context, "%8" PRId32"d" "\n", used ); | ||
454 | } | ||
455 | |||
456 | |||
457 | } | ||
458 | |||
459 | /* | ||
460 | * rtems_stack_checker_fatal_extension | ||
461 | */ | ||
462 | #ifndef DONT_USE_FATAL_EXTENSION | ||
463 | void rtems_stack_checker_fatal_extension( | ||
464 | Internal_errors_Source source, | ||
465 | bool_Bool is_internal, | ||
466 | uint32_t status | ||
467 | ) | ||
468 | { | ||
469 | if (status == 0) | ||
470 | rtems_stack_checker_report_usage(); | ||
471 | } | ||
472 | #endif | ||
473 | |||
474 | /*PAGE | ||
475 | * | ||
476 | * rtems_stack_checker_report_usage | ||
477 | */ | ||
478 | |||
479 | void rtems_stack_checker_report_usage_with_plugin( | ||
480 | void *context, | ||
481 | rtems_printk_plugin_t print | ||
482 | ) | ||
483 | { | ||
484 | if ( !print ) | ||
485 | return; | ||
486 | |||
487 | print_context = context; | ||
488 | print_handler = print; | ||
489 | |||
490 | (*print)( context, "Stack usage by thread\n"); | ||
491 | (*print)( context, | ||
492 | " ID NAME LOW HIGH CURRENT AVAILABLE USED\n" | ||
493 | ); | ||
494 | |||
495 | /* iterate over all threads and dump the usage */ | ||
496 | rtems_iterate_over_all_threads( Stack_check_Dump_threads_usage ); | ||
497 | |||
498 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||
499 | /* dump interrupt stack info if any */ | ||
500 | Stack_check_Dump_threads_usage((Thread_Control *) -1); | ||
501 | #endif | ||
502 | |||
503 | print_context = NULL((void*)0); | ||
504 | print_handler = NULL((void*)0); | ||
505 | } | ||
506 | |||
507 | void rtems_stack_checker_report_usage( void ) | ||
508 | { | ||
509 | rtems_stack_checker_report_usage_with_plugin( NULL((void*)0), printk_plugin ); | ||
510 | } |