source: trunk/dll/fortify.c@ 1015

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

Add missing svn:keyword and svn:eol-style properties

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.3 KB
Line 
1
2/* $Id: fortify.c 1015 2008-05-12 01:18:01Z stevenhl $ */
3/* fortify.cxx - A fortified memory allocation shell - V2.2 */
4
5/*
6 * This software is not public domain. All material in
7 * this archive is (C) Copyright 1995 Simon P. Bullen. The
8 * software is freely distributable, with the condition that
9 * no more than a nominal fee is charged for media.
10 * Everything in this distribution must be kept together, in
11 * original, unmodified form.
12 * The software may be modified for your own personal use,
13 * but modified files may not be distributed.
14 * The material is provided "as is" without warranty of
15 * any kind. The author accepts no responsibility for damage
16 * caused by this software.
17 * This software may not be used in any way by Microsoft
18 * Corporation or its subsidiaries, or current employees of
19 * Microsoft Corporation or its subsidiaries.
20 * This software may not be used for the construction,
21 * development, production, or testing of weapon systems of
22 * any kind.
23 * This software may not be used for the construction,
24 * development, production, or use of plants/installations
25 * which include the processing of radioactive/fissionable
26 * material.
27 */
28
29/*
30 * If you use this software at all, I'd love to hear from
31 * you. All questions, criticisms, suggestions, praise and
32 * postcards are most welcome.
33 *
34 * email: sbullen@cybergraphic.com.au
35 *
36 * snail: Simon P. Bullen
37 * PO BOX 12138
38 * A'Beckett St.
39 * Melbourne 3000
40 * Australia
41 */
42
43 /* 06 May 08 SHL Rework scope logic to be MT capable
44 */
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.