7

I'm making a memory leak detector for c++. It replaces the global new operator and uses a macro to initialise two global variables, __file__ and __line__, like so:

#define new (__file__=__FILE__,__line__=__LINE__) && 0 ? NULL : new

I learnt this trick from another StackOverflow user whose name I can't remember. This works fine with simple operations involving new, however this appraoch causes problem when the user defines a local operator new for a namespace. For one thing, lines like

void* operator new(size_t size);

is also matched by the macro; also, explicit calls to global new, like:

int* i = ::new int;

causes syntactic errors.

Is there a way to redefine or suppress __LINE__and__FILE__ constants (so that they show the file name and line number of the call to operator new) in part of the code? If not, how could the macro be improved to not match user defined "operator new" and not cause problem with "::new"?

I would really love to get rid of the wonkiness of macros. Thanks in advance :)

Kijewski
  • 25,517
  • 12
  • 101
  • 143
Einheri
  • 957
  • 1
  • 9
  • 22
  • 2
    This is the reason that the C++ language definition does not allow creating macros that redefine keywords. – Pete Becker Dec 19 '13 at 11:25
  • Assigning new values to two globals (which, to make it worse, are using reserved names) by redefining a keyword isn't going to make a leak detector, though (unless you assume it is always the last allocation that is leaked). While you're at using nonstandard stuff already, I'd rather suggest you overload global `operator new` and `delete` with a custom allocator that remembers `__builtin_return_address(1)` for each allocation. – Damon Dec 19 '13 at 13:56
  • @Damon The macro isn't the only part of the program, I did replace the global new and delete operators. The information is stored in a linked list. – Einheri Dec 19 '13 at 14:50

2 Answers2

0

I know of no way to do this non-instrusively. In the past I've used a regex or c++ function replacing tool (like the refactor tools available in Visual Studio) to change all instances of new to explicitly call a macro that records the file and line number.

Another option is to instrument your memory system to record stack frames. This method comes with higher runtime cost, but occasionally will be useful if the leak is occurring from an allocation that occurs due to misuse of frequently leveraged library code. There is no platform agnostic way to do this, see this question for information that applies to common platforms (linux and windows).

Edit: For your specific case you could just undefine the macro and redefine it after instances of the new identifier that are causing trouble.

Community
  • 1
  • 1
Dan O
  • 4,323
  • 5
  • 29
  • 44
  • too bad I'm developing this app for a platform that has neither windows nor linux library available. Also I do need to keep track of calls to global new, so it probably won't be viable to ignore these lines. – Einheri Dec 19 '13 at 06:28
0

Ok, I've given up trying to make the macro work. From the look of it, it can't. I've written a perl script to do the job. It runs before preprocessing (a pre-preprocessor) and it does a smarter substitution than what the C preprocessor would do. These are the regexes used to match new and ::new into something else:

$this =~ s/(::)?\s*new([^\w_])/__fl_init(__FILE__,__LINE__)?NULL: $1new$2/g;

I don't know, maybe I'll write a batch file to auto pre-preprocess the source. Please do comment if anybody knows a work-around using the CPP.

Einheri
  • 957
  • 1
  • 9
  • 22
  • Glad to hear you've given up the effort because creating macros that redefine language keywords should be a criminal offense, as reflected by the fact that the C++ standard prohibits it. – Carey Gregory Jan 09 '14 at 02:02