source: trunk/dll/fortify.c@ 1009

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

Add xfree xstrdup Fortify support
Add MT capable Fortify scope logic

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