source: trunk/dll/fortify.c@ 1077

Last change on this file since 1077 was 1077, checked in by Steven Levine, 17 years ago

Enhance Fortify infrastructure
Add Fortify_SetOwner Fortify_ChangeOwner Fortify_ChangeScope
Add FORTIFY_VERBOSE_SCOPE_ENTER_EXIT support
Add more fm/2 Fortify tooling and rework existing tooling for correct nesting
Still lots to do for cross-thread allocations
Add misc.h
Add walkem.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.7 KB
Line 
1
2/* $Id: fortify.c 1077 2008-07-18 18:11:54Z stevenhl $ */
3/* fortify.cxx - A fortified memory allocation shell - V2.2 */
4
5/*
6 * This software is not public domain. All material in
7 * this archive is (C) Copyright 1995 Simon P. Bullen. The
8 * software is freely distributable, with the condition that
9 * no more than a nominal fee is charged for media.
10 * Everything in this distribution must be kept together, in
11 * original, unmodified form.
12 * The software may be modified for your own personal use,
13 * but modified files may not be distributed.
14 * The material is provided "as is" without warranty of
15 * any kind. The author accepts no responsibility for damage
16 * caused by this software.
17 * This software may not be used in any way by Microsoft
18 * Corporation or its subsidiaries, or current employees of
19 * Microsoft Corporation or its subsidiaries.
20 * This software may not be used for the construction,
21 * development, production, or testing of weapon systems of
22 * any kind.
23 * This software may not be used for the construction,
24 * development, production, or use of plants/installations
25 * which include the processing of radioactive/fissionable
26 * material.
27 */
28
29/*
30 * If you use this software at all, I'd love to hear from
31 * you. All questions, criticisms, suggestions, praise and
32 * postcards are most welcome.
33 *
34 * email: sbullen@cybergraphic.com.au
35 *
36 * snail: Simon P. Bullen
37 * PO BOX 12138
38 * A'Beckett St.
39 * Melbourne 3000
40 * Australia
41 */
42
43 /* 06 May 08 SHL Rework scope logic to be MT capable
44 26 May 08 SHL Show TID for leaking scope
45 17 Jul 08 SHL Add Fortify_SetOwner Fortify_ChangeOwner Fortify_ChangeScope
46 18 Jul 08 SHL Add FORTIFY_VERBOSE_SCOPE_ENTER_EXIT
47 */
48
49#ifdef FORTIFY
50
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <assert.h>
55#include <math.h>
56#include <ctype.h>
57#include <time.h>
58
59
60/* the user's options */
61#include "ufortify.h"
62
63/* Prototypes and such */
64#define __FORTIFY_C__ // Suppress malloc replacement etc.
65#include "fortify.h"
66
67
68#ifdef MT_SCOPES
69unsigned long Get_TID_Ordinal(void);
70// Get tib_ptib2 from TIB
71// Get thread id from TIB2
72#pragma aux Get_TID_Ordinal = \
73 "mov ebx, fs:[0xc]" \
74 "mov eax, [ebx+0]" \
75 modify exact [eax ebx] \
76 value [eax]
77#endif
78
79/*
80 * Round x up to the nearest multiple of n.
81 */
82#define ROUND_UP(x, n) ((((x) + (n)-1)/(n))*(n))
83
84/*
85 * struct Header - this structure is used
86 * internally by Fortify to manage it's
87 * own private lists of memory.
88 */
89struct Header
90{
91 unsigned short Checksum; /* For the integrity of our goodies */
92 const char *File; /* The sourcefile of the allocator */
93 unsigned long Line; /* The sourceline of the allocator */
94#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
95 const char *FreedFile; /* The sourcefile of the deallocator */
96 unsigned long FreedLine; /* The sourceline of the deallocator */
97 unsigned char Deallocator; /* The deallocator used */
98#endif
99 size_t Size; /* The size of the malloc'd block */
100 struct Header *Prev; /* Previous link */
101 struct Header *Next; /* Next link */
102 char *Label; /* User's Label (may be null) */
103 unsigned char Scope; /* Scope level of the owner */
104 unsigned char Allocator; /* malloc/realloc/new/etc */
105# ifdef MT_SCOPES
106 unsigned short Owner; /* TID ordinal of block owner */
107# endif
108};
109
110#define FORTIFY_HEADER_SIZE ROUND_UP(sizeof(struct Header), sizeof(unsigned short))
111
112
113/*
114 * FORTIFY_ALIGNED_BEFORE_SIZE is FORTIFY_BEFORE_SIZE rounded up to the
115 * next multiple of FORTIFY_ALIGNMENT. This is so that we can guarantee
116 * the alignment of user memory for such systems where this is important
117 * (eg storing doubles on a SPARC)
118 */
119#define FORTIFY_ALIGNED_BEFORE_SIZE ( \
120 ROUND_UP(FORTIFY_HEADER_SIZE + FORTIFY_BEFORE_SIZE, FORTIFY_ALIGNMENT) \
121 - FORTIFY_HEADER_SIZE)
122
123/*
124 * FORTIFY_OVERHEAD is the total overhead added by Fortify to each
125 * memory block.
126 */
127#define FORTIFY_OVERHEAD ( FORTIFY_HEADER_SIZE \
128 + FORTIFY_ALIGNED_BEFORE_SIZE \
129 + FORTIFY_AFTER_SIZE)
130
131
132/*
133 *
134 * Static Function Prototypes
135 *
136 */
137static int st_CheckBlock(struct Header *h, const char *file, unsigned long line);
138static int st_CheckFortification (unsigned char *ptr, unsigned char value, size_t size);
139static void st_SetFortification (unsigned char *ptr, unsigned char value, size_t size);
140static void st_OutputFortification(unsigned char *ptr, unsigned char value, size_t size);
141static void st_HexDump(unsigned char *ptr, size_t offset, size_t size, int title);
142static int st_IsHeaderValid(struct Header *h);
143static void st_MakeHeaderValid(struct Header *h);
144static unsigned short st_ChecksumHeader(struct Header *h);
145static int st_IsOnAllocatedList(struct Header *h);
146static void st_OutputHeader(struct Header *h);
147static void st_OutputMemory(struct Header *h);
148static void st_OutputLastVerifiedPoint(void);
149static void st_DefaultOutput(const char *String);
150static const char *st_MemoryBlockString(struct Header *h);
151static void st_OutputDeleteTrace();
152
153#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
154#ifdef FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
155#ifdef FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
156 static const char *st_DeallocatedMemoryBlockString(struct Header *h);
157#endif /* FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
158#endif /* FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
159 static int st_IsOnDeallocatedList(struct Header *h);
160 static int st_PurgeDeallocatedBlocks(unsigned long Bytes, const char *file, unsigned long line);
161 static int st_PurgeDeallocatedScope(unsigned char Scope, const char *file, unsigned long line);
162 static int st_CheckDeallocatedBlock(struct Header *h, const char *file, unsigned long line);
163 static void st_FreeDeallocatedBlock(struct Header *h, const char *file, unsigned long line);
164#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
165
166
167/*
168 *
169 * Static variables
170 *
171 */
172static struct Header *st_AllocatedHead;
173static int st_AllocateFailRate;
174static char st_Buffer[256];
175static Fortify_OutputFuncPtr st_Output = st_DefaultOutput;
176static const char *st_LastVerifiedFile = "unknown";
177static unsigned long st_LastVerifiedLine;
178#ifdef MT_SCOPES
179static unsigned volatile st_cOrdinals; // Number of known threads
180static volatile unsigned char* st_pScopes; // Scope level of blocks allocated by thread
181static volatile unsigned long* st_pOwners; // Owner of blocks allocated by thread
182#else
183static unsigned char st_Scope = 0;
184#endif
185static unsigned char st_Disabled = 0;
186
187#ifdef __cplusplus
188 int FORTIFY_STORAGE gbl_FortifyMagic = 0; // 28 Jan 08 SHL
189 static const char *st_DeleteFile[FORTIFY_DELETE_STACK_SIZE];
190 static unsigned long st_DeleteLine[FORTIFY_DELETE_STACK_SIZE];
191 static unsigned long st_DeleteStackTop;
192#endif /* __cplusplus */
193
194/* statistics */
195static unsigned long st_MaxBlocks = 0;
196static unsigned long st_MaxAllocation = 0;
197static unsigned long st_CurBlocks = 0;
198static unsigned long st_CurAllocation = 0;
199static unsigned long st_Allocations = 0;
200static unsigned long st_Frees = 0;
201static unsigned long st_TotalAllocation = 0;
202static unsigned long st_AllocationLimit = 0xffffffff;
203
204#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
205 static struct Header *st_DeallocatedHead = 0;
206 static struct Header *st_DeallocatedTail = 0;
207 static unsigned long st_TotalDeallocated = 0;
208#endif
209
210
211/* allocators */
212static const char *st_AllocatorName[] =
213{
214 "malloc()",
215 "calloc()",
216 "realloc()",
217 "strdup()",
218 "new",
219 "new[]"
220};
221
222/* deallocators */
223static const char *st_DeallocatorName[] =
224{
225 "nobody",
226 "free()",
227 "realloc()",
228 "delete",
229 "delete[]"
230};
231
232static const unsigned char st_ValidDeallocator[] =
233{
234 (1<<Fortify_Deallocator_free) | (1<<Fortify_Deallocator_realloc),
235 (1<<Fortify_Deallocator_free) | (1<<Fortify_Deallocator_realloc),
236 (1<<Fortify_Deallocator_free) | (1<<Fortify_Deallocator_realloc),
237 (1<<Fortify_Deallocator_free) | (1<<Fortify_Deallocator_realloc),
238#if defined(FORTIFY_PROVIDE_ARRAY_NEW) && defined(FORTIFY_PROVIDE_ARRAY_DELETE)
239 (1<<Fortify_Deallocator_delete),
240 (1<<Fortify_Deallocator_array_delete)
241#else
242 (1<<Fortify_Deallocator_delete) | (1<<Fortify_Deallocator_array_delete),
243 (1<<Fortify_Deallocator_delete) | (1<<Fortify_Deallocator_array_delete)
244#endif
245};
246
247
248/*
249 * Fortify_Allocate() - allocate a block of fortified memory
250 */
251void *FORTIFY_STORAGE
252Fortify_Allocate(size_t size, unsigned char allocator, const char *file, unsigned long line)
253{
254 unsigned char *ptr;
255 struct Header *h;
256 int another_try;
257
258#ifdef MT_SCOPES
259 unsigned ordinal;
260#endif
261
262 /*
263 * If Fortify has been disabled, then it's easy
264 */
265 if(st_Disabled)
266 {
267#ifdef FORTIFY_FAIL_ON_ZERO_MALLOC
268 if(size == 0 && (allocator == Fortify_Allocator_new
269 || allocator == Fortify_Allocator_array_new))
270 {
271 /*
272 * A new of zero bytes must succeed, but a malloc of
273 * zero bytes probably won't
274 */
275 return malloc(1);
276 }
277#endif
278
279 return malloc(size);
280 }
281
282#ifdef FORTIFY_CHECK_ALL_MEMORY_ON_ALLOCATE
283 Fortify_CheckAllMemory(file, line);
284#endif
285
286 if(st_AllocateFailRate > 0)
287 {
288 if(rand() % 100 < st_AllocateFailRate)
289 {
290#ifdef FORTIFY_WARN_ON_FALSE_FAIL
291 sprintf(st_Buffer,
292 "\nFortify: A \"%s\" of %lu bytes \"false failed\" at %s.%lu\n",
293 st_AllocatorName[allocator], (unsigned long)size, file, line);
294 st_Output(st_Buffer);
295#endif
296 return(0);
297 }
298 }
299
300 /* Check to see if this allocation will
301 * push us over the artificial limit
302 */
303 if(st_CurAllocation + size > st_AllocationLimit)
304 {
305#ifdef FORTIFY_WARN_ON_FALSE_FAIL
306 sprintf(st_Buffer,
307 "\nFortify: A \"%s\" of %lu bytes \"false failed\" at %s.%lu\n",
308 st_AllocatorName[allocator], (unsigned long)size, file, line);
309 st_Output(st_Buffer);
310#endif
311 return(0);
312 }
313
314#ifdef FORTIFY_WARN_ON_ZERO_MALLOC
315 if(size == 0 && (allocator == Fortify_Allocator_malloc ||
316 allocator == Fortify_Allocator_calloc ||
317 allocator == Fortify_Allocator_realloc ))
318 {
319 sprintf(st_Buffer,
320 "\nFortify: A \"%s\" of 0 bytes attempted at %s.%lu\n",
321 st_AllocatorName[allocator], file, line);
322 st_Output(st_Buffer);
323 }
324#endif /* FORTIFY_WARN_ON_ZERO_MALLOC */
325
326#ifdef FORTIFY_FAIL_ON_ZERO_MALLOC
327 if(size == 0 && (allocator == Fortify_Allocator_malloc ||
328 allocator == Fortify_Allocator_calloc ||
329 allocator == Fortify_Allocator_realloc ))
330 {
331#ifdef FORTIFY_WARN_ON_ALLOCATE_FAIL
332 sprintf(st_Buffer, "\nFortify: A \"%s\" of %lu bytes failed at %s.%lu\n",
333 st_AllocatorName[allocator], (unsigned long)size, file, line);
334 st_Output(st_Buffer);
335#endif /* FORTIFY_WARN_ON_ALLOCATE_FAIL */
336 return 0;
337 }
338#endif /* FORTIFY_FAIL_ON_ZERO_MALLOC */
339
340#ifdef FORTIFY_WARN_ON_SIZE_T_OVERFLOW
341 /*
342 * Ensure the size of the memory block
343 * plus the overhead isn't bigger than
344 * size_t (that'd be a drag)
345 */
346 {
347 size_t private_size = FORTIFY_HEADER_SIZE
348 + FORTIFY_ALIGNED_BEFORE_SIZE + size + FORTIFY_AFTER_SIZE;
349
350 if(private_size < size)
351 {
352 sprintf(st_Buffer,
353 "\nFortify: A \"%s\" of %lu bytes has overflowed size_t at %s.%lu\n",
354 st_AllocatorName[allocator], (unsigned long)size, file, line);
355 st_Output(st_Buffer);
356 return(0);
357 }
358 }
359#endif
360
361 another_try = 1;
362 do
363 {
364 /*
365 * malloc the memory, including the space
366 * for the header and fortification buffers
367 */
368 ptr = (unsigned char *)malloc( FORTIFY_HEADER_SIZE
369 + FORTIFY_ALIGNED_BEFORE_SIZE
370 + size
371 + FORTIFY_AFTER_SIZE );
372
373#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
374 /*
375 * If we're tracking deallocated memory, then
376 * we can free some of it, rather than let
377 * this malloc fail
378 */
379 if(!ptr)
380 {
381 another_try = st_PurgeDeallocatedBlocks(size, file, line);
382 }
383#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
384
385 }
386 while(!ptr && another_try);
387
388 if(!ptr)
389 {
390#ifdef FORTIFY_WARN_ON_ALLOCATE_FAIL
391 sprintf(st_Buffer, "\nFortify: A \"%s\" of %lu bytes failed at %s.%lu\n",
392 st_AllocatorName[allocator], (unsigned long)size, file, line);
393 st_Output(st_Buffer);
394#endif
395 return(0);
396 }
397
398 /*
399 * Begin Critical Region
400 */
401 FORTIFY_LOCK();
402
403
404 /*
405 * Make the head's prev pointer point to us
406 * ('cos we're about to become the head)
407 */
408 if(st_AllocatedHead)
409 {
410 st_CheckBlock(st_AllocatedHead, file, line);
411 /* what should we do if this fails? (apart from panic) */
412
413 st_AllocatedHead->Prev = (struct Header *)ptr;
414 st_MakeHeaderValid(st_AllocatedHead);
415 }
416
417# ifdef MT_SCOPES
418 ordinal = Get_TID_Ordinal();
419 // In case owner overridden by Fortify_SetOwner
420 if (ordinal < st_cOrdinals)
421 ordinal = st_pOwners[ordinal];
422# endif
423
424 /*
425 * Initialize and validate the header
426 */
427 h = (struct Header *)ptr;
428 h->Size = size;
429 h->File = file;
430 h->Line = line;
431 h->Next = st_AllocatedHead;
432 h->Prev = 0;
433# ifdef MT_SCOPES
434 h->Scope = ordinal < st_cOrdinals ? st_pScopes[ordinal] : 0;
435 h->Owner = ordinal;
436# else
437 h->Scope = st_Scope;
438# endif
439 h->Allocator = allocator;
440 h->Label = 0;
441#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
442 h->FreedFile = 0;
443 h->FreedLine = 0;
444 h->Deallocator = Fortify_Deallocator_nobody;
445#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
446 st_MakeHeaderValid(h);
447 st_AllocatedHead = h;
448
449 /*
450 * Initialize the fortifications
451 */
452 st_SetFortification(ptr + FORTIFY_HEADER_SIZE,
453 FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
454 st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + size,
455 FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
456
457#ifdef FORTIFY_FILL_ON_ALLOCATE
458 /*
459 * Fill the actual user memory
460 */
461 st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
462 FORTIFY_FILL_ON_ALLOCATE_VALUE, size);
463#endif
464
465 /*
466 * End Critical Region
467 */
468 FORTIFY_UNLOCK();
469
470
471 /*
472 * update the statistics
473 */
474 st_TotalAllocation += size;
475 st_Allocations++;
476 st_CurBlocks++;
477 st_CurAllocation += size;
478 if(st_CurBlocks > st_MaxBlocks)
479 st_MaxBlocks = st_CurBlocks;
480 if(st_CurAllocation > st_MaxAllocation)
481 st_MaxAllocation = st_CurAllocation;
482
483 /*
484 * We return the address of the user's memory, not the start of the block,
485 * which points to our magic cookies
486 */
487 return(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE);
488}
489
490
491
492/*
493 * Fortify_Deallocate() - Free a block of memory allocated with Fortify_Allocate()
494 */
495void FORTIFY_STORAGE
496Fortify_Deallocate(void *uptr, unsigned char deallocator, const char *file, unsigned long line)
497{
498 unsigned char *ptr = (unsigned char *)uptr
499 - FORTIFY_HEADER_SIZE
500 - FORTIFY_ALIGNED_BEFORE_SIZE;
501 struct Header *h = (struct Header *)ptr;
502
503#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
504#ifdef MT_SCOPES
505 unsigned ordinal = Get_TID_Ordinal();
506#endif
507#endif
508
509#ifdef FORTIFY_CHECK_ALL_MEMORY_ON_DEALLOCATE
510 Fortify_CheckAllMemory(file, line);
511#endif
512
513 /*
514 * If Fortify has been disabled, then it's easy
515 * (well, almost)
516 */
517 if(st_Disabled)
518 {
519 /* there is a possibility that this memory
520 * block was allocated when Fortify was
521 * enabled, so we must check the Allocated
522 * list before we free it.
523 */
524 if(!st_IsOnAllocatedList(h))
525 {
526 free(uptr);
527 return;
528 }
529 else
530 {
531 /* the block was allocated by Fortify, so we
532 * gotta free it differently.
533 */
534 /*
535 * Begin critical region
536 */
537 FORTIFY_LOCK();
538
539 /*
540 * Remove the block from the list
541 */
542 if(h->Prev)
543 h->Prev->Next = h->Next;
544 else
545 st_AllocatedHead = h->Next;
546
547 if(h->Next)
548 h->Next->Prev = h->Prev;
549
550 /*
551 * End Critical Region
552 */
553 FORTIFY_UNLOCK();
554
555 /*
556 * actually free the memory
557 */
558 free(ptr);
559 return;
560 }
561 }
562
563
564#ifdef FORTIFY_PARANOID_DEALLOCATE
565 if(!st_IsOnAllocatedList(h))
566 {
567#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
568 if(st_IsOnDeallocatedList(h))
569 {
570 sprintf(st_Buffer, "\nFortify: \"%s\" twice of %s detected at %s.%lu\n",
571 st_DeallocatorName[deallocator],
572 st_MemoryBlockString(h), file, line);
573 st_Output(st_Buffer);
574
575 sprintf(st_Buffer, " Memory block was deallocated by \"%s\" at %s.%lu\n",
576 st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
577 st_Output(st_Buffer);
578 st_OutputDeleteTrace();
579 return;
580 }
581#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
582
583#ifdef FORTIFY_NO_PERCENT_P
584 sprintf(st_Buffer, "\nFortify: Possible \"%s\" twice of (0x%08lx) was detected at %s.%lu\n",
585#else
586 sprintf(st_Buffer, "\nFortify: Possible \"%s\" twice of (%p) was detected at %s.%lu\n",
587#endif
588 st_DeallocatorName[deallocator],
589 uptr, file, line);
590 st_Output(st_Buffer);
591 st_OutputDeleteTrace();
592 return;
593 }
594#endif /* FORTIFY_PARANOID_DEALLOCATE */
595
596 /*
597 * Make sure the block is okay before we free it.
598 * If it's not okay, don't free it - it might not
599 * be a real memory block. Or worse still, someone
600 * might still be writing to it
601 */
602 if(!st_CheckBlock(h, file, line))
603 {
604 st_OutputDeleteTrace();
605 return;
606 }
607
608#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
609 /*
610 * Make sure the block hasn't been freed already
611 * (we can get to here if FORTIFY_PARANOID_DEALLOCATE
612 * is off, but FORTIFY_TRACK_DEALLOCATED_MEMORY
613 * is on).
614 */
615 if(h->Deallocator != Fortify_Deallocator_nobody)
616 {
617 sprintf(st_Buffer, "\nFortify: \"%s\" twice of %s detected at %s.%lu\n",
618 st_DeallocatorName[deallocator],
619 st_MemoryBlockString(h), file, line);
620 st_Output(st_Buffer);
621
622 sprintf(st_Buffer, " Memory block was deallocated by \"%s\" at %s.%lu\n",
623 st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
624 st_Output(st_Buffer);
625 st_OutputDeleteTrace();
626 return;
627 }
628#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
629
630 /*
631 * Make sure the block is being freed with a valid
632 * deallocator. If not, complain. (but free it anyway)
633 */
634 if((st_ValidDeallocator[h->Allocator] & (1<<deallocator)) == 0)
635 {
636 sprintf(st_Buffer, "\nFortify: Incorrect deallocator \"%s\" detected at %s.%lu\n",
637 st_DeallocatorName[deallocator], file, line);
638 st_Output(st_Buffer);
639 sprintf(st_Buffer, " %s was allocated with \"%s\"\n",
640 st_MemoryBlockString(h), st_AllocatorName[h->Allocator]);
641 st_Output(st_Buffer);
642 st_OutputDeleteTrace();
643 }
644
645 /*
646 * Begin critical region
647 */
648 FORTIFY_LOCK();
649
650 /*
651 * Remove the block from the list
652 */
653 if(h->Prev)
654 {
655 if(!st_CheckBlock(h->Prev, file, line))
656 {
657 FORTIFY_UNLOCK();
658 st_OutputDeleteTrace();
659 return;
660 }
661
662 h->Prev->Next = h->Next;
663 st_MakeHeaderValid(h->Prev);
664 }
665 else
666 st_AllocatedHead = h->Next;
667
668 if(h->Next)
669 {
670 if(!st_CheckBlock(h->Next, file, line))
671 {
672 FORTIFY_UNLOCK();
673 st_OutputDeleteTrace();
674 return;
675 }
676
677 h->Next->Prev = h->Prev;
678 st_MakeHeaderValid(h->Next);
679 }
680
681 /*
682 * End Critical Region
683 */
684 FORTIFY_UNLOCK();
685
686 /*
687 * update the statistics
688 */
689 st_Frees++;
690 st_CurBlocks--;
691 st_CurAllocation -= h->Size;
692
693#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
694#ifdef MT_SCOPES
695 ordinal = Get_TID_Ordinal();
696 if (ordinal < st_cOrdinals && st_pScopes[ordinal] > 0)
697#else
698 if(st_Scope > 0)
699#endif
700 {
701 /*
702 * Don't _actually_ free the memory block, just yet.
703 * Place it onto the deallocated list, instead, so
704 * we can check later to see if it's been written to.
705 */
706 #ifdef FORTIFY_FILL_ON_DEALLOCATE
707 /*
708 * Nuke out all user memory that is about to be freed
709 */
710 st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
711 FORTIFY_FILL_ON_DEALLOCATE_VALUE,
712 h->Size);
713 #endif /* FORTIFY_FILL_ON_DEALLOCATE */
714
715 /*
716 * Begin critical region
717 */
718 FORTIFY_LOCK();
719
720 /*
721 * Place the block on the deallocated list
722 */
723 if(st_DeallocatedHead)
724 {
725 st_DeallocatedHead->Prev = (struct Header *)ptr;
726 st_MakeHeaderValid(st_DeallocatedHead);
727 }
728
729 h = (struct Header *)ptr;
730 h->FreedFile = file;
731 h->FreedLine = line;
732 h->Deallocator = deallocator;
733 h->Next = st_DeallocatedHead;
734 h->Prev = 0;
735 st_MakeHeaderValid(h);
736 st_DeallocatedHead = h;
737
738 if(!st_DeallocatedTail)
739 st_DeallocatedTail = h;
740
741 st_TotalDeallocated += h->Size;
742
743 #ifdef FORTIFY_DEALLOCATED_MEMORY_LIMIT
744 /*
745 * If we've got too much on the deallocated list; free some
746 */
747 if(st_TotalDeallocated > FORTIFY_DEALLOCATED_MEMORY_LIMIT)
748 {
749 st_PurgeDeallocatedBlocks(st_TotalDeallocated - FORTIFY_DEALLOCATED_MEMORY_LIMIT, file, line);
750 }
751 #endif
752
753 /*
754 * End critical region
755 */
756 FORTIFY_UNLOCK();
757 }
758 else
759#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
760 {
761 /*
762 * Free the User Label
763 */
764 if(h->Label)
765 {
766 free(h->Label);
767 }
768
769#ifdef FORTIFY_FILL_ON_DEALLOCATE
770 /*
771 * Nuke out all memory that is about to be freed, including the header
772 */
773 st_SetFortification(ptr, FORTIFY_FILL_ON_DEALLOCATE_VALUE,
774 FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size + FORTIFY_AFTER_SIZE);
775#endif /* FORTIFY_FILL_ON_DEALLOCATE */
776
777 /*
778 * And do the actual free
779 */
780 free(ptr);
781 }
782}
783
784
785/*
786 * Fortify_LabelPointer() - Labels the memory block
787 * with a string provided by the user. This function
788 * takes a copy of the passed in string.
789 * The pointer MUST be one returned by a Fortify
790 * allocation function.
791 */
792void
793Fortify_LabelPointer(void *uptr, const char *label, const char *file, unsigned long line)
794{
795 if(!st_Disabled)
796 {
797 unsigned char *ptr = (unsigned char *)uptr
798 - FORTIFY_HEADER_SIZE - FORTIFY_ALIGNED_BEFORE_SIZE;
799 struct Header *h = (struct Header *)ptr;
800
801 /* make sure the pointer is okay */
802 Fortify_CheckPointer(uptr, file, line);
803
804 /* free the previous label */
805 if(h->Label)
806 {
807 free(h->Label);
808 }
809
810 /* make sure the label is sensible */
811 assert(label);
812
813 /* copy it in */
814 h->Label = (char*)malloc(strlen(label)+1);
815 strcpy(h->Label, label);
816
817 /* update the checksum */
818 st_MakeHeaderValid(h);
819 }
820}
821
822/*
823 * Fortify_CheckPointer() - Returns true if the uptr
824 * points to a valid piece of Fortify_Allocated()'d
825 * memory. The memory must be on the allocated list,
826 * and it's fortifications must be intact.
827 * Always returns TRUE if Fortify is disabled.
828 */
829int FORTIFY_STORAGE
830Fortify_CheckPointer(void *uptr, const char *file, unsigned long line)
831{
832 unsigned char *ptr = (unsigned char *)uptr
833 - FORTIFY_HEADER_SIZE - FORTIFY_ALIGNED_BEFORE_SIZE;
834 struct Header *h = (struct Header *)ptr;
835 int r;
836
837 if(st_Disabled)
838 return 1;
839
840 FORTIFY_LOCK();
841
842 if(!st_IsOnAllocatedList(h))
843 {
844#ifdef FORTIFY_NO_PERCENT_P
845 sprintf(st_Buffer, "\nFortify: Invalid pointer (0x%08lx) detected at %s.%lu\n",
846#else
847 sprintf(st_Buffer, "\nFortify: Invalid pointer (%p) detected at %s.%lu\n",
848#endif
849 uptr, file, line);
850 st_Output(st_Buffer);
851 FORTIFY_UNLOCK();
852 return(0);
853 }
854
855#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
856 if(st_IsOnDeallocatedList(h))
857 {
858#ifdef FORTIFY_NO_PERCENT_P
859 sprintf(st_Buffer, "\nFortify: Deallocated pointer (0x%08lx) detected at %s.%lu\n",
860#else
861 sprintf(st_Buffer, "\nFortify: Deallocated pointer (%p) detected at %s.%lu\n",
862#endif
863 uptr, file, line);
864 st_Output(st_Buffer);
865 sprintf(st_Buffer, " Memory block was deallocated by \"%s\" at %s.%lu\n",
866 st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
867 st_Output(st_Buffer);
868 FORTIFY_UNLOCK();
869 return(0);
870 }
871#endif
872
873 r = st_CheckBlock(h, file, line);
874 FORTIFY_UNLOCK();
875 return r;
876}
877
878/*
879 * Fortify_SetOutputFunc(Fortify_OutputFuncPtr Output) -
880 * Sets the function used to output all error and
881 * diagnostic messages. The output function takes
882 * a single const unsigned char * argument, and must be
883 * able to handle newlines. This function returns the
884 * old output function.
885 */
886Fortify_OutputFuncPtr FORTIFY_STORAGE
887Fortify_SetOutputFunc(Fortify_OutputFuncPtr Output)
888{
889 Fortify_OutputFuncPtr Old = st_Output;
890
891 st_Output = Output;
892
893 return(Old);
894}
895
896/*
897 * Fortify_SetAllocateFailRate(int Percent) -
898 * Fortify_Allocate() will "fail" this Percent of
899 * the time, even if the memory is available.
900 * Useful to "stress-test" an application.
901 * Returns the old value.
902 * The fail rate defaults to 0 (a good default I think).
903 */
904int FORTIFY_STORAGE
905Fortify_SetAllocateFailRate(int Percent)
906{
907 int Old = st_AllocateFailRate;
908
909 st_AllocateFailRate = Percent;
910
911 return(Old);
912}
913
914
915/*
916 * Fortify_CheckAllMemory() - Checks the fortifications
917 * of all memory on the allocated list. And, if
918 * FORTIFY_DEALLOCATED_MEMORY is enabled, all the
919 * known deallocated memory as well.
920 * Returns the number of blocks that failed.
921 * Always returns 0 if Fortify is disabled.
922 */
923unsigned long FORTIFY_STORAGE
924Fortify_CheckAllMemory(const char *file, unsigned long line)
925{
926 struct Header *curr = st_AllocatedHead;
927 unsigned long count = 0;
928
929 if(st_Disabled)
930 return 0;
931
932 FORTIFY_LOCK();
933
934 /*
935 * Check the allocated memory
936 */
937 while(curr)
938 {
939 if(!st_CheckBlock(curr, file, line))
940 count++;
941
942 curr = curr->Next;
943 }
944
945 /*
946 * Check the deallocated memory while you're at it
947 */
948#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
949 curr = st_DeallocatedHead;
950 while(curr)
951 {
952 if(!st_CheckDeallocatedBlock(curr, file, line))
953 count++;
954
955 curr = curr->Next;
956 }
957#endif
958
959 /*
960 * If we know where we are, and everything is cool,
961 * remember that. It might be important.
962 */
963 if(file && count == 0)
964 {
965 st_LastVerifiedFile = file;
966 st_LastVerifiedLine = line;
967 }
968
969 FORTIFY_UNLOCK();
970 return(count);
971}
972
973
974/*
975 * Fortify_EnterScope() - enters a new Fortify scope
976 * level. Returns the new scope level.
977 */
978unsigned char FORTIFY_STORAGE
979Fortify_EnterScope(const char *file, unsigned long line)
980{
981#ifdef MT_SCOPES
982 unsigned ordinal = Get_TID_Ordinal();
983 unsigned i;
984 unsigned c;
985
986 if (ordinal >= st_cOrdinals) {
987 // Expand arrays
988 FORTIFY_LOCK();
989 i = st_cOrdinals;
990 c = ordinal + 1;
991 st_pScopes = realloc((void*)st_pScopes, sizeof(*st_pScopes) * c);
992 st_pOwners = realloc((void*)st_pOwners, sizeof(*st_pOwners) * c);
993 for (; i <= ordinal; i++) {
994 st_pScopes[i] = 0; // Default to scope level 0
995 st_pOwners[i] = i; // Default block owner to self
996 }
997 st_cOrdinals = c;
998 FORTIFY_UNLOCK();
999 }
1000 i = ++st_pScopes[ordinal];
1001# ifdef FORTIFY_VERBOSE_SCOPE_ENTER_EXIT
1002 sprintf(st_Buffer,
1003 "Fortify: Entering scope %u in TID %u at %s.%lu\n",
1004 i, ordinal,
1005 file, line); // 26 May 08 SHL
1006 st_Output(st_Buffer);
1007# endif
1008 return(i);
1009#else
1010 return(++st_Scope);
1011#endif
1012}
1013
1014/* Fortify_LeaveScope - leaves a Fortify scope level,
1015 * also prints a memory dump of all non-freed memory
1016 * that was allocated during the scope being exited.
1017 * Does nothing and returns 0 if Fortify is disabled.
1018 */
1019unsigned char FORTIFY_STORAGE
1020Fortify_LeaveScope(const char *file, unsigned long line)
1021{
1022 struct Header *curr = st_AllocatedHead;
1023 unsigned long size = 0, count = 0;
1024#ifdef MT_SCOPES
1025 unsigned ordinal;
1026#endif
1027
1028 if(st_Disabled)
1029 return 0;
1030
1031 FORTIFY_LOCK();
1032
1033#ifdef MT_SCOPES
1034 // Complain on leave without enter 06 May 08 SHL
1035 ordinal = Get_TID_Ordinal();
1036 if (ordinal < st_cOrdinals && st_pScopes[ordinal] > 0) {
1037 st_pScopes[ordinal]--;
1038 }
1039 else {
1040 sprintf(st_Buffer,
1041 "\nFortify: Attempting to leave scope before enter in TID %u at %s.%lu\n",
1042 ordinal, file, line); // 26 May 08 SHL
1043 st_Output(st_Buffer);
1044 }
1045#else
1046 if (st_Scope > 0)
1047 st_Scope--;
1048 else {
1049 sprintf(st_Buffer, "\nFortify: Attempting to leave scope before enter at %s.%lu\n", file, line);
1050 st_Output(st_Buffer);
1051 }
1052#endif
1053 while(curr)
1054 {
1055#ifdef MT_SCOPES
1056 if(curr->Owner == ordinal && ordinal < st_cOrdinals && curr->Scope > st_pScopes[ordinal])
1057#else
1058 if(curr->Scope > st_Scope)
1059#endif
1060 {
1061 if(count == 0)
1062 {
1063 // Report just first occurrance
1064#ifdef MT_SCOPES
1065 sprintf(st_Buffer,
1066 "\nFortify: Memory leak detected leaving scope %d in TID %u at %s.%lu\n",
1067 ordinal < st_cOrdinals ? st_pScopes[ordinal] + 1 : 0,
1068 ordinal,
1069 file, line);
1070#else
1071 sprintf(st_Buffer, "\nFortify: Memory leak detected leaving scope at %s.%lu\n", file, line);
1072#endif
1073 st_Output(st_Buffer);
1074 sprintf(st_Buffer, "%10s %8s %s\n", "Address", "Size", "Allocator");
1075 st_Output(st_Buffer);
1076 }
1077
1078 st_OutputHeader(curr);
1079 count++;
1080 size += curr->Size;
1081 }
1082
1083 curr = curr->Next;
1084 }
1085
1086 if(count)
1087 {
1088 sprintf(st_Buffer,"%10s %8lu bytes in %lu blocks with %lu bytes overhead\n",
1089 "total", size, count, count * FORTIFY_OVERHEAD);
1090 st_Output(st_Buffer);
1091 }
1092# ifdef FORTIFY_VERBOSE_SCOPE_ENTER_EXIT
1093 else {
1094 sprintf(st_Buffer,
1095 "Fortify: Leaving scope %u in TID %u at %s.%lu\n",
1096 ordinal < st_cOrdinals ? st_pScopes[ordinal] + 1 : 0,
1097 ordinal,
1098 file, line); // 26 May 08 SHL
1099 st_Output(st_Buffer);
1100 }
1101# endif
1102
1103#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
1104 /*
1105 * Quietly free all the deallocated memory
1106 * that was allocated in this scope that
1107 * we are still tracking
1108 */
1109#ifdef MT_SCOPES
1110 st_PurgeDeallocatedScope( ordinal < st_cOrdinals ? st_pScopes[ordinal] : 0,
1111 file, line );
1112#else
1113 st_PurgeDeallocatedScope( st_Scope, file, line );
1114#endif
1115#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
1116
1117 FORTIFY_UNLOCK();
1118#ifdef MT_SCOPES
1119 return(ordinal < st_cOrdinals ? st_pScopes[ordinal] : 0);
1120#else
1121 return(st_Scope);
1122#endif
1123}
1124
1125/*
1126 * Fortify_ListAllMemory() - Outputs the entire
1127 * list of currently allocated memory. For each block
1128 * is output it's Address, Size, and the SourceFile and
1129 * Line that allocated it.
1130 *
1131 * If there is no memory on the list, this function
1132 * outputs nothing.
1133 *
1134 * It returns the number of blocks on the list, unless
1135 * Fortify has been disabled, in which case it always
1136 * returns 0.
1137 */
1138unsigned long FORTIFY_STORAGE
1139Fortify_ListAllMemory(const char *file, unsigned long line)
1140{
1141 struct Header *curr = st_AllocatedHead;
1142 unsigned long size = 0, count = 0;
1143
1144 if(st_Disabled)
1145 return 0;
1146
1147 Fortify_CheckAllMemory(file, line);
1148
1149 FORTIFY_LOCK();
1150
1151 if(curr)
1152 {
1153 sprintf(st_Buffer, "\nFortify: Memory List at %s.%lu\n", file, line);
1154 st_Output(st_Buffer);
1155 sprintf(st_Buffer, "%10s %8s %s\n", "Address", "Size", "Allocator");
1156 st_Output(st_Buffer);
1157
1158 while(curr)
1159 {
1160 st_OutputHeader(curr);
1161 count++;
1162 size += curr->Size;
1163 curr = curr->Next;
1164 }
1165
1166 sprintf(st_Buffer, "%10s %8lu bytes in %lu blocks and %lu bytes overhead\n",
1167 "total", size, count, count * FORTIFY_OVERHEAD);
1168 st_Output(st_Buffer);
1169 }
1170
1171 FORTIFY_UNLOCK();
1172 return(count);
1173}
1174
1175/*
1176 * Fortify_DumpAllMemory() - Outputs the entire list of
1177 * currently allocated memory. For each allocated block
1178 * is output it's Address, Size, the SourceFile and Line
1179 * that allocated it, a hex dump of the contents of the
1180 * memory and an ascii dump of printable characters.
1181 *
1182 * If there is no memory on the list, this function outputs nothing.
1183 */
1184unsigned long FORTIFY_STORAGE
1185Fortify_DumpAllMemory(const char *file, unsigned long line)
1186{
1187 struct Header *curr = st_AllocatedHead;
1188 unsigned long count = 0;
1189
1190 if(st_Disabled)
1191 return 0;
1192
1193 Fortify_CheckAllMemory(file, line);
1194
1195 FORTIFY_LOCK();
1196
1197 while(curr)
1198 {
1199 sprintf(st_Buffer, "\nFortify: Hex Dump of %s at %s.%lu\n",
1200 st_MemoryBlockString(curr), file, line);
1201 st_Output(st_Buffer);
1202 st_OutputMemory(curr);
1203 st_Output("\n");
1204 count++;
1205
1206 curr = curr->Next;
1207 }
1208
1209 FORTIFY_UNLOCK();
1210 return(count);
1211}
1212
1213/* Fortify_OutputStatistics() - displays statistics
1214 * about the maximum amount of memory that was
1215 * allocated at any one time.
1216 */
1217void FORTIFY_STORAGE
1218Fortify_OutputStatistics(const char *file, unsigned long line)
1219{
1220 if(st_Disabled)
1221 return;
1222
1223 sprintf(st_Buffer, "\nFortify: Statistics at %s.%lu\n", file, line);
1224 st_Output(st_Buffer);
1225
1226 sprintf(st_Buffer, " Memory currently allocated: %lu bytes in %lu blocks\n",
1227 st_CurAllocation, st_CurBlocks);
1228 st_Output(st_Buffer);
1229 sprintf(st_Buffer, " Maximum memory allocated at one time: %lu bytes in %lu blocks\n",
1230 st_MaxAllocation, st_MaxBlocks);
1231 st_Output(st_Buffer);
1232 sprintf(st_Buffer, " There have been %lu allocations and %lu deallocations\n",
1233 st_Allocations, st_Frees);
1234 st_Output(st_Buffer);
1235 sprintf(st_Buffer, " There was a total of %lu bytes allocated\n",
1236 st_TotalAllocation);
1237 st_Output(st_Buffer);
1238
1239 if(st_Allocations > 0)
1240 {
1241 sprintf(st_Buffer, " The average allocation was %lu bytes\n",
1242 st_TotalAllocation / st_Allocations);
1243 st_Output(st_Buffer);
1244 }
1245}
1246
1247/* Fortify_GetCurrentAllocation() - returns the number of
1248 * bytes currently allocated.
1249 */
1250unsigned long FORTIFY_STORAGE
1251Fortify_GetCurrentAllocation(const char *file, unsigned long line)
1252{
1253 if(st_Disabled)
1254 return 0;
1255
1256 return st_CurAllocation;
1257}
1258
1259/* Fortify_SetAllocationLimit() - set a limit on the total
1260 * amount of memory allowed for this application.
1261 */
1262void FORTIFY_STORAGE
1263Fortify_SetAllocationLimit(unsigned long NewLimit, const char *file, unsigned long line)
1264{
1265 st_AllocationLimit = NewLimit;
1266}
1267
1268/*
1269 * Fortify_Disable() - Run time method of disabling Fortify.
1270 * Useful if you need to turn off Fortify without recompiling
1271 * everything. Not as effective as compiling out, of course.
1272 * The less memory allocated by Fortify when it is disabled
1273 * the better.
1274 * (Previous versions of Fortify did not allow it to be
1275 * disabled if there was any memory allocated at the time,
1276 * but since in C++ memory is often allocated before main
1277 * is even entered, this was useless so Fortify is now
1278 * able to cope).
1279 */
1280void FORTIFY_STORAGE
1281Fortify_Disable(const char *file, unsigned long line)
1282{
1283#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
1284 /* free all deallocated memory we might be tracking */
1285 st_PurgeDeallocatedScope( 0, file, line );
1286#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
1287
1288 st_Disabled = 1;
1289}
1290
1291
1292
1293/*
1294 * st_CheckBlock - Check a block's header and fortifications.
1295 * Returns true if the block is happy.
1296 */
1297static int
1298st_CheckBlock(struct Header *h, const char *file, unsigned long line)
1299{
1300 unsigned char *ptr = (unsigned char *)h;
1301 int result = 1;
1302
1303 if(!st_IsHeaderValid(h))
1304 {
1305 sprintf(st_Buffer,
1306#ifdef FORTIFY_NO_PERCENT_P
1307 "\nFortify: Invalid pointer (0x%08lx) or corrupted header detected at %s.%lu\n",
1308#else
1309 "\nFortify: Invalid pointer (%p) or corrupted header detected at %s.%lu\n",
1310#endif
1311 ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE, file, line);
1312 st_Output(st_Buffer);
1313 st_OutputLastVerifiedPoint();
1314 return(0);
1315 }
1316
1317 if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE,
1318 FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE))
1319 {
1320 sprintf(st_Buffer, "\nFortify: Underwrite detected before block %s at %s.%lu\n",
1321 st_MemoryBlockString(h), file, line);
1322 st_Output(st_Buffer);
1323
1324 st_OutputLastVerifiedPoint();
1325 st_OutputFortification(ptr + FORTIFY_HEADER_SIZE,
1326 FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
1327 result = 0;
1328
1329#ifdef FORTIFY_FILL_ON_CORRUPTION
1330 st_SetFortification(ptr + FORTIFY_HEADER_SIZE, FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
1331#endif
1332 }
1333
1334 if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
1335 FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE))
1336 {
1337 sprintf(st_Buffer, "\nFortify: Overwrite detected after block %s at %s.%lu\n",
1338 st_MemoryBlockString(h), file, line);
1339 st_Output(st_Buffer);
1340
1341 st_OutputLastVerifiedPoint();
1342 st_OutputFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
1343 FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
1344 result = 0;
1345
1346#ifdef FORTIFY_FILL_ON_CORRUPTION
1347 st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
1348 FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
1349#endif
1350 }
1351
1352 return(result);
1353}
1354
1355#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
1356
1357/*
1358 * st_CheckDeallocatedBlock - Check a deallocated block's header and fortifications.
1359 * Returns true if the block is happy.
1360 */
1361static int
1362st_CheckDeallocatedBlock(struct Header *h, const char *file, unsigned long line)
1363{
1364 unsigned char *ptr = (unsigned char *)h;
1365 int result = 1;
1366
1367 if(!st_IsHeaderValid(h))
1368 {
1369 sprintf(st_Buffer,
1370#ifdef FORTIFY_NO_PERCENT_P
1371 "\nFortify: Invalid deallocated pointer (0x%08lx) or corrupted header detected at %s.%lu\n",
1372#else
1373 "\nFortify: Invalid deallocated pointer (%p) or corrupted header detected at %s.%lu\n",
1374#endif
1375 ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE, file, line);
1376 st_Output(st_Buffer);
1377 st_OutputLastVerifiedPoint();
1378 return(0);
1379 }
1380
1381 if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE,
1382 FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE))
1383 {
1384 sprintf(st_Buffer, "\nFortify: Underwrite detected before deallocated block %s at %s.%lu\n",
1385 st_MemoryBlockString(h), file, line);
1386 st_Output(st_Buffer);
1387 sprintf(st_Buffer, " Memory block was deallocated by \"%s\" at %s.%lu\n",
1388 st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
1389 st_Output(st_Buffer);
1390
1391 st_OutputLastVerifiedPoint();
1392 st_OutputFortification(ptr + FORTIFY_HEADER_SIZE,
1393 FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
1394
1395#ifdef FORTIFY_FILL_ON_CORRUPTION
1396 st_SetFortification(ptr + FORTIFY_HEADER_SIZE, FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
1397#endif
1398 result = 0;
1399 }
1400
1401 if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
1402 FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE))
1403 {
1404 sprintf(st_Buffer, "\nFortify: Overwrite detected after deallocated block %s at %s.%lu\n",
1405 st_MemoryBlockString(h), file, line);
1406 st_Output(st_Buffer);
1407 sprintf(st_Buffer, " Memory block was deallocated by \"%s\" at %s.%lu\n",
1408 st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
1409 st_Output(st_Buffer);
1410
1411 st_OutputLastVerifiedPoint();
1412 st_OutputFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
1413 FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
1414
1415#ifdef FORTIFY_FILL_ON_CORRUPTION
1416 st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
1417 FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
1418#endif
1419 result = 0;
1420 }
1421
1422#ifdef FORTIFY_FILL_ON_DEALLOCATE
1423 if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1424 FORTIFY_FILL_ON_DEALLOCATE_VALUE, h->Size))
1425 {
1426 sprintf(st_Buffer, "\nFortify: Write to deallocated block %s detected at %s.%lu\n",
1427 st_MemoryBlockString(h), file, line);
1428 st_Output(st_Buffer);
1429
1430 sprintf(st_Buffer, " Memory block was deallocated by \"%s\" at %s.%lu\n",
1431 st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
1432 st_Output(st_Buffer);
1433 st_OutputLastVerifiedPoint();
1434
1435 st_OutputFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1436 FORTIFY_FILL_ON_DEALLOCATE_VALUE, h->Size);
1437
1438#ifdef FORTIFY_FILL_ON_CORRUPTION
1439 st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1440 FORTIFY_FILL_ON_DEALLOCATE_VALUE, h->Size);
1441#endif /* FORTIFY_FILL_ON_CORRUPTION */
1442 result = 0;
1443 }
1444#endif /* FORTIFY_FILL_ON_DEALLOCATE */
1445 return result;
1446 }
1447
1448#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
1449
1450
1451/*
1452 * st_CheckFortification - Checks if the _size_
1453 * bytes from _ptr_ are all set to _value_
1454 * Returns true if all is happy.
1455 */
1456static int
1457st_CheckFortification(unsigned char *ptr, unsigned char value, size_t size)
1458{
1459 while(size--)
1460 if(*ptr++ != value)
1461 return(0);
1462
1463 return(1);
1464}
1465
1466/*
1467 * st_SetFortification - Set the _size_ bytes from _ptr_ to _value_.
1468 */
1469static void
1470st_SetFortification(unsigned char *ptr, unsigned char value, size_t size)
1471{
1472 memset(ptr, value, size);
1473}
1474
1475/*
1476 * st_OutputFortification - Output the corrupted section of the fortification
1477 */
1478static void
1479st_OutputFortification(unsigned char *ptr, unsigned char value, size_t size)
1480{
1481 size_t offset, skipped, advance;
1482 offset = 0;
1483
1484 sprintf(st_Buffer, " Address Offset Data (%02x)", value);
1485 st_Output(st_Buffer);
1486
1487 while(offset < size)
1488 {
1489 /*
1490 * Skip 3 or more 'correct' lines
1491 */
1492 if((size - offset) < 3 * 16)
1493 advance = size - offset;
1494 else
1495 advance = 3 * 16;
1496 if(advance > 0 && st_CheckFortification(ptr+offset, value, advance))
1497 {
1498 offset += advance;
1499 skipped = advance;
1500
1501 if(size - offset < 16)
1502 advance = size - offset;
1503 else
1504 advance = 16;
1505
1506 while(advance > 0 && st_CheckFortification(ptr+offset, value, advance))
1507 {
1508 offset += advance;
1509 skipped += advance;
1510 if(size - offset < 16)
1511 advance = size - offset;
1512 else
1513 advance = 16;
1514 }
1515 sprintf(st_Buffer, "\n ...%lu bytes skipped...", (unsigned long)skipped);
1516 st_Output(st_Buffer);
1517 continue;
1518 }
1519 else
1520 {
1521 if(size - offset < 16)
1522 st_HexDump(ptr, offset, size-offset, 0);
1523 else
1524 st_HexDump(ptr, offset, 16, 0);
1525
1526 offset += 16;
1527 }
1528 }
1529
1530 st_Output("\n");
1531}
1532
1533/*
1534 * st_HexDump - output a nice hex dump of "size" bytes, starting at "ptr" + "offset"
1535 */
1536static void
1537st_HexDump(unsigned char *ptr, size_t offset, size_t size, int title)
1538{
1539 char ascii[17];
1540 int column;
1541 int output;
1542
1543 if(title)
1544 st_Output(" Address Offset Data");
1545
1546 column = 0;
1547 ptr += offset;
1548 output = 0;
1549
1550 while(output < size)
1551 {
1552 if(column == 0)
1553 {
1554#ifdef FORTIFY_NO_PERCENT_P
1555 sprintf(st_Buffer, "\n0x%08lx %8lu ", ptr, (unsigned long)offset);
1556#else
1557 sprintf(st_Buffer, "\n%10p %8lu ", ptr, (unsigned long)offset);
1558#endif
1559 st_Output(st_Buffer);
1560 }
1561
1562 sprintf(st_Buffer, "%02x%s", *ptr, ((column % 4) == 3) ? " " : "");
1563 st_Output(st_Buffer);
1564
1565 ascii[ column ] = isprint( *ptr ) ? (char)(*ptr) : (char)('.');
1566 ascii[ column + 1 ] = '\0';
1567
1568 ptr++;
1569 offset++;
1570 output++;
1571 column++;
1572
1573 if(column == 16)
1574 {
1575 st_Output( " \"" );
1576 st_Output( ascii );
1577 st_Output( "\"" );
1578 column = 0;
1579 }
1580 }
1581
1582 if ( column != 0 )
1583 {
1584 while ( column < 16 )
1585 {
1586 if( column % 4 == 3 )
1587 st_Output( " " );
1588 else
1589 st_Output( " " );
1590
1591 column++;
1592 }
1593 st_Output( " \"" );
1594 st_Output( ascii );
1595 st_Output( "\"" );
1596 }
1597}
1598
1599/*
1600 * st_IsHeaderValid - Returns true if the
1601 * supplied pointer does indeed point to a
1602 * real Header
1603 */
1604static int
1605st_IsHeaderValid(struct Header *h)
1606{
1607 return(st_ChecksumHeader(h) == FORTIFY_CHECKSUM_VALUE);
1608}
1609
1610/*
1611 * st_MakeHeaderValid - Updates the checksum
1612 * to make the header valid
1613 */
1614static void
1615st_MakeHeaderValid(struct Header *h)
1616{
1617 h->Checksum = 0;
1618 h->Checksum = (unsigned short)(FORTIFY_CHECKSUM_VALUE - st_ChecksumHeader(h));
1619}
1620
1621/*
1622 * st_ChecksumHeader - Calculate (and return)
1623 * the checksum of the header. (Including the
1624 * Checksum field itself. If all is well, the
1625 * checksum returned by this function should
1626 * be FORTIFY_CHECKSUM_VALUE
1627 */
1628static unsigned short
1629st_ChecksumHeader(struct Header *h)
1630{
1631 unsigned short c, checksum, *p;
1632
1633 for(c = 0, checksum = 0, p = (unsigned short *)h;
1634 c < FORTIFY_HEADER_SIZE/sizeof(unsigned short); c++)
1635 {
1636 checksum += *p++;
1637 }
1638
1639 return(checksum);
1640}
1641
1642/*
1643 * st_IsOnAllocatedList - Examines the allocated
1644 * list to see if the given header is on it.
1645 */
1646static int
1647st_IsOnAllocatedList(struct Header *h)
1648{
1649 struct Header *curr;
1650
1651 curr = st_AllocatedHead;
1652 while(curr)
1653 {
1654 if(curr == h)
1655 return(1);
1656
1657 curr = curr->Next;
1658 }
1659
1660 return(0);
1661}
1662
1663#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
1664/*
1665 * st_IsOnDeallocatedList - Examines the deallocated
1666 * list to see if the given header is on it.
1667 */
1668static int
1669st_IsOnDeallocatedList(struct Header *h)
1670{
1671 struct Header *curr;
1672
1673 curr = st_DeallocatedHead;
1674 while(curr)
1675 {
1676 if(curr == h)
1677 return(1);
1678
1679 curr = curr->Next;
1680 }
1681
1682 return(0);
1683}
1684
1685/*
1686 * st_PurgeDeallocatedBlocks - free at least "Bytes"
1687 * worth of deallocated memory, starting at the
1688 * oldest deallocated block.
1689 * Returns true if any blocks were freed.
1690 */
1691static int
1692st_PurgeDeallocatedBlocks(unsigned long Bytes, const char *file, unsigned long line)
1693{
1694 unsigned long FreedBytes = 0;
1695 unsigned long FreedBlocks = 0;
1696
1697#ifdef FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
1698 sprintf(st_Buffer, "\nFortify: Warning - Discarding deallocated memory at %s.%lu\n",
1699 file, line);
1700 st_Output(st_Buffer);
1701#endif /* FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
1702
1703 while(st_DeallocatedTail && FreedBytes < Bytes)
1704 {
1705 st_CheckDeallocatedBlock(st_DeallocatedTail, file, line);
1706 FreedBytes += st_DeallocatedTail->Size;
1707 FreedBlocks++;
1708#ifdef FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
1709#ifdef FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
1710 sprintf(st_Buffer, " %s\n",
1711 st_DeallocatedMemoryBlockString(st_DeallocatedTail));
1712 st_Output(st_Buffer);
1713#endif /* FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
1714#endif /* FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
1715 st_FreeDeallocatedBlock(st_DeallocatedTail, file, line);
1716 }
1717
1718 return FreedBlocks != 0;
1719}
1720
1721/*
1722 * st_PurgeDeallocatedScope - free all deallocated
1723 * memory blocks that were allocated within "Scope"
1724 */
1725static int
1726st_PurgeDeallocatedScope(unsigned char Scope, const char *file, unsigned long line)
1727{
1728 struct Header *curr, *next;
1729 unsigned long FreedBlocks = 0;
1730#ifdef MT_SCOPES
1731 unsigned ordinal = Get_TID_Ordinal();
1732#endif
1733
1734 curr = st_DeallocatedHead;
1735 while(curr)
1736 {
1737 next = curr->Next;
1738#ifdef MT_SCOPES
1739 if(curr->Owner == ordinal && curr->Scope >= Scope)
1740#else
1741 if(curr->Scope >= Scope)
1742#endif
1743 {
1744 st_FreeDeallocatedBlock(curr, file, line);
1745 FreedBlocks++;
1746 }
1747
1748 curr = next;
1749 }
1750
1751 return FreedBlocks != 0;
1752}
1753
1754/*
1755 * st_FreeDeallocatedBlock - actually remove
1756 * a deallocated block from the deallocated
1757 * list, and actually free it's memory.
1758 */
1759static void
1760st_FreeDeallocatedBlock(struct Header *h, const char *file, unsigned long line)
1761{
1762 st_CheckDeallocatedBlock( h, file, line );
1763
1764 /*
1765 * Begin Critical region
1766 */
1767 FORTIFY_LOCK();
1768
1769 st_TotalDeallocated -= h->Size;
1770
1771 if(st_DeallocatedHead == h)
1772 {
1773 st_DeallocatedHead = h->Next;
1774 }
1775
1776 if(st_DeallocatedTail == h)
1777 {
1778 st_DeallocatedTail = h->Prev;
1779 }
1780
1781 if(h->Prev)
1782 {
1783 st_CheckDeallocatedBlock(h->Prev, file, line);
1784 h->Prev->Next = h->Next;
1785 st_MakeHeaderValid(h->Prev);
1786 }
1787
1788 if(h->Next)
1789 {
1790 st_CheckDeallocatedBlock(h->Next, file, line);
1791 h->Next->Prev = h->Prev;
1792 st_MakeHeaderValid(h->Next);
1793 }
1794
1795 /*
1796 * Free the label
1797 */
1798 if(h->Label)
1799 {
1800 free(h->Label);
1801 }
1802
1803 /*
1804 * Nuke out all memory that is about to be freed, including the header
1805 */
1806 st_SetFortification((unsigned char*)h, FORTIFY_FILL_ON_DEALLOCATE_VALUE,
1807 FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size + FORTIFY_AFTER_SIZE);
1808
1809 /*
1810 * And do the actual free
1811 */
1812 free(h);
1813
1814 /*
1815 * End critical region
1816 */
1817 FORTIFY_UNLOCK();
1818}
1819
1820#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
1821
1822/*
1823 * st_OutputMemory - Hex and ascii dump the
1824 * user memory of a block.
1825 */
1826static void
1827st_OutputMemory(struct Header *h)
1828{
1829 st_HexDump((unsigned char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1830 0, h->Size, 1);
1831}
1832
1833
1834/*
1835 * st_OutputHeader - Output the header
1836 */
1837static void
1838st_OutputHeader(struct Header *h)
1839{
1840 if(h->Label == NULL)
1841 {
1842#ifdef FORTIFY_NO_PERCENT_P
1843 sprintf(st_Buffer, "0x%08lx %8lu %s.%lu\n",
1844#else
1845 sprintf(st_Buffer, "%10p %8lu %s.%lu\n",
1846#endif
1847 (unsigned char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1848 (unsigned long)h->Size,
1849 h->File, h->Line);
1850 }
1851 else
1852 {
1853#ifdef FORTIFY_NO_PERCENT_P
1854 sprintf(st_Buffer, "0x%08lx %8lu %s.%lu %s\n",
1855#else
1856 sprintf(st_Buffer, "%10p %8lu %s.%lu %s\n",
1857#endif
1858 (unsigned char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1859 (unsigned long)h->Size,
1860 h->File, h->Line, h->Label);
1861 }
1862 st_Output(st_Buffer);
1863}
1864
1865/*
1866 * st_OutputLastVerifiedPoint - output the last
1867 * known point where everything was hoopy.
1868 */
1869static void
1870st_OutputLastVerifiedPoint()
1871{
1872 sprintf(st_Buffer, " Memory integrity was last verified at %s.%lu\n",
1873 st_LastVerifiedFile,
1874 st_LastVerifiedLine);
1875 st_Output(st_Buffer);
1876}
1877
1878/*
1879 * st_MemoryBlockString - constructs a string that
1880 * desribes a memory block. (pointer,size,allocator,label)
1881 */
1882static const char *
1883st_MemoryBlockString(struct Header *h)
1884{
1885 static char st_BlockString[512];
1886
1887 if(h->Label == 0)
1888 {
1889#ifdef FORTIFY_NO_PERCENT_P
1890 sprintf(st_BlockString,"(0x%08lx,%lu,%s.%lu)",
1891#else
1892 sprintf(st_BlockString,"(%p,%lu,%s.%lu)",
1893#endif
1894 (char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1895 (unsigned long)h->Size, h->File, h->Line);
1896 }
1897 else
1898 {
1899#ifdef FORTIFY_NO_PERCENT_P
1900 sprintf(st_BlockString,"(0x%08lx,%lu,%s.%lu,%s)",
1901#else
1902 sprintf(st_BlockString,"(%p,%lu,%s.%lu,%s)",
1903#endif
1904 (char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1905 (unsigned long)h->Size, h->File, h->Line, h->Label);
1906 }
1907
1908 return st_BlockString;
1909}
1910
1911#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
1912#ifdef FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
1913#ifdef FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
1914/*
1915 * st_DeallocatedMemoryBlockString - constructs
1916 * a string that desribes a deallocated memory
1917 * block. (pointer,size,allocator,deallocator)
1918 */
1919
1920static const char *
1921st_DeallocatedMemoryBlockString(struct Header *h)
1922{
1923 static char st_BlockString[256];
1924
1925 if(h->Label == 0)
1926 {
1927#ifdef FORTIFY_NO_PERCENT_P
1928 sprintf(st_BlockString,"(0x%08lx,%lu,%s.%lu,%s.%lu)",
1929#else
1930 sprintf(st_BlockString,"(%p,%lu,%s.%lu,%s.%lu)",
1931#endif
1932 (char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1933 (unsigned long)h->Size, h->File, h->Line, h->FreedFile, h->FreedLine);
1934 }
1935 else
1936 {
1937#ifdef FORTIFY_NO_PERCENT_P
1938 sprintf(st_BlockString,"(0x%08lx,%lu,%s.%lu,%s.%lu,%s)",
1939#else
1940 sprintf(st_BlockString,"(%p,%lu,%s.%lu,%s.%lu,%s)",
1941#endif
1942 (char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
1943 (unsigned long)h->Size, h->File, h->Line, h->FreedFile, h->FreedLine, h->Label);
1944 }
1945
1946 return st_BlockString;
1947}
1948#endif /* FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
1949#endif /* FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
1950#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
1951
1952
1953/*
1954 * st_DefaultOutput - the default output function
1955 */
1956static void
1957st_DefaultOutput(const char *String)
1958{
1959 fprintf(stdout, String);
1960 fflush(stdout);
1961}
1962
1963/*
1964 * Fortify_malloc - Fortify's replacement malloc()
1965 */
1966void *FORTIFY_STORAGE
1967Fortify_malloc(size_t size, const char *file, unsigned long line)
1968{
1969 return Fortify_Allocate(size, Fortify_Allocator_malloc, file, line);
1970}
1971
1972/*
1973 * Fortify_realloc - Fortify's replacement realloc()
1974 */
1975void * FORTIFY_STORAGE // 28 Jan 08 SHL
1976Fortify_realloc(void *uptr, size_t new_size, const char *file, unsigned long line)
1977{
1978 unsigned char *ptr = (unsigned char *)uptr - FORTIFY_HEADER_SIZE - FORTIFY_ALIGNED_BEFORE_SIZE;
1979 struct Header *h = (struct Header *)ptr;
1980 void *new_ptr;
1981
1982 /*
1983 * If Fortify is disabled, we gotta do this a little
1984 * differently.
1985 */
1986 if(!st_Disabled)
1987 {
1988 if(!uptr)
1989 return(Fortify_Allocate(new_size, Fortify_Allocator_realloc, file, line));
1990
1991 if(!st_IsOnAllocatedList(h))
1992 {
1993#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
1994 if(st_IsOnDeallocatedList(h))
1995 {
1996 sprintf(st_Buffer, "\nFortify: Deallocated memory block passed to \"%s\" at %s.%lu\n",
1997 st_AllocatorName[Fortify_Allocator_realloc], file, line);
1998 st_Output(st_Buffer);
1999 sprintf(st_Buffer, " Memory block %s was deallocated by \"%s\" at %s.%lu\n",
2000 st_MemoryBlockString(h),
2001 st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
2002 st_Output(st_Buffer);
2003 return 0;
2004 }
2005#endif
2006
2007 sprintf(st_Buffer,
2008#ifdef FORTIFY_NO_PERCENT_P
2009 "\nFortify: Invalid pointer (0x%08lx) passed to realloc at %s.%lu\n",
2010#else
2011 "\nFortify: Invalid pointer (%p) passed to realloc at %s.%lu\n",
2012#endif
2013 ptr, file, line);
2014 st_Output(st_Buffer);
2015 return 0;
2016 }
2017
2018 if(!st_CheckBlock(h, file, line))
2019 return 0;
2020
2021 new_ptr = Fortify_Allocate(new_size, Fortify_Allocator_realloc, file, line);
2022 if(!new_ptr)
2023 {
2024 return(0);
2025 }
2026
2027 if(h->Size < new_size)
2028 memcpy(new_ptr, uptr, h->Size);
2029 else
2030 memcpy(new_ptr, uptr, new_size);
2031
2032 Fortify_Deallocate(uptr, Fortify_Deallocator_realloc, file, line);
2033 return(new_ptr);
2034 }
2035 else
2036 {
2037 /*
2038 * If the old block was fortified, we can't use normal realloc.
2039 */
2040 if(st_IsOnAllocatedList(h))
2041 {
2042 new_ptr = Fortify_Allocate(new_size, Fortify_Allocator_realloc, file, line);
2043 if(!new_ptr)
2044 return(0);
2045
2046 if(h->Size < new_size)
2047 memcpy(new_ptr, uptr, h->Size);
2048 else
2049 memcpy(new_ptr, uptr, new_size);
2050
2051 Fortify_Deallocate(uptr, Fortify_Deallocator_realloc, file, line);
2052 return(new_ptr);
2053 }
2054 else /* easy */
2055 {
2056 return realloc(uptr, new_size);
2057 }
2058 }
2059}
2060
2061/*
2062 * Fortify_calloc - Fortify's replacement calloc
2063 */
2064void *
2065Fortify_calloc(size_t num, size_t size, const char *file, unsigned long line)
2066{
2067 if(!st_Disabled)
2068 {
2069 void *ptr = Fortify_Allocate(size * num, Fortify_Allocator_calloc, file, line);
2070 if(ptr)
2071 {
2072 memset(ptr, 0, size*num);
2073 }
2074 return ptr;
2075 }
2076 else
2077 {
2078 return calloc(num, size);
2079 }
2080}
2081
2082/*
2083 * Fortify_free - Fortify's replacement free
2084 */
2085void FORTIFY_STORAGE // 28 Jan 08 SHL
2086Fortify_free(void *uptr, const char *file, unsigned long line)
2087{
2088 /* it is defined to be safe to free(0) */
2089 if(uptr == 0)
2090 return;
2091
2092 Fortify_Deallocate(uptr, Fortify_Deallocator_free, file, line);
2093}
2094
2095/*
2096 * Fortify_strdup - Fortify's replacement strdup. Since strdup isn't
2097 * ANSI, it is only provided if FORTIFY_STRDUP is defined.
2098 */
2099#ifdef FORTIFY_STRDUP
2100char *FORTIFY_STORAGE
2101Fortify_strdup(const char *oldStr, const char *file, unsigned long line)
2102{
2103 if(!st_Disabled)
2104 {
2105 char *newStr = (char *)Fortify_Allocate(strlen(oldStr)+1, Fortify_Allocator_strdup, file, line);
2106 if(newStr)
2107 {
2108 strcpy(newStr, oldStr);
2109 }
2110
2111 return newStr;
2112 }
2113 else
2114 {
2115 return strdup(oldStr);
2116 }
2117}
2118#endif /* FORTIFY_STRDUP */
2119
2120static void
2121st_OutputDeleteTrace()
2122{
2123#ifdef __cplusplus
2124 if(st_DeleteStackTop > 1)
2125 {
2126 sprintf(st_Buffer, "Delete Trace: %s.%lu\n", st_DeleteFile[st_DeleteStackTop-1],
2127 st_DeleteLine[st_DeleteStackTop-1]);
2128 st_Output(st_Buffer);
2129 for(int c = st_DeleteStackTop-2; c >= 0; c--)
2130 {
2131 sprintf(st_Buffer, " %s.%lu\n", st_DeleteFile[c],
2132 st_DeleteLine[c]);
2133 st_Output(st_Buffer);
2134 }
2135 }
2136#endif
2137}
2138
2139#ifdef __cplusplus
2140
2141/*
2142 * st_NewHandler() - there is no easy way to get
2143 * the new handler function. And isn't it great
2144 * how the new handler doesn't take a parameter
2145 * giving the size of the request that failed.
2146 * Thanks Bjarne!
2147 */
2148Fortify_NewHandlerFunc
2149st_NewHandler()
2150{
2151 /* get the current handler */
2152 Fortify_NewHandlerFunc handler = set_new_handler(0);
2153
2154 /* and set it back (since we cant
2155 * get it without changing it)
2156 */
2157 set_new_handler(handler);
2158
2159 return handler;
2160}
2161
2162/*
2163 * operator new - Fortify's replacement new,
2164 * without source-code information.
2165 */
2166void *FORTIFY_STORAGE
2167operator new(size_t size)
2168{
2169 void *p;
2170
2171 while((p = Fortify_Allocate(size, Fortify_Allocator_new,
2172 st_AllocatorName[Fortify_Allocator_new], 0)) == 0)
2173 {
2174 if(st_NewHandler())
2175 (*st_NewHandler())();
2176 else
2177 return 0;
2178 }
2179
2180 return p;
2181}
2182
2183/*
2184 * operator new - Fortify's replacement new,
2185 * with source-code information
2186 */
2187void *FORTIFY_STORAGE
2188operator new(size_t size, const char *file, int line)
2189{
2190 void *p;
2191
2192 while((p = Fortify_Allocate(size, Fortify_Allocator_new, file, line)) == 0)
2193 {
2194 if(st_NewHandler())
2195 (*st_NewHandler())();
2196 else
2197 return 0;
2198 }
2199
2200 return p;
2201}
2202
2203#ifdef FORTIFY_PROVIDE_ARRAY_NEW
2204
2205/*
2206 * operator new[], without source-code info
2207 */
2208void *FORTIFY_STORAGE
2209operator new[](size_t size)
2210{
2211 void *p;
2212
2213 while((p = Fortify_Allocate(size, Fortify_Allocator_array_new,
2214 st_AllocatorName[Fortify_Allocator_array_new], 0)) == 0)
2215 {
2216 if(st_NewHandler())
2217 (*st_NewHandler())();
2218 else
2219 return 0;
2220 }
2221
2222 return p;
2223}
2224
2225/*
2226 * operator new[], with source-code info
2227 */
2228void *FORTIFY_STORAGE
2229operator new[](size_t size, const char *file, unsigned long line)
2230{
2231 void *p;
2232
2233 while((p = Fortify_Allocate(size, Fortify_Allocator_array_new, file, line)) == 0)
2234 {
2235 if(st_NewHandler())
2236 (*st_NewHandler())();
2237 else
2238 return 0;
2239 }
2240
2241 return p;
2242}
2243
2244#endif /* FORTIFY_PROVIDE_ARRAY_NEW */
2245
2246/*
2247 * Fortify_PreDelete - C++ does not allow overloading
2248 * of delete, so the delete macro calls Fortify_PreDelete
2249 * with the source-code info, and then calls delete.
2250 */
2251void FORTIFY_STORAGE
2252Fortify_PreDelete(const char *file, int line)
2253{
2254 FORTIFY_LOCK();
2255
2256 /*
2257 * Push the source code info for the delete onto the delete stack
2258 * (if we have enough room, of course)
2259 */
2260 if(st_DeleteStackTop < FORTIFY_DELETE_STACK_SIZE)
2261 {
2262 st_DeleteFile[st_DeleteStackTop] = file;
2263 st_DeleteLine[st_DeleteStackTop] = line;
2264 }
2265
2266 st_DeleteStackTop++;
2267}
2268
2269/*
2270 * Fortify_PostDelete() - Pop the delete source-code info
2271 * off the source stack.
2272 */
2273void FORTIFY_STORAGE
2274Fortify_PostDelete()
2275{
2276 st_DeleteStackTop--;
2277
2278 FORTIFY_UNLOCK();
2279}
2280
2281/*
2282 * operator delete - fortify's replacement delete
2283 */
2284void FORTIFY_STORAGE
2285operator delete(void *uptr)
2286{
2287 const char *file;
2288 unsigned long line;
2289
2290 /*
2291 * It is defined to be harmless to delete 0
2292 */
2293 if(uptr == 0)
2294 return;
2295
2296 /*
2297 * find the source-code info
2298 */
2299 if(st_DeleteStackTop)
2300 {
2301 if(st_DeleteStackTop < FORTIFY_DELETE_STACK_SIZE)
2302 {
2303 file = st_DeleteFile[st_DeleteStackTop-1];
2304 line = st_DeleteLine[st_DeleteStackTop-1];
2305 }
2306 else
2307 {
2308 file = st_DeleteFile[FORTIFY_DELETE_STACK_SIZE-1];
2309 line = st_DeleteLine[FORTIFY_DELETE_STACK_SIZE-1];
2310 }
2311 }
2312 else
2313 {
2314 file = st_DeallocatorName[Fortify_Deallocator_delete];
2315 line = 0;
2316 }
2317
2318 Fortify_Deallocate(uptr, Fortify_Deallocator_delete, file, line);
2319}
2320
2321#ifdef FORTIFY_PROVIDE_ARRAY_DELETE
2322
2323/*
2324 * operator delete[] - fortify's replacement delete[]
2325 */
2326void FORTIFY_STORAGE
2327operator delete[](void *uptr)
2328{
2329 const char *file;
2330 unsigned long line;
2331
2332 /*
2333 * It is defined to be harmless to delete 0
2334 */
2335 if(uptr == 0)
2336 return;
2337
2338 /*
2339 * find the source-code info
2340 */
2341 if(st_DeleteStackTop)
2342 {
2343 if(st_DeleteStackTop < FORTIFY_DELETE_STACK_SIZE)
2344 {
2345 file = st_DeleteFile[st_DeleteStackTop-1];
2346 line = st_DeleteLine[st_DeleteStackTop-1];
2347 }
2348 else
2349 {
2350 file = st_DeleteFile[FORTIFY_DELETE_STACK_SIZE-1];
2351 line = st_DeleteLine[FORTIFY_DELETE_STACK_SIZE-1];
2352 }
2353 }
2354 else
2355 {
2356 file = st_DeallocatorName[Fortify_Deallocator_array_delete];
2357 line = 0;
2358 }
2359
2360 Fortify_Deallocate(uptr, Fortify_Deallocator_array_delete, file, line);
2361}
2362
2363#endif /* FORTIFY_PROVIDE_ARRAY_DELETE */
2364
2365#ifdef FORTIFY_AUTOMATIC_LOG_FILE
2366/* Automatic log file stuff!
2367 *
2368 * AutoLogFile class. There can only ever be ONE of these
2369 * instantiated! It is a static class, which means that
2370 * it's constructor will be called at program initialization,
2371 * and it's destructor will be called at program termination.
2372 * We don't know if the other static class objects have been
2373 * constructed/destructed yet, but this pretty much the best
2374 * we can do with standard C++ language features.
2375 */
2376class Fortify_AutoLogFile
2377{
2378 static FILE *fp;
2379 static int written_something;
2380 static char *init_string, *term_string;
2381
2382public:
2383 Fortify_AutoLogFile()
2384 {
2385 written_something = 0;
2386 Fortify_SetOutputFunc(Fortify_AutoLogFile::Output);
2387 Fortify_EnterScope(init_string, 0);
2388 }
2389
2390 static void Output(const char *s)
2391 {
2392 if(written_something == 0)
2393 {
2394 FORTIFY_FIRST_ERROR_FUNCTION;
2395 fp = fopen(FORTIFY_LOG_FILENAME, "w");
2396 if(fp)
2397 {
2398 time_t t;
2399 time(&t);
2400 fprintf(fp, "Fortify log started at %s\n", ctime(&t));
2401 written_something = 1;
2402 }
2403 }
2404
2405 if(fp)
2406 {
2407 fputs(s, fp);
2408 fflush(fp);
2409 }
2410 }
2411
2412 ~Fortify_AutoLogFile()
2413 {
2414 Fortify_LeaveScope(term_string, 0);
2415 Fortify_CheckAllMemory(term_string, 0);
2416 if(fp)
2417 {
2418 time_t t;
2419 time(&t);
2420 fprintf(fp, "\nFortify log closed at %s\n", ctime(&t));
2421 fclose(fp);
2422 fp = 0;
2423 }
2424 }
2425};
2426
2427FILE *Fortify_AutoLogFile::fp = 0;
2428int Fortify_AutoLogFile::written_something = 0;
2429char *Fortify_AutoLogFile::init_string = "Program Initialization";
2430char *Fortify_AutoLogFile::term_string = "Program Termination";
2431
2432static Fortify_AutoLogFile Abracadabra;
2433
2434#endif /* FORTIFY_AUTOMATIC_LOG_FILE */
2435
2436#endif /* __cplusplus */
2437
2438#ifdef MT_SCOPES
2439
2440/**
2441 * Set/reset owner of blocks allocated by this thread
2442 * Use when worker thread will allocate blocks for another thread
2443 * and other thread is known
2444 * More efficient than Fortify_ChangeOwner
2445 * @param lOwnerTID is new owner TID, -1 requests reset of self
2446 */
2447
2448void Fortify_SetOwner(long lOwnerTID)
2449{
2450 unsigned ordinal = Get_TID_Ordinal();
2451
2452 if (ordinal >= st_cOrdinals) {
2453 // Expand arrays
2454 unsigned i;
2455 unsigned c;
2456 FORTIFY_LOCK();
2457 i = st_cOrdinals;
2458 c = ordinal + 1;
2459 st_pScopes = realloc((void*)st_pScopes, sizeof(*st_pScopes) * c);
2460 st_pOwners = realloc((void*)st_pOwners, sizeof(*st_pOwners) * c);
2461 for (; i <= ordinal; i++) {
2462 st_pScopes[i] = 0;
2463 st_pOwners[i] = i; // Block owner is self
2464 }
2465 st_cOrdinals = c;
2466 FORTIFY_UNLOCK();
2467 }
2468 // Set owner for blocks allocated by this thread
2469 st_pOwners[ordinal] = lOwnerTID != -1 ? lOwnerTID : ordinal;
2470}
2471
2472/**
2473 * Take ownership of block allocated by some other thread
2474 * Allows scope enter/exit logic to correctly report leaks in
2475 * cross thread allocations
2476 * @param pBlock points to block allocated by Fortify
2477 */
2478
2479void Fortify_ChangeOwner(void *pBlock)
2480{
2481 unsigned char *ptr = (unsigned char *)pBlock -
2482 FORTIFY_HEADER_SIZE -
2483 FORTIFY_ALIGNED_BEFORE_SIZE;
2484 struct Header *h = (struct Header *)ptr;
2485
2486 unsigned ordinal = Get_TID_Ordinal();
2487
2488 h->Scope = ordinal < st_cOrdinals ? st_pScopes[ordinal] : 0;
2489 h->Owner = ordinal; // Take ownership
2490 st_MakeHeaderValid(h);
2491}
2492
2493/**
2494 * Adjust scope level of allocated block
2495 * Allows scope enter/exit logic to correctly report leaks in
2496 * window procedure related allocations
2497 * @param pBlock points to block allocated by Fortify
2498 */
2499
2500void Fortify_ChangeScope(void *pBlock, int delta)
2501{
2502 unsigned char *ptr = (unsigned char *)pBlock -
2503 FORTIFY_HEADER_SIZE -
2504 FORTIFY_ALIGNED_BEFORE_SIZE;
2505 struct Header *h = (struct Header *)ptr;
2506 h->Scope += delta;
2507 st_MakeHeaderValid(h);
2508}
2509
2510#endif // MT_SCOPES
2511
2512#endif /* FORTIFY */
Note: See TracBrowser for help on using the repository browser.