source: trunk/dll/fortify.c@ 1673

Last change on this file since 1673 was 1673, checked in by Gregg Young, 13 years ago

Update to Doxygen comment style Ticket 55. Also some minor code cleanup.

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