aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/kmp_wrapper_malloc.h
blob: 453d1ef5e7c7ecaa77710b6de8f3821fd1f70977 (plain)
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
/*
 * kmp_wrapper_malloc.h -- Wrappers for memory allocation routines
 *                         (malloc(), free(), and others).
 */


//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//


#ifndef KMP_WRAPPER_MALLOC_H
#define KMP_WRAPPER_MALLOC_H

/*
    This header serves for 3 purposes:

        1. Declaring standard memory allocation rourines in OS-independent way.
        2. Passing source location info through memory allocation wrappers.
        3. Enabling native memory debugging capabilities.


    1. Declaring standard memory allocation rourines in OS-independent way.
    -----------------------------------------------------------------------

    On Linux* OS, alloca() function is declared in <alloca.h> header, while on Windows* OS there is no
    <alloca.h> header, function _alloca() (note underscore!) is declared in <malloc.h>. This header
    eliminates these differences, so client code incluiding "kmp_wrapper_malloc.h" can rely on
    following routines:

        malloc
        calloc
        realloc
        free
        alloca

    in OS-independent way. It also enables memory tracking capabilities in debug build. (Currently
    it is available only on Windows* OS.)


    2. Passing source location info through memory allocation wrappers.
    -------------------------------------------------------------------

    Some tools may help debugging memory errors, for example, report memory leaks. However, memory
    allocation wrappers may hinder source location.

    For example:

        void * aligned_malloc( int size ) {
            void * ptr = malloc( size ); // All the memory leaks will be reported at this line.
            // some adjustments...
            return ptr;
        };

        ptr = aligned_malloc( size );    // Memory leak will *not* be detected here. :-(

    To overcome the problem, information about original source location should be passed through all
    the memory allocation wrappers, for example:

        void * aligned_malloc( int size, char const * file, int line ) {
            void * ptr = _malloc_dbg( size, file, line );
            // some adjustments...
            return ptr;
        };

        void * ptr = aligned_malloc( size, __FILE__, __LINE__ );

    This is a good idea for debug, but passing additional arguments impacts performance. Disabling
    extra arguments in release version of the software introduces too many conditional compilation,
    which makes code unreadable. This header defines few macros and functions facilitating it:

        void * _aligned_malloc( int size KMP_SRC_LOC_DECL ) {
            void * ptr = malloc_src_loc( size KMP_SRC_LOC_PARM );
            // some adjustments...
            return ptr;
        };
        #define aligned_malloc( size ) _aligned_malloc( (size) KMP_SRC_LOC_CURR )
            // Use macro instead of direct call to function.

        void * ptr = aligned_malloc( size );  // Bingo! Memory leak will be reported at this line.


    3. Enabling native memory debugging capabilities.
    -------------------------------------------------

    Some platforms may offer memory debugging capabilities. For example, debug version of Microsoft
    RTL tracks all memory allocations and can report memory leaks. This header enables this, and
    makes report more useful (see "Passing source location info through memory allocation
    wrappers").

*/

#include <stdlib.h>

#include "kmp_os.h"

// Include alloca() declaration.
#if KMP_OS_WINDOWS
    #include <malloc.h>        // Windows* OS: _alloca() declared in "malloc.h".
    #define alloca _alloca     // Allow to use alloca() with no underscore.
#elif KMP_OS_FREEBSD || KMP_OS_NETBSD
    // Declared in "stdlib.h".
#elif KMP_OS_UNIX
    #include <alloca.h>        // Linux* OS and OS X*: alloc() declared in "alloca".
#else
    #error Unknown or unsupported OS.
#endif

/*
    KMP_SRC_LOC_DECL -- Declaring source location paramemters, to be used in function declaration.
    KMP_SRC_LOC_PARM -- Source location paramemters, to be used to pass parameters to underlying
        levels.
    KMP_SRC_LOC_CURR -- Source location arguments describing current location, to be used at
        top-level.

    Typical usage:

        void * _aligned_malloc( int size KMP_SRC_LOC_DECL ) {
            // Note: Comma is missed before KMP_SRC_LOC_DECL.
            KE_TRACE( 25, ( "called from %s:%d\n", KMP_SRC_LOC_PARM ) );
            ...
        }
        #define aligned_malloc( size ) _aligned_malloc( (size) KMP_SRC_LOC_CURR )
            // Use macro instead of direct call to function -- macro passes info about current
            // source location to the func.
*/
#if KMP_DEBUG
    #define KMP_SRC_LOC_DECL    , char const * _file_, int _line_
    #define KMP_SRC_LOC_PARM    , _file_, _line_
    #define KMP_SRC_LOC_CURR    , __FILE__, __LINE__
#else
    #define KMP_SRC_LOC_DECL
    #define KMP_SRC_LOC_PARM
    #define KMP_SRC_LOC_CURR
#endif // KMP_DEBUG

/*
    malloc_src_loc() and free_src_loc() are pseudo-functions (really macros) with accepts extra
    arguments (source location info) in debug mode. They should be used in place of malloc() and
    free(), this allows enabling native memory debugging capabilities (if any).

    Typical usage:

        ptr = malloc_src_loc( size KMP_SRC_LOC_PARM );
            // Inside memory allocation wrapper, or
        ptr = malloc_src_loc( size KMP_SRC_LOC_CURR );
            // Outside of memory allocation wrapper.


*/
#define malloc_src_loc( args )    _malloc_src_loc( args )
#define free_src_loc(   args )    _free_src_loc(   args )
    /*
        Depending on build mode (debug or release), malloc_src_loc is declared with 1 or 3
        parameters, but calls to malloc_src_loc() are always the same:

            ... malloc_src_loc( size KMP_SRC_LOC_PARM ); // or KMP_SRC_LOC_CURR

        Compiler issues warning/error "too few arguments in macro invocation". Declaring two
        macroses, malloc_src_loc() and _malloc_src_loc() overcomes the problem.
    */

#if KMP_DEBUG

    #if KMP_OS_WINDOWS && _DEBUG
        // KMP_DEBUG != _DEBUG. MS debug RTL is available only if _DEBUG is defined.

        // Windows* OS has native memory debugging capabilities. Enable them.

        #include <crtdbg.h>

        #define KMP_MEM_BLOCK           _CLIENT_BLOCK
        #define malloc( size )          _malloc_dbg( (size), KMP_MEM_BLOCK, __FILE__, __LINE__ )
        #define calloc( num, size )     _calloc_dbg( (num), (size), KMP_MEM_BLOCK, __FILE__, __LINE__ )
        #define realloc( ptr, size )    _realloc_dbg( (ptr), (size), KMP_MEM_BLOCK, __FILE__, __LINE__ )
        #define free( ptr )             _free_dbg( (ptr), KMP_MEM_BLOCK )

        #define _malloc_src_loc( size, file, line )  _malloc_dbg( (size), KMP_MEM_BLOCK, (file), (line) )
        #define _free_src_loc(    ptr, file, line )  _free_dbg(   (ptr),  KMP_MEM_BLOCK                 )

    #else

        // Linux* OS, OS X*, or non-debug Windows* OS.

        #define _malloc_src_loc( size, file, line )    malloc( (size) )
        #define _free_src_loc( ptr, file, line )       free( (ptr) )

    #endif

#else

    // In release build malloc_src_loc() and free_src_loc() do not have extra parameters.
    #define _malloc_src_loc( size )    malloc( (size) )
    #define _free_src_loc( ptr )       free( (ptr) )

#endif // KMP_DEBUG

#endif // KMP_WRAPPER_MALLOC_H

// end of file //