2

I'd like to overload global and non-global new/delete operators for logging.

As I just want to add logging informations, I'd like to keep the standard behavior of this operators.

Is there a way to overload new/delete operator to add logging but without having to rewrite the standard behavior (which might be error prone) ?

Actually, I not only need standard behavior. I need the same behavior as Visual 2010 implementations, which might be not standard.

The kind of error I am looking for with this kind of logging is new[]/delete mismatch.

I could use classic tools but they slowdown the execution and I'd like to share the binary with other people to gather more informations.

BenjaminB
  • 1,809
  • 3
  • 18
  • 32
  • 2
    I believe that if you just call malloc you will preserve the standard behaviour. Whether you'll preserve the precise behaviour of the operator new you are replacing is another matter. – john Sep 13 '12 at 09:26
  • 1
    Any attempts made so far? What were the problems you encountered in your attempts? – Vite Falcon Sep 13 '12 at 09:26
  • The default behaviour isn't terribly complex, so I wouldn't worry about it. If you do it properly, there'll be a loop and calls to `get_new_handler`, I suppose. Make sure not to use standard containers inside the allocation functions, unless you give them a different allocator that doesn't itself use `operator new`. – Kerrek SB Sep 13 '12 at 09:28
  • @john Thank you, I added information to my question, I do not only need standard behavior, I need the same behavior as Visual 2010 implementation. – BenjaminB Sep 13 '12 at 09:36
  • @ViteFalcon No attempts. The problem is that I can't simply "try" and hope for the best. The software I work on is defense-sensitive and I'd like to propose adding information to new and delete to fight memory leaks. If I can be sure that the implementation I propose can not add bugs, that would help me. – BenjaminB Sep 13 '12 at 09:39
  • I have never tried, but overloading the operator should not prevent you from calling the default implementation when you are done with your own stuff, does it ? – J.N. Sep 13 '12 at 09:43
  • @Ubiquité I'm pretty sure the source code for the operator new implementation is available in Visual Studio. So you could just find that. However if you are doing this to find memory leaks, then a) not all memory leaks will result from incorrect use of new, b) wouldn't you be better using a dedicated leak detection tool rather than trying to write your own? – john Sep 13 '12 at 09:43
  • @Ubiquité : have you never heard of prototyping ? You can't make something on the first try ever, you always to play around to understand the scope of your problem ! – J.N. Sep 13 '12 at 09:44
  • 2
    From [this excellent FAQ question](http://stackoverflow.com/q/7194127/743214) you see that it isn't really that involved to write your own standard conformant `operator new/delete`, just some 5-10 lines of boilerplate, plus your logging functionality and a call to `std::malloc/free`. – Christian Rau Sep 13 '12 at 09:49
  • @J.N. There is tones of different use case to try. So it would be more efficient to share the "logging-producing" binary. – BenjaminB Sep 13 '12 at 10:11
  • @john Thank you, I found this : http://msdn.microsoft.com/en-us/library/t48aek43%28v=vs.100%29.aspx and this : http://msdn.microsoft.com/en-us/library/248aa748%28v=vs.100%29.aspx – BenjaminB Sep 13 '12 at 10:11

2 Answers2

4

You can use malloc/free for the basic allocation. Handling full standards compliance for new is a bit tricky; you need something like:

void*
operator new( size_t n )
{
    void* results = malloc( n );
    while ( results == NULL ) {
        if ( std::get_new_handler() == NULL ) {
            throw std::bad_alloc();
        }
        (*std::get_new_handler())();
        results = malloc( n );
    }
    return results;
}

Often, however, you don't need such full compliance. If you say that you don't support setting the new_handler, for example, you can simplify greatly. In the overloaded version I use for testing, in fact, if malloc really fails, I abort (but this version has options to trigger a failure of new, on demand, since I want to test that my code reacts correctly to it as well).

If you're logging, be very careful to avoid endless recursion. The only functions guaranteed not to use operator new in the standard library are malloc and free. Of course, a lot have no reason to allocate dynamically, and I don't worry about functions like memcpy or strlen. In practice, you are probably safe with any of the functions in the C library (although in theory, printf could be implemented in terms of iostream). But any use of iostream, locale or the standard containers is out, unless you protect against recursion:

void*
operator new( size_t n )
{
    static int recursionCount = 0;
    ++ recursionCount;
    void* results = malloc() ;
    //  Any additional logic you need...
    if ( recursionCount == 1 ) {
        logAllocation( results, n );
    }
    -- recursionCount;
    return results;
}

Formally, you should do the same for operator delete, although in practice, if you're logging to a file, I wouldn't expect any delete except in close() or the destructor.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

You can redefine the new keyword to call a different signature and pass __FILE__ and such.

In the general case this works out OK. When you start using objects that override operator new though you kinda screw yourself.

If I knew it by memory I'd share, but you can probably find with google. I think there's an implementation on codeproject somewhere.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125