You could have enable_no_heap_allowed() increment a thread-local int, and decrement_no_heap_allowed() decrement it. Then write a global-new operator that checks the thread-local variable and throws an exception/assert if it’s non-zero, or allocates the requested memory otherwise.
Note that this approach isn't a full solution since it only looks at calls to the new
and delete
operators; as @HolyBlackCat points out, heap-accesses that are done by directly calling malloc()
or free()
or other C-level heap-manipulation functions will not be detected.
Regardless, here is some C++11 example code (which btw you can use to figure out what std::string
considers a "short string" for purposes of its short-string optimization):
#include <stdio.h>
#include <string>
static thread_local int _heapDisallowedCount = 0;
void begin_no_heap_allowed() {_heapDisallowedCount++;}
void end_no_heap_allowed() {_heapDisallowedCount--;}
void check_heap_allowed(const char * desc, size_t numBytes)
{
if (_heapDisallowedCount != 0)
{
printf("ERROR, heap access in heap-disallowed section (reported by %s, %zi bytes)\n", desc, numBytes);
// add code to assert() or throw an exception here if you want
}
}
void * operator new(size_t s) throw(std::bad_alloc)
{
check_heap_allowed("operator new", s);
void * ret = malloc(s);
if (ret == NULL) throw std::bad_alloc();
return ret;
}
void * operator new[](size_t s) throw(std::bad_alloc)
{
check_heap_allowed("operator new[]", s);
void * ret = malloc(s);
if (ret == NULL) throw std::bad_alloc();
return ret;
}
void operator delete(void * p) throw()
{
check_heap_allowed("delete", -1);
return free(p);
}
void operator delete[](void * p) throw()
{
check_heap_allowed("delete[]", -1);
return free(p);
}
static void SomeFunction()
{
char buf[256];
fgets(buf, sizeof(buf), stdin);
char * newline = strchr(buf, '\n');
if (newline) *newline = '\0';
printf("You typed: [%s]\n", buf);
std::string s(buf);
printf("As a std::string, that's: [%s]\n", s.c_str());
}
int main(int, char **)
{
printf("Enter a string:\n");
SomeFunction();
printf("Enter another string (now with new/delete calls being detected:\n");
begin_no_heap_allowed();
SomeFunction();
end_no_heap_allowed();
return 0;
}