source: trunk/dll/fortify.c@ 1072

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

Add Fortify_SetOwner Fortify_ChangeOwner to support cross thread allocations

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