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