source: trunk/dll/fortify.c@ 1036

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

Show TID for leaking scope

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