source: trunk/dll/fortify.c@ 1005

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

Add baseline fortify support

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