Find out where heap memory gets corrupted - c++

I know there are already many similar questions and answers exist, but I am not able to solve my problem.
In my big application heap is getting corrupted somewhere and I am not able to locate it. I used tool like gflags also but no luck.
I tried gflags on the following sample which corrupts the heap by purpose:
char* pBuffer = new char[256];
memset(pBuffer, 0, 256 + 1);
delete[] pBuffer;
At line#2 heap is overwritten but how to find it via tools like gflags, windbg etc. May be I am not using the gflags properly.

If automated tools (like electric fence or valgrind) don't do the trick, and staring intently at your code to try and figure out where it might have gone wrong doesn't help, and disabling/enabling various operations (until you get a correlation between the presence of heap-corruption and what operations did or didn't execute beforehand) to narrow it doesn't seem to work, you can always try this technique, which attempts to find the corruption sooner rather than later, so as to make it easier to track down the source:
Create your own custom new and delete operators that put corruption-evident guard areas around the allocated memory regions, something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <new>
// make this however big you feel is "big enough" so that corrupted bytes will be seen in the guard bands
static int GUARD_BAND_SIZE_BYTES = 64;
static void * MyCustomAlloc(size_t userNumBytes)
{
// We'll allocate space for a guard-band, then space to store the user's allocation-size-value,
// then space for the user's actual data bytes, then finally space for a second guard-band at the end.
char * buf = (char *) malloc(GUARD_BAND_SIZE_BYTES+sizeof(userNumBytes)+userNumBytes+GUARD_BAND_SIZE_BYTES);
if (buf)
{
char * w = buf;
memset(w, 'B', GUARD_BAND_SIZE_BYTES); w += GUARD_BAND_SIZE_BYTES;
memcpy(w, &userNumBytes, sizeof(userNumBytes)); w += sizeof(userNumBytes);
char * userRetVal = w; w += userNumBytes;
memset(w, 'E', GUARD_BAND_SIZE_BYTES); w += GUARD_BAND_SIZE_BYTES;
return userRetVal;
}
else throw std::bad_alloc();
}
static void MyCustomDelete(void * p)
{
if (p == NULL) return; // since delete NULL is a safe no-op
// Convert the user's pointer back to a pointer to the top of our header bytes
char * internalCP = ((char *) p)-(GUARD_BAND_SIZE_BYTES+sizeof(size_t));
char * cp = internalCP;
for (int i=0; i<GUARD_BAND_SIZE_BYTES; i++)
{
if (*cp++ != 'B')
{
printf("CORRUPTION DETECTED at BEGIN GUARD BAND POSITION %i of allocation %p\n", i, p);
abort();
}
}
// At this point, (cp) should be pointing to the stored (userNumBytes) field
size_t userNumBytes = *((const size_t *)cp);
cp += sizeof(userNumBytes); // skip past the user's data
cp += userNumBytes;
// At this point, (cp) should be pointing to the second guard band
for (int i=0; i<GUARD_BAND_SIZE_BYTES; i++)
{
if (*cp++ != 'E')
{
printf("CORRUPTION DETECTED at END GUARD BAND POSITION %i of allocation %p\n", i, p);
abort();
}
}
// If we got here, no corruption was detected, so free the memory and carry on
free(internalCP);
}
// override the global C++ new/delete operators to call our
// instrumented functions rather than their normal behavior
void * operator new(size_t s) throw(std::bad_alloc) {return MyCustomAlloc(s);}
void * operator new[](size_t s) throw(std::bad_alloc) {return MyCustomAlloc(s);}
void operator delete(void * p) throw() {MyCustomDelete(p);}
void operator delete[](void * p) throw() {MyCustomDelete(p);}
... the above will be enough to get you Electric-Fence style functionality, in that if anything writes into either of the two 64-byte "guard bands" at the beginning or end of any new/delete memory-allocation, then when the allocation is deleted, MyCustomDelete() will notice the corruption and crash the program.
If that's not good enough (e.g. because by the time the deletion occurs, so much has happened since the corruption that it's difficult to tell what caused the corruption), you can go even further by having MyCustomAlloc() add the allocated buffer into a singleton/global doubly-linked list of allocations, and have MyCustomDelete() remove it from that same list (make sure to serialize these operations if your program is multithreaded!). The advantage of doing that is that you can then add another function called e.g. CheckForHeapCorruption() that will iterate over that linked list and check the guard-bands of every allocation in the linked list, and report if any of them have been corrupted. Then you can sprinkle calls to CheckForHeapCorruption() throughout your code, so that when heap corruption occurs it will be detected at the next call to CheckForHeapCorruption() rather than some time later on. Eventually you will find that one call to CheckForHeapCorruption() passed with flying colors, and then the next call to CheckForHeapCorruption(), just a few lines later, detected corruption, at which point you know that the corruption was caused by whatever code executed between the two calls to CheckForHeapCorruption(), and you can then study that particular code to figure out what it's doing wrong, and/or add more calls to CheckForHeapCorruption() into that code as necessary.
Repeat until the bug becomes obvious. Good luck!

If the same variable is consistently being corrupted, data break points are a quick and simple way to find the code responsible for the change (if your IDE supports them). (Debug->New Break Point->New Data Breakpoint... in MS Visual Studio 2008). They won't help if your heap corruption is more random (but figured I'd share the simple answer in case it helps).

There's a tool called electric fence that I think is supported also on Windows.
Essentially, what it does is hijack malloc and co to make every allocation end at page boundary and mark the next page inaccessible.
The effect is that you get a seg fault on buffer overrun.
It probably also have an option for buffer underrun.

Please read this link
Visual Studio - how to find source of heap corruption errors
Is there a good Valgrind substitute for Windows?
It tells technique for finding heap issues on windows.
But on the other hand you can always write (if you are writing new code) memory managers.
The way to do is: use your wrapper apis which will call malloc/calloc etc.
Suppose you have api myMalloc(size_t len);
then inside your function, you can try allocationg HEADER + len + FOOTER.
On your header save info like size of allocation or may be more info. At the footer, add some magic number like deadbeef. And return ptr(from malloc) + HEADER from myMalloc.
When freeing it up using myfree(void *ptr), then just do ptr -HEADER, check the len, then jump at the FOOTER = ptr-HEADER + really allcated len. At this offset, you should find deadbeef, and if you dont find, then you know, its been corrupted.

Related

What can explain heap corruption on a call to free()?

I have been debugging a crash for days now, that occurs in the depths of OpenSSL (discussion with the maintainers here). I took some time investigating so I'll try to make this question interesting and informative.
First and to give some context, my minimal-sample that reproduces the crash is as follow:
#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/engine.h>
int main()
{
ERR_load_crypto_strings(); OpenSSL_add_all_algorithms();
ENGINE_load_builtin_engines();
EC_GROUP* group = EC_GROUP_new_by_curve_name(NID_sect571k1);
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
EC_KEY* eckey = EC_KEY_new();
EC_KEY_set_group(eckey, group);
EC_KEY_generate_key(eckey);
BIO* out = BIO_new(BIO_s_file());
BIO_set_fp(out, stdout, BIO_NOCLOSE);
PEM_write_bio_ECPrivateKey(out, eckey, NULL, NULL, 0, NULL, NULL); // <= CRASH.
}
Basically, this code generates an Elliptic Curve key and tries to output it to stdout. Similar code can be found in openssl.exe ecparam and on Wikis online. It works fine on Linux (valgrind reports no error at all). It only crashes on Windows (Visual Studio 2013 - x64). I made sure the proper runtimes were linked-to (/MD in my case, for all dependencies).
Fearing no evil, I recompiled OpenSSL in x64-debug (this time linking everything in /MDd), and stepped through the code to find the offending set of instructions. My search led me to this code (in OpenSSL's tasn_fre.c file):
static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine)
{
// ... some code, not really relevant.
tt = it->templates + it->tcount - 1;
for (i = 0; i < it->tcount; tt--, i++) {
ASN1_VALUE **pseqval;
seqtt = asn1_do_adb(pval, tt, 0);
if (!seqtt) continue;
pseqval = asn1_get_field_ptr(pval, seqtt);
ASN1_template_free(pseqval, seqtt);
}
if (asn1_cb)
asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL);
if (!combine) {
OPENSSL_free(*pval); // <= CRASH OCCURS ON free()
*pval = NULL;
}
// Some more code...
}
For those not too familiar with OpenSSL and it's ASN.1 routines, basically what this for-loop does is that it goes trough all the elements of a sequence (starting with the last element) and "deletes" them (more on that later).
Right before the crash happens, a sequence of 3 elements is deleted (at *pval, which is 0x00000053379575E0). Looking at the memory, one can see the following things happen:
The sequence is 12 bytes long, each element being 4-bytes long (in this case, 2, 5, and 10). On each loop iteration, elements are "deleted" by OpenSSL (in this context, neither delete or free are called: they are just set to a specific value). Here is how the memory looks after one iteration:
The last element here was set to ff ff ff 7f which I assume is OpenSSL's way of ensuring no key information leaks when the memory is unallocated later.
Right after the loop (and before the call to OPENSSL_free()), the memory is as follow:
All elements were set to ff ff ff 7f, asn1_cb is NULL so no call is made. The next thing that goes on is the call to OPENSSL_free(*pval).
This call to free() on what seems to be a valid & allocated memory fails and cause the execution to abort with a message: "HEAP CORRUPTION DETECTED".
Curious about this, I hooked into malloc, realloc and free (as OpenSSL permits) to ensure this wasn't a double-free or a free on never-allocated memory. It turns out the memory at 0x00000053379575E0 really is a 12 bytes block that was indeed allocated (and never freed before).
I'm at loss figuring out what happens here: from my research, it seems that free() fails on a pointer that was normally returned by malloc(). In addition to that, this memory location was being written to a couple of instructions before without any problem which confirms the hypothesis that the memory be correctly allocated.
I know it's hard, if not impossible, to debug remotely without all the information but I have no idea what my next steps should be.
So my question is: how exactly is this "HEAP CORRUPTION" detected by Visual Studio's debugger ? What are all the possible causes for it when originating from a call to free() ?
In general the possibilities include:
Duplicate free.
Prior duplicate free.
(Most probable) Your code wrote beyond the limits of the allocated chunk of memory, either before the beginning or after the end. malloc() and friends put extra bookkeeping information in here, such as the size, and probably a sanity-check, which you will fail by overwriting.
Freeing something that hadn't been malloc()-ed.
Continuing to write to a chunk that had already been free()-d.
I could finally find the problem and solve it.
Turned out some instruction was writing bytes past the allocated heap buffer (hence the 0x00000000 instead of the expected 0xfdfdfdfd).
In debug mode this overwrite of the memory guards remains undetected until the memory is freed with free() or reallocated with realloc(). This is what caused the HEAP CORRUPTION message I faced.
I expect that in release mode, this could have had dramatic effects, like overwritting a valid memory block used somewhere else in the application.
For future reference to people facing similar issues, here is how I did:
OpenSSL provides a CRYPTO_set_mem_ex_functions() function, defined like so:
int CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const char *, int),
void *(*r) (void *, size_t, const char *,
int), void (*f) (void *))
This function allows you to hook in and replace memory allocation/freeing functions within OpenSSL. The nice thing is the addition of the const char *, int parameters which are basically filled for you by OpenSSL and contain the filename and line number of the allocation.
Armed with this information, it was easy to find out the place where the memory block was allocated. I could then step through the code while looking at the memory inspector waiting for the memory block to be corrupted.
In my case what happenned was:
if (!combine) {
*pval = OPENSSL_malloc(it->size); // <== The allocation is here.
if (!*pval) goto memerr;
memset(*pval, 0, it->size);
asn1_do_lock(pval, 0, it);
asn1_enc_init(pval, it);
}
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
pseqval = asn1_get_field_ptr(pval, tt);
if (!ASN1_template_new(pseqval, tt))
goto memerr;
}
ASN1_template_new() is called on the 3 sequence elements to initialize them.
Turns out ASN1_template_new() calls in turn asn1_item_ex_combine_new() which does this:
if (!combine)
*pval = NULL;
pval being a ASN1_VALUE**, this instruction sets 8 bytes on Windows x64 systems instead of the intended 4 bytes, leading to memory corruption for the last element of the list.
For the full discussion on how this problem was solved upstream, see this thread.

Receive SIGSEGV signal when using malloc for char * in Linux Qt Creator C++

When I run the following code to allocate memory for char * using malloc() on QT Linux C++, SIGSEGV is signaled after about 250 executions.
for(int i = 0; i < 10000; i++)
{
char * test = (char * )malloc(500);
test = "mas";
cout<<test<<endl;
}
I tried to use free() or delete() but they also trigger system signal.
What is the problem?
The main problem is that you're stepping on your malloc()'ed pointer. Stepping on it multiple times:
// Original test case
for(int i = 0; i < 10000; i++) {
char * test = (char * )malloc(500);
test = "mas"; // BAD!!!
// You've just stepped on your "malloc'ed" pointer with a *different pointer!!!!
cout<<test<<endl;
}
Here is an alternative. Note that you've also got to have some way to "remember" the pointer for each malloc(), so you can "free()" it at the appropriate time:
// Better:
for(int i = 0; i < 10000; i++) {
char * test = (char * )malloc(500);
if (test == NULL) {
cout << "malloc error!" << endl;
break;
}
strcpy (test, "mas");
cout<<test<<endl;
free (test);
}
You've changed the value of the pointer test. You need to use memcpy or the like to copy the value "mas" into the buffer.
Better yet, use std::string
This code:
test = "mas";
Doesn't do what you think it does. You think it copies the string "mas" in to the buffer pointed to by test. What it actually does is it changes what test points to. Instead of pointing to the memory you allocated with the malloc, now it points to a statically allocated char buffer.
When you're allocating memory with malloc or new you get only a pointer in return, so you have to approach to that differently - with functions like strcpy, strcmp (if you need to check equality of texts you can't compare only pointers either). Read more about pointers in any C++ book. It's possible to create texts without allocating memory explicitly, for example, this is legal:
const char *text = "my text";
But further modifications like you showed in question are not (notice const here, it gives us more safety). In this case text is created somewhere in memory by compiler itself (i'm simplifying things now) and only pointer is assigned. In that case you cannot modify that text (at least not safe).
Next thing, when you are allocating any memory you have to free it manually, at least in languages like C/C++ where memory management (garbage collectors etc.) don't really exist. If you'll skip that step you'll run into trouble (out of memory exceptions for example) faster than you think.
this statement:
test = "mas";
does not copy strings, but pointers.
To copy a string in C, use carefully strcpy(3) (often strncpyis better).
strcpy(test, "mas");
But you really should use (as Vinbot answered) std::string since you code in C++
Also, compile C++ code on Linux with g++ -g Wall (and C code with gcc -g -Wall) to get warnings and debug info. Learn how to use the gdb debugger and also valgrind
See also this answer to a related question.

Error in realloc but not malloc?

I am having to work with someone else's code, so I am not entirely in control over what I can change but I am wondering why I am getting this error and would appreciate any suggestions. This code is in the part that I can't change but I need to make sure the part I wrote (StringRef class) works.
The error it gives me is 'Heap block at X modified at Y past requested size of 28'. If I change the existing code which is using realloc to malloc it kicks the can down the road a bit and loads a few more values into the array. Here are the lines in question. I can't include all the code as it is too extensive. Is this enough info to diagnose what I am doing wrong?
struct StringList
{
StringRef *elements;
unsigned int count;
};
.....
// Append the given StringRef to the list.
bool StringListAppend(StringList& self, StringRef p_string)
{
StringRef *t_new_elements;
t_new_elements = (StringRef *)realloc(self.elements, (self.count + 1) * sizeof(StringRef *));
if (t_new_elements == NULL)
return false;
self.elements = t_new_elements;
std::cout<<self.count<<"\n";
// Initialize and assign the new element.
StringInitialize(self.elements[self.count]);
if (!StringAssign(self.elements[self.count], p_string))
return false;
// We've successfully added the element, so bump the count.
self.count += 1;
return true;
}
vs
StringRef *t_new_elements;
t_new_elements = (StringRef *)malloc((self.count + 1) * sizeof(StringRef *));
for the line with realloc averts the problem a little further.
sizeof(StringRef *) should be sizeof(StringRef)
You could avoid this error by using this idiom:
ptr = realloc(old_ptr, n_elements * sizeof *ptr);
when the number of bytes to allocate is determined based on the type of the variable that holds the returned pointer; it doesn't require you to repeat anything and thereby introduce a discrepancy.
As to why changing realloc to malloc slightly moves the point at which the program crashes... undefined behaviour is undefined :)
Lets say you wish to allocate some memory.
You should use malloc (stores memory on heap uninitialized) or calloc(stores initializes all elements to 0).
Explained more Here!
Realloc extends the length of your allocated memory. So you need to allocate some before you can extend it. (dont neeed to, but it is good coding practice to do so) Realloc
I would suggest looking up more on memory allocation because abusing it can greatly reduce efficiency and must be treated with precaution, like: you should always free memory that you have allocated at the end of your program!

C++/ActiveX replacing realloc with malloc, memcpy, free. Functional and Performance tests

I've been assigned to a project that is a complex legacy system written in C++ and ActiveX ~ 10 years old.
The setup is Microsoft Visual Studio 2008.
Whilst there are no issues with the system right now, as part of the security review of the legacy system, an automated security code scanning tool has marked instances of realloc as Bad Practice issue, due to security vulnerability.
This is because realloc function might leave a copy of sensitive information stranded in memory where it cannot be overwritten. The tool recommends replacing realloc with malloc, memcpy and free.
Now realloc function being versatile, will allocate memory when the source buffer is null. It also frees memory when the size of the buffer is 0. I was able to verify both these scenarios.
Source: MDSN Library 2001
realloc returns a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL if the size is zero and the buffer argument is not NULL, or if there is not enough available memory to expand the block to the given size. In the first case, the original block is freed. In the second, the original block is unchanged. The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.
So, my replacement function that uses malloc, memcpy and free has to cater for these cases.
I have reproduced below the original code snippet (an array implementation) that uses realloc to dynamically resize and shrink its internal buffer.
First the class definition:
template <class ITEM>
class CArray
{
// Data members:
protected:
ITEM *pList;
int iAllocUnit;
int iAlloc;
int iCount;
public:
CArray() : iAllocUnit(30), iAlloc(0), iCount(0), pList(NULL)
{
}
virtual ~CArray()
{
Clear(); //Invokes SetCount(0) which destructs objects and then calls ReAlloc
}
The existing ReAlloc method:
void ReAllocOld()
{
int iOldAlloc = iAlloc;
// work out new size
if (iCount == 0)
iAlloc = 0;
else
iAlloc = ((int)((float)iCount / (float)iAllocUnit) + 1) * iAllocUnit;
// reallocate
if (iOldAlloc != iAlloc)
{
pList = (ITEM *)realloc(pList, sizeof(ITEM) * iAlloc);
}
}
The following is my implementation that replaces these with malloc,memcpy and free:
void ReAllocNew()
{
int iOldAlloc = iAlloc;
// work out new size
if (iCount == 0)
iAlloc = 0;
else
iAlloc = ((int)((float)iCount / (float)iAllocUnit) + 1) * iAllocUnit;
// reallocate
if (iOldAlloc != iAlloc)
{
size_t iAllocSize = sizeof(ITEM) * iAlloc;
if(iAllocSize == 0)
{
free(pList); /* Free original buffer and return */
}
else
{
ITEM *tempList = (ITEM *) malloc(iAllocSize); /* Allocate temporary buffer */
if (tempList == NULL) /* Memory allocation failed, throw error */
{
free(pList);
ATLTRACE(_T("(CArray: Memory could not allocated. malloc failed.) "));
throw CAtlException(E_OUTOFMEMORY);
}
if(pList == NULL) /* This is the first request to allocate memory to pList */
{
pList = tempList; /* assign newly allocated buffer to pList and return */
}
else
{
size_t iOldAllocSize = sizeof(ITEM) * iOldAlloc; /* Allocation size before this request */
size_t iMemCpySize = min(iOldAllocSize, iAllocSize); /* Allocation size for current request */
if(iMemCpySize > 0)
{
/* MemCpy only upto the smaller of the sizes, since this could be request to shrink or grow */
/* If this is a request to grow, copying iAllocSize will result in an access violation */
/* If this is a request to shrink, copying iOldAllocSize will result in an access violation */
memcpy(tempList, pList, iMemCpySize); /* MemCpy returns tempList as return value, thus can be omitted */
free(pList); /* Free old buffer */
pList = tempList; /* Assign newly allocated buffer and return */
}
}
}
}
}
Notes:
Objects are constructed and destructed correctly in both the old and new code.
No memory leaks detected (as reported by Visual Studio built in CRT Debug heap functions: http://msdn.microsoft.com/en-us/library/e5ewb1h3(v=vs.90).aspx)
I wrote a small test harness (console app) that does the following:
a. Add 500000 instances of class containing 2 integers and an STL string.
Integers added are running counter and its string representations like so:
for(int i = 0; i < cItemsToAdd; i++)
{
ostringstream str;
str << "x=" << 1+i << "\ty=" << cItemsToAdd-i << endl;
TestArray value(1+i, cItemsToAdd-i, str.str());
array.Append(&value);
}
b. Open a big log file containing 86526 lines of varying lengths, adding to an instance of this array: CArray of CStrings and CArray of strings.
I ran the test harness with the existing method (baseline) and my modified method. I ran it in both debug and release builds.
The following are the results:
Test-1: Debug build -> Adding class with int,int,string, 100000 instances:
Original implementation: 5 seconds, Modified implementation: 12 seconds
Test-2: Debug build -> Adding class with int,int,string, 500000 instances:
Original implementation: 71 seconds, Modified implementation: 332 seconds
Test-3: Release build -> Adding class with int,int,string, 100000 instances:
Original implementation: 2 seconds, Modified implementation: 7 seconds
Test-4: Release build -> Adding class with int,int,string, 500000 instances:
Original implementation: 54 seconds, Modified implementation: 183 seconds
Reading big log file into CArray of CString objects:
Test-5: Debug build -> Read big log file with 86527 lines CArray of CString
Original implementation: 5 seconds, Modified implementation: 5 seconds
Test-6: Release build -> Read big log file with 86527 lines CArray of CString
Original implementation: 5 seconds, Modified implementation: 5 seconds
Reading big log file into CArray of string objects:
Test-7: Debug build -> Read big log file with 86527 lines CArray of string
Original implementation: 12 seconds, Modified implementation: 16 seconds
Test-8: Release build -> Read big log file with 86527 lines CArray of string
Original implementation: 9 seconds, Modified implementation: 13 seconds
Questions:
As you can see from the above tests, realloc is consistently faster compared to memalloc, memcpy and free. In some instances (Test-2 for eg) its faster by a whopping 367%. Similarly for Test-4 it is 234%. So what can I do to get these numbers down that is comparable to realloc implementation?
Can my version be made more efficient?
Assumptions:
Please note that I cannot use C++ new and delete. I have to use only malloc and free. I also cannot change any of the other methods (as it is existing functionality) and impacts are huge. So my hands are tied to get the best implementation of realloc that I possibly can.
I have verified that my modified implementation is functionally correct.
PS: This is my first SO post. I have tried to be as detailed as possible. Suggestions on posting is also appreciated.
First of all I'd like to point out you are not addressing the vulnerability as the memory released by free is not being cleared as well, same as realloc.
Also note your code does more than the old realloc: it throws an exception when out of memory. Which may be futile.
Why is your code slower than realloc? Probably because realloc is using under the hood shortcuts which are not available to you. For example realloc may be allocating more memory than you actually request, or allocating contiguous memory just after the end of the previous block, so your code is doing more memcpy's than realloc.
Point in case. Running the following code in CompileOnline gives result Wow no copy
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
void* p = realloc(NULL, 1024);
void* t = realloc(p, 2048);
if (p == t)
cout << "Wow no copy" << endl;
else
cout << "Alas, a copy" << endl;
return 0;
}
What can you do to make your code faster?
You can try to allocate more memory after the currently allocated block, but then freeing the memory becomes more problematic as you need to remember all the pointers you allocated, or find a way to modify the lookup tables used by free to free the correct amount of memory on one go.
OR
Use the common strategy of (internally) allocating twice as much memory as you previously allocated and (optionally) shrink the memory only when the new threshold is less than half the allocated memory.
This gives you some head room so not every time memory grows is it necessary to call malloc/memcpy/free.
If you look at an implementation of realloc e.g.
http://www.scs.stanford.edu/histar/src/pkg/uclibc/libc/stdlib/malloc/realloc.c
you see that the difference between your implementation and an existing one
is that it expands the memory heap block instead of creating a whole new block
by using low-level calls. This probably accounts for some of the speed difference.
I think you also need to consider the implications of memset of memory every time you do a realloc because then a performance degradation seems inevitable.
I find the argument about realloc leaving code in the memory is somewhat overly paranoid because the same can be said about normal malloc/calloc/free. It would mean that you would not only need to find all reallocs/malloc/callocs but also any runtime or 3rd party function that internally uses those functions to be really sure that nothing is kept in memory alternatively another way would be to create your own heap and replace it with the regular one to keep it clean.
Conceptually realloc() is not doing anything too smart - it allocates memory by some blocks exactly as you do in your ReAllocNew.
The only conceptual difference can be in the way how new block size is calculated.
realloc may use something like this:
int new_buffer_size = old_buffer_size * 2;
and this will decrease number of memory moves from what you have there.
In any case I think that block size calculation formula is the key factor.

Writing my own memory manager class, overriding new and delete operators

I was given the assignment of making my own memory manager class, but I really have no idea where to start. My instructions are;
//1> write a memman allocation function
//2> insure the alloce functions returns unused addresses
//3> once all memman memmory is used up, subsequent alloces return NULL
//4> enable freeing of memory and subsequent reuse of those free'd regions
I've tried searching around for any guides on dealing with memory allocation, but I have not been too successful.
Here is one very, very naive idea to get you started:
char arena[1000000];
char * current = arena;
void * memman(std::size_t n)
{
char * p = current;
current += 16 * ((n + 15) / 16); // or whatever your alignment
return p;
}
All the memory is statically allocated, so you don't need any library calls to get your initial chunk of memory. We make sure to return only pointers with maximal alignment (hardcoded to 16 here, though this should be a constant like sizeof(std::maxalign_t)). This version doesn't allow for any reclamation, and it's missing the overflow checks.
For reclamation, you could try and write a free list.
As a slight variation, you could make your array be an array of maxalign_ts, which would simplify the stepping logic a bit. Or you could make it an array of uintptr_t and use the memory itself as the free list.