33 static const size_t AllocationLimitsTryFirst = 500;
34 static const size_t AllocationLimitsTryLast = 200;
35 static const size_t AllocationLimitsStepRatio = 1000;
37 DebugAllocator& DebugAllocator::getSingleton() {
38 static DebugAllocator singleton;
42 void DebugAllocator::rewindInput() {
44 if (!freopen(_inputFile.c_str(),
"r", stdin))
45 reportError(
"Could not open file \"" + _inputFile +
"\" for input.");
55 int DebugAllocator::runDebugMain(
int argc,
const char** argv) {
56 processDebugOptions(argc, argv);
65 size_t maxAllocations = _allocationCount;
66 if (_actionIsTest || !_debugAllocation)
71 fputs(
"DEBUG: Now debugging out-of-memory conditions.\n", stderr);
72 fprintf(stderr,
"DEBUG: There are %i allocations in total on this input.\n",
76 if (maxAllocations < AllocationLimitsTryFirst + AllocationLimitsTryLast) {
77 fputs(
"DEBUG: This is few, so am now running through "
78 "every possible condition.\n", stderr);
79 for (
size_t limit = 0; limit < maxAllocations; ++limit)
80 runWithLimit(argc, argv, limit);
84 fprintf(stderr,
"DEBUG: Trying the first %i allocations.\n",
85 (
int)AllocationLimitsTryFirst);
86 for (
size_t limit = 0; limit < AllocationLimitsTryFirst; ++limit)
87 runWithLimit(argc, argv, limit);
89 fprintf(stderr,
"DEBUG: Trying the last %i allocations.\n",
90 (
int)AllocationLimitsTryLast);
91 for (
size_t limit = 0; limit < AllocationLimitsTryLast; ++limit)
92 runWithLimit(argc, argv, maxAllocations - limit);
95 maxAllocations - AllocationLimitsTryFirst - AllocationLimitsTryLast;
96 size_t stepSize = limitsLeft / AllocationLimitsStepRatio + 1;
98 "DEBUG: Going through the %i remaining allocations "
99 "with steps of size %i.\n",
100 (
int)limitsLeft, (
int)stepSize);
102 for (
size_t limit = AllocationLimitsTryFirst;
103 limit < maxAllocations - AllocationLimitsTryLast; limit += stepSize)
104 runWithLimit(argc, argv, limit);
109 void DebugAllocator::runWithLimit(
int argc,
const char** argv,
size_t limit) {
110 if (_detailAllocation)
111 fprintf(stderr,
"DEBUG: Trying allocation limit of %i\n", (
int)limit);
116 _limitAllocation =
true;
117 _allocationLimit = limit;
118 _allocationCount = 0;
122 _expectBadAllocException =
false;
128 }
catch (
const bad_alloc&) {
129 if (!_expectBadAllocException)
133 _limitAllocation =
false;
136 void DebugAllocator::processDebugOptions(
int& argc,
const char**& argv) {
137 const char* originalArgvZero = argv[0];
140 if (argc <= 1 || argv[1][0] !=
'_')
143 string option(argv[1] + 1);
147 if (option ==
"debugAlloc")
148 _debugAllocation =
true;
149 else if (option ==
"detailAlloc")
150 _detailAllocation =
true;
151 else if (option ==
"input") {
153 reportError(
"Debug option _input requries an argument.");
155 _inputFile = argv[1];
159 reportError(
"Unknown debug option \"" + option +
"\".");
162 if (argc >= 2 &&
string(argv[1]) ==
"test")
163 _actionIsTest =
true;
165 argv[0] = originalArgvZero;
168 void DebugAllocator::runTest(
TestCase& test,
const string& name) {
169 test.
run(name.c_str(),
true);
171 if (!_debugAllocation)
174 _limitAllocation =
true;
176 for (_allocationLimit = 0; _allocationLimit < numeric_limits<size_t>::max();
177 ++_allocationLimit) {
178 if (_detailAllocation)
179 fprintf(stderr,
"DEBUG: Trying test allocation limit of %i\n",
180 (
int)_allocationLimit);
185 _allocationCount = 0;
186 _expectBadAllocException =
false;
191 test.
run(name.c_str(),
false);
195 }
catch (
const bad_alloc&) {
196 if (!_expectBadAllocException)
202 _limitAllocation =
false;
205 void* DebugAllocator::allocate(
size_t size) {
206 return allocate(size, 0, 0);
209 void* DebugAllocator::allocate(
size_t size,
212 if (_detailAllocation) {
214 fprintf(stderr,
"DEBUG: Allocating %i bytes at %s:%i.\n",
215 (
int)size, file, (
int)lineNumber);
217 fprintf(stderr,
"DEBUG: Allocating %i bytes at an unknown point.\n",
221 if (_limitAllocation && _allocationCount >= _allocationLimit) {
222 if (_detailAllocation)
223 fputs(
"DEBUG: Throwing bad_alloc due to artifically imposed limit.\n",
225 _expectBadAllocException =
true;
230 void* p = malloc(size);
236 DebugAllocator::DebugAllocator():
237 _debugAllocation(false),
238 _detailAllocation(false),
239 _limitAllocation(false),
240 _expectBadAllocException(false),
241 _actionIsTest(false),
243 _allocationLimit(0) {
246 void*
operator new(
size_t size,
const char* file,
size_t lineNumber)
248 return DebugAllocator::getSingleton().allocate(size, file, lineNumber);
251 void*
operator new[](
size_t size,
const char* file,
size_t lineNumber)
253 return DebugAllocator::getSingleton().allocate(size, file, lineNumber);
256 void*
operator new(
size_t size)
throw (bad_alloc) {
257 return DebugAllocator::getSingleton().allocate(size);
260 void*
operator new[](
size_t size)
throw (bad_alloc) {
261 return DebugAllocator::getSingleton().allocate(size);
264 void operator delete(
void* buffer)
throw() {
268 void operator delete[](
void* buffer)
throw() {
290 void operator delete(
void* buffer,
const char* file,
size_t line) {
294 void operator delete[](
void* buffer,
const char* file,
size_t line) {
static void clearStaticCache()
Ideal caches memory allocated with new internally and reuses it to avoid calling new all the time.
Represents a test case, which is usually created through a macro that defines a subclass.
virtual void run(const char *nameOfTest, bool printDots)=0
Run the test and record the name of the test as __nameOfTest.
void reportError(const string &errorMsg)
int frobbyMain(int argc, const char **argv)
This function runs the Frobby console interface.
static const int ExitCodeSuccess