📄 fortify.c
字号:
/* fortify.cxx - A fortified memory allocation shell - V2.2 */
/*
* This software is not public domain. All material in
* this archive is (C) Copyright 1995 Simon P. Bullen. The
* software is freely distributable, with the condition that
* no more than a nominal fee is charged for media.
* Everything in this distribution must be kept together, in
* original, unmodified form.
*
* The software may be modified for your own personal use,
* but modified files may not be distributed.
*
* The material is provided "as is" without warranty of
* any kind. The author accepts no responsibility for damage
* caused by this software.
*
* This software may not be used in any way by Microsoft
* Corporation or its subsidiaries, or current employees of
* Microsoft Corporation or its subsidiaries.
*
* This software may not be used for the construction,
* development, production, or testing of weapon systems of
* any kind.
*
* This software may not be used for the construction,
* development, production, or use of plants/installations
* which include the processing of radioactive/fissionable
* material.
*/
/*
* If you use this software at all, I'd love to hear from
* you. All questions, criticisms, suggestions, praise and
* postcards are most welcome.
*
* email: sbullen@cybergraphic.com.au
*
* snail: Simon P. Bullen
* PO BOX 12138
* A'Beckett St.
* Melbourne 3000
* Australia
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <ctype.h>
#include <time.h>
/* Prototypes and such */
#define __FORTIFY_C__
#include "wattcp.h"
#include "misc.h"
#if (DOSX) /* Using inchksum_fast() function */
#undef FORTIFY_CHECKSUM_VALUE
#define FORTIFY_CHECKSUM_VALUE 0xFFFF
#endif
#include "fortify.h"
#include "chksum.h"
#if defined(USE_FORTIFY) || defined(USE_BSD_FORTIFY)
#define STATIC
/*
* struct Header - this structure is used
* internally by Fortify to manage it's
* own private lists of memory.
*/
struct Header {
WORD Checksum; /* For the integrity of our goodies */
const char *File; /* The sourcefile of the allocator */
DWORD Line; /* The sourceline of the allocator */
#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
const char *FreedFile; /* The sourcefile of the deallocator */
DWORD FreedLine; /* The sourceline of the deallocator */
BYTE Deallocator; /* The deallocator used */
#endif
size_t Size; /* The size of the malloc'd block */
struct Header *Prev; /* Previous link */
struct Header *Next; /* Next link */
char *Label; /* User's Label (may be null) */
BYTE Scope; /* Scope level of the caller */
BYTE Allocator; /* malloc/realloc/new/etc */
};
/*
* Round x up to the nearest multiple of n.
*/
#define ROUND_UP(x,n) ((((x) + (n)-1)/(n))*(n))
#define FORTIFY_HEADER_SIZE ROUND_UP(sizeof(struct Header), sizeof(WORD))
/*
* FORTIFY_ALIGNED_BEFORE_SIZE is FORTIFY_BEFORE_SIZE rounded up to the
* next multiple of FORTIFY_ALIGNMENT. This is so that we can guarantee
* the alignment of user memory for such systems where this is important
* (eg storing doubles on a SPARC)
*/
#define FORTIFY_ALIGNED_BEFORE_SIZE ( \
ROUND_UP (FORTIFY_HEADER_SIZE+FORTIFY_BEFORE_SIZE, FORTIFY_ALIGNMENT) \
- FORTIFY_HEADER_SIZE)
/*
* FORTIFY_OVERHEAD is the total overhead added by Fortify to each
* memory block.
*/
#define FORTIFY_OVERHEAD (FORTIFY_HEADER_SIZE + \
FORTIFY_ALIGNED_BEFORE_SIZE + \
FORTIFY_AFTER_SIZE)
/*
* Static Function Prototypes
*/
STATIC int st_CheckBlock (struct Header *h, const char *file, DWORD line);
STATIC int st_CheckFortification (BYTE *ptr, BYTE value, size_t size);
STATIC void st_SetFortification (BYTE *ptr, BYTE value, size_t size);
STATIC void st_OutputFortification(BYTE *ptr, BYTE value, size_t size);
STATIC void st_HexDump (BYTE *ptr, size_t offset, size_t size, int title);
STATIC int st_IsHeaderValid (struct Header *h);
STATIC void st_MakeHeaderValid (struct Header *h);
STATIC WORD st_ChecksumHeader (struct Header *h);
STATIC int st_IsOnAllocatedList (struct Header *h);
STATIC void st_OutputHeader (struct Header *h);
STATIC void st_OutputMemory (struct Header *h);
STATIC void st_OutputLastVerifiedPoint(void);
STATIC void st_DefaultOutput (const char *String);
STATIC const char *st_MemoryBlockString(struct Header *h);
STATIC void st_OutputDeleteTrace (void);
#if defined (FORTIFY_TRACK_DEALLOCATED_MEMORY)
#if defined (FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY) && \
defined (FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY)
STATIC const char *st_DeallocatedMemoryBlockString(struct Header *h);
#endif
STATIC int st_IsOnDeallocatedList(struct Header *h);
STATIC int st_PurgeDeallocatedBlocks(DWORD Bytes, const char *file, DWORD line);
STATIC int st_PurgeDeallocatedScope(BYTE Scope, const char *file, DWORD line);
STATIC int st_CheckDeallocatedBlock(struct Header *h, const char *file, DWORD line);
STATIC void st_FreeDeallocatedBlock(struct Header *h, const char *file, DWORD line);
#endif
/*
* Static variables
*/
STATIC char st_Buffer[4096] = { 0 }; /* don't use BSS */
STATIC struct Header *st_AllocatedHead = 0;
STATIC int st_AllocateFailRate = 0;
STATIC Fortify_OutputFuncPtr st_Output = st_DefaultOutput;
STATIC const char *st_LastVerifiedFile = "unknown";
STATIC DWORD st_LastVerifiedLine = 0;
STATIC BYTE st_Scope = 0;
STATIC BYTE st_Disabled = 0;
#if defined(__HIGHC__) && 0 // !! not yet
STATIC char st_LockDataStart = 0;
#endif
#ifdef __cplusplus
int gbl_FortifyMagic = 0;
STATIC const char *st_DeleteFile[FORTIFY_DELETE_STACK_SIZE];
STATIC DWORD st_DeleteLine[FORTIFY_DELETE_STACK_SIZE];
STATIC DWORD st_DeleteStackTop;
#endif
/* statistics */
STATIC DWORD st_MaxBlocks = 0;
STATIC DWORD st_MaxAllocation = 0;
STATIC DWORD st_CurBlocks = 0;
STATIC DWORD st_CurAllocation = 0;
STATIC DWORD st_Allocations = 0;
STATIC DWORD st_Frees = 0;
STATIC DWORD st_TotalAllocation = 0;
STATIC DWORD st_AllocationLimit = 0xffffffff;
#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
STATIC struct Header *st_DeallocatedHead = 0;
STATIC struct Header *st_DeallocatedTail = 0;
STATIC DWORD st_TotalDeallocated = 0;
#endif
/* allocators */
STATIC const char *st_AllocatorName[] = {
"malloc()",
"calloc()",
"realloc()",
"strdup()",
"new",
"new[]"
};
/* deallocators */
STATIC const char *st_DeallocatorName[] = {
"nobody",
"free()",
"realloc()",
"delete",
"delete[]"
};
STATIC const BYTE st_ValidDeallocator[] = {
(1 << Fortify_Deallocator_free) | (1 << Fortify_Deallocator_realloc),
(1 << Fortify_Deallocator_free) | (1 << Fortify_Deallocator_realloc),
(1 << Fortify_Deallocator_free) | (1 << Fortify_Deallocator_realloc),
(1 << Fortify_Deallocator_free) | (1 << Fortify_Deallocator_realloc),
#if defined(FORTIFY_PROVIDE_ARRAY_NEW) && defined(FORTIFY_PROVIDE_ARRAY_DELETE)
(1 << Fortify_Deallocator_delete),
(1 << Fortify_Deallocator_array_delete)
#else
(1 << Fortify_Deallocator_delete) | (1 << Fortify_Deallocator_array_delete),
(1 << Fortify_Deallocator_delete) | (1 << Fortify_Deallocator_array_delete)
#endif
};
STATIC char st_LockDataFill[4096] = { 0 };
STATIC char st_LockDataEnd = 0;
#if defined(__HIGHC__) && 0 // !! not yet
#include <pharlap.h>
#include <hw386.h>
/*
* Change page-attributes for local data.
* Set to present or non-present pages.
*/
STATIC Fortify_LockLocalData (int lock)
{
UINT lockSize = (ULONG)&st_LockDataEnd - (ULONG)&st_LockDataStart;
ULONG num_pages = (lockSize + 4095) / 4096;
ULONG page = ((ULONG)&st_LockDataStart + 4095) / 4096;
for ( ; page < page + num_pages; page++)
{
ULONG pte, ptInfo;
if (_dx_rd_ptinfl (page << 12, &pte, &ptInfo))
break;
if (lock)
pte &= ~PE_PRESENT;
else pte |= PE_PRESENT;
if (_dx_wr_ptinfl (page << 12, pte, ptInfo))
break;
}
}
#endif
/*
* Fortify_Allocate() - allocate a block of fortified memory
*/
void *FORTIFY_STORAGE
Fortify_Allocate (size_t size, BYTE allocator, const char *file, DWORD line)
{
struct Header *h;
int another_try;
BYTE *ptr = NULL;
/*
* If Fortify has been disabled, then it's easy
*/
if (st_Disabled)
{
#ifdef FORTIFY_FAIL_ON_ZERO_MALLOC
if (size == 0 &&
(allocator == Fortify_Allocator_new ||
allocator == Fortify_Allocator_array_new))
{
/*
* A new of zero bytes must succeed, but a malloc of
* zero bytes probably won't
*/
return malloc(1);
}
#endif
return malloc(size);
}
#ifdef FORTIFY_CHECK_ALL_MEMORY_ON_ALLOCATE
Fortify_CheckAllMemory (file, line);
#endif
if (st_AllocateFailRate > 0)
{
if (rand() % 100 < st_AllocateFailRate)
{
#ifdef FORTIFY_WARN_ON_FALSE_FAIL
sprintf (st_Buffer,
"\nFortify: A \"%s\" of %lu bytes \"false failed\" at %s.%lu\n",
st_AllocatorName[allocator], (DWORD)size, file, line);
st_Output (st_Buffer);
#endif
return (0);
}
}
/* Check to see if this allocation will
* push us over the artificial limit
*/
if (st_CurAllocation + size > st_AllocationLimit)
{
#ifdef FORTIFY_WARN_ON_FALSE_FAIL
sprintf (st_Buffer,
"\nFortify: A \"%s\" of %lu bytes \"false failed\" at %s.%lu\n",
st_AllocatorName[allocator], (DWORD)size, file, line);
st_Output (st_Buffer);
#endif
return (0);
}
#ifdef FORTIFY_WARN_ON_ZERO_MALLOC
if (size == 0 && (allocator == Fortify_Allocator_malloc ||
allocator == Fortify_Allocator_calloc ||
allocator == Fortify_Allocator_realloc))
{
sprintf(st_Buffer,
"\nFortify: A \"%s\" of 0 bytes attempted at %s.%lu\n",
st_AllocatorName[allocator], file, line);
st_Output(st_Buffer);
}
#endif /* FORTIFY_WARN_ON_ZERO_MALLOC */
#ifdef FORTIFY_FAIL_ON_ZERO_MALLOC
if (size == 0 && (allocator == Fortify_Allocator_malloc ||
allocator == Fortify_Allocator_calloc ||
allocator == Fortify_Allocator_realloc))
{
#ifdef FORTIFY_WARN_ON_ALLOCATE_FAIL
sprintf(st_Buffer, "\nFortify: A \"%s\" of %lu bytes failed at %s.%lu\n",
st_AllocatorName[allocator], (DWORD)size, file, line);
st_Output(st_Buffer);
#endif /* FORTIFY_WARN_ON_ALLOCATE_FAIL */
return (0);
}
#endif /* FORTIFY_FAIL_ON_ZERO_MALLOC */
#ifdef FORTIFY_WARN_ON_SIZE_T_OVERFLOW
/*
* Ensure the size of the memory block
* plus the overhead isn't bigger than
* size_t (that'd be a drag)
*/
{
size_t private_size = FORTIFY_HEADER_SIZE
+ FORTIFY_ALIGNED_BEFORE_SIZE + size + FORTIFY_AFTER_SIZE;
if (private_size < size)
{
sprintf(st_Buffer,
"\nFortify: A \"%s\" of %lu bytes has overflowed size_t at %s.%lu\n",
st_AllocatorName[allocator], (DWORD)size, file, line);
st_Output(st_Buffer);
return (0);
}
#if (DOSX) && defined(__WATCOMC__) && 0
if (private_size >= 65536UL)
{
sprintf(st_Buffer,
"\nFortify: A \"%s\" of %lu bytes has exceeded 64kB limit by %d bytes, at %s.%lu\n",
st_AllocatorName[allocator], (DWORD)size,
private_size - size, file, line);
st_Output(st_Buffer);
return (0);
}
#endif
}
#endif
another_try = 1;
do
{
/*
* malloc the memory, including the space
* for the header and fortification buffers
*/
ptr = (BYTE *)malloc ( FORTIFY_HEADER_SIZE
+ FORTIFY_ALIGNED_BEFORE_SIZE
+ size
+ FORTIFY_AFTER_SIZE);
#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
/*
* If we're tracking deallocated memory, then
* we can free some of it, rather than let
* this malloc fail
*/
if (!ptr)
another_try = st_PurgeDeallocatedBlocks(size, file, line);
#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
}
while (!ptr && another_try);
if (!ptr)
{
#ifdef FORTIFY_WARN_ON_ALLOCATE_FAIL
sprintf(st_Buffer, "\nFortify: A \"%s\" of %lu bytes failed at %s.%lu\n",
st_AllocatorName[allocator], (DWORD)size, file, line);
st_Output(st_Buffer);
#endif
return (0);
}
/*
* Begin Critical Region
*/
FORTIFY_LOCK();
/*
* Make the head's prev pointer point to us
* ('cos we're about to become the head)
*/
if (st_AllocatedHead)
{
st_CheckBlock(st_AllocatedHead, file, line);
/* what should we do if this fails? (apart from panic) */
st_AllocatedHead->Prev = (struct Header *)ptr;
st_MakeHeaderValid(st_AllocatedHead);
}
/*
* Initialize and validate the header
*/
h = (struct Header *)ptr;
h->Size = size;
h->File = file;
h->Line = line;
h->Next = st_AllocatedHead;
h->Prev = 0;
h->Scope = st_Scope;
h->Allocator = allocator;
h->Label = 0;
#ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
h->FreedFile = 0;
h->FreedLine = 0;
h->Deallocator = Fortify_Deallocator_nobody;
#endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
st_MakeHeaderValid(h);
st_AllocatedHead = h;
/*
* Initialize the fortifications
*/
st_SetFortification(ptr + FORTIFY_HEADER_SIZE,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -