summaryrefslogtreecommitdiff
path: root/src/debug/debug_new.h
blob: 926de99de2282fe937c55f5a4c7d023af27e97c3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
// vim:tabstop=4:shiftwidth=4:expandtab:

/*
 * Copyright (C) 2004-2015 Wu Yongwei <adah at users dot sourceforge dot net>
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute
 * it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must
 *    not claim that you wrote the original software.  If you use this
 *    software in a product, an acknowledgement in the product
 *    documentation would be appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must
 *    not be misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source
 *    distribution.
 *
 * This file is part of Stones of Nvwa:
 *      http://sourceforge.net/projects/nvwa
 *
 */

/**
 * @file  debug_new.h
 *
 * Header file for checking leaks caused by unmatched new/delete.
 *
 * @date  2015-10-25
 */

#ifndef NVWA_DEBUG_NEW_H
#define NVWA_DEBUG_NEW_H

#include <new>                  // size_t/std::bad_alloc
#include <stdio.h>              // FILE
#include "debug/_nvwa.h"              // NVWA_NAMESPACE_*
#include "debug/c++11.h"              // _NOEXCEPT

/* Special allocation/deallocation functions in the global scope */
void* operator new(size_t size, const char* file, int line);
void* operator new[](size_t size, const char* file, int line);
void operator delete(void* ptr, const char* file, int line) _NOEXCEPT;
void operator delete[](void* ptr, const char* file, int line) _NOEXCEPT;

NVWA_NAMESPACE_BEGIN

/**
 * @def _DEBUG_NEW_REDEFINE_NEW
 *
 * Macro to indicate whether redefinition of \c new is wanted.  If one
 * wants to define one's own <code>operator new</code>, or to call
 * <code>operator new</code> directly, it should be defined to \c 0 to
 * alter the default behaviour.  Unless, of course, one is willing to
 * take the trouble to write something like:
 * @code
 * # ifdef new
 * #   define _NEW_REDEFINED
 * #   undef new
 * # endif
 *
 * // Code that uses new is here
 *
 * # ifdef _NEW_REDEFINED
 * #   ifdef DEBUG_NEW
 * #     define new DEBUG_NEW
 * #   endif
 * #   undef _NEW_REDEFINED
 * # endif
 * @endcode
 */
#ifndef _DEBUG_NEW_REDEFINE_NEW
#define _DEBUG_NEW_REDEFINE_NEW 1
#endif

/**
 * @def _DEBUG_NEW_TYPE
 *
 * Macro to indicate which variant of #DEBUG_NEW is wanted.  The
 * default value \c 1 allows the use of placement new (like
 * <code>%new(std::nothrow)</code>), but the verbose output (when
 * nvwa#new_verbose_flag is \c true) looks worse than some older
 * versions (no file/line information for allocations).  Define it
 * to \c 2 to revert to the old behaviour that records file and line
 * information directly on the call to <code>operator new</code>.
 */
#ifndef _DEBUG_NEW_TYPE
#define _DEBUG_NEW_TYPE 1
#endif

/**
 * Callback type for stack trace printing.
 *
 * @param fp          pointer to the output stream
 * @param stacktrace  pointer to the stack trace array (null-terminated)
 */
typedef void (*stacktrace_print_callback_t)(FILE* fp, void** stacktrace);

/**
 * Callback type for the leak whitelist function.  \a file, \a address,
 * and \a backtrace might be null depending on library configuration,
 * platform, and amount of runtime information available.  \a line can
 * be 0 when line number info is not available at runtime.
 *
 * @param file        null-terminated string of the file name
 * @param line        line number
 * @param addr        address of code where leakage happens
 * @param stacktrace  pointer to the stack trace array (null-terminated)
 * @return            \c true if the leak should be whitelisted;
 *                    \c false otherwise
 */
typedef bool (*leak_whitelist_callback_t)(char const* file, int line,
                                          void* addr, void** stacktrace);

/* Prototypes */
int check_leaks();
int check_mem_corruption();

/* Control variables */
extern bool new_autocheck_flag; // default to true: call check_leaks() on exit
extern bool new_verbose_flag;   // default to false: no verbose information
extern FILE* new_output_fp;     // default to stderr: output to console
extern const char* new_progname;// default to null; should be assigned argv[0]
extern stacktrace_print_callback_t stacktrace_print_callback;// default to null
extern leak_whitelist_callback_t leak_whitelist_callback;    // default to null

/**
 * @def DEBUG_NEW
 *
 * Macro to catch file/line information on allocation.  If
 * #_DEBUG_NEW_REDEFINE_NEW is \c 0, one can use this macro directly;
 * otherwise \c new will be defined to it, and one must use \c new
 * instead.
 */
# if _DEBUG_NEW_TYPE == 1
#   define DEBUG_NEW NVWA::debug_new_recorder(__FILE__, __LINE__) ->* new
# else
#   define DEBUG_NEW new(__FILE__, __LINE__)
# endif

# if _DEBUG_NEW_REDEFINE_NEW
#   define new DEBUG_NEW
# endif
# ifdef _DEBUG_NEW_EMULATE_MALLOC
#   include <stdlib.h>
#   ifdef new
#     define malloc(s) ((void*)(new char[s]))
#   else
#     define malloc(s) ((void*)(DEBUG_NEW char[s]))
#   endif
#   define free(p) delete[] (char*)(p)
# endif

/**
 * Recorder class to remember the call context.
 *
 * The idea comes from <a href="http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/7089382e3bc1c489/85f9107a1dc79ee9?#85f9107a1dc79ee9">Greg Herlihy's post</a> in comp.lang.c++.moderated.
 */
class debug_new_recorder
{
    const char* _M_file;
    const int   _M_line;
    void _M_process(void* ptr);
public:
    /**
     * Constructor to remember the call context.  The information will
     * be used in debug_new_recorder::operator->*.
     */
    debug_new_recorder(const char* file, int line)
        : _M_file(file), _M_line(line) {}
    /**
     * Operator to write the context information to memory.
     * <code>operator->*</code> is chosen because it has the right
     * precedence, it is rarely used, and it looks good: so people can
     * tell the special usage more quickly.
     */
    template <class _Tp> _Tp* operator->*(_Tp* ptr)
    { _M_process(ptr); return ptr; }
private:
    debug_new_recorder(const debug_new_recorder&);
    debug_new_recorder& operator=(const debug_new_recorder&);
};

/**
 * Counter class for on-exit leakage check.
 *
 * This technique is learnt from <em>The C++ Programming Language</em> by
 * Bjarne Stroustup.
 */
class debug_new_counter
{
    static int _S_count;
public:
    debug_new_counter();
    ~debug_new_counter();
};
/** Counting object for each file including debug_new.h. */
static debug_new_counter __debug_new_count;

NVWA_NAMESPACE_END

#endif // NVWA_DEBUG_NEW_H