Bug Summary

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

Annotated Source Code

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 */
46static int Stack_check_Initialized = 0;
47
48/*
49 * The "magic pattern" used to mark the end of the stack.
50 */
51Stack_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 */
58static 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 */
136void 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 */
175bool_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 */
191void 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 */
214void Stack_check_report_blown_task(
215 Thread_Control *running,
216 bool_Bool pattern_ok
217) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE__attribute__ ((noreturn));
218
219void 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':
a
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
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 */
266void 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 */
294bool_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 */
336static 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 */
377static void *print_context;
378static rtems_printk_plugin_t print_handler;
379
380void 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
479void 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
507void rtems_stack_checker_report_usage( void )
508{
509 rtems_stack_checker_report_usage_with_plugin( NULL((void*)0), printk_plugin );
510}