1 /*
2  * kmp_wrapper_malloc.h -- Wrappers for memory allocation routines
3  *                         (malloc(), free(), and others).
4  */
5 
6 
7 //===----------------------------------------------------------------------===//
8 //
9 //                     The LLVM Compiler Infrastructure
10 //
11 // This file is dual licensed under the MIT and the University of Illinois Open
12 // Source Licenses. See LICENSE.txt for details.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 
17 #ifndef KMP_WRAPPER_MALLOC_H
18 #define KMP_WRAPPER_MALLOC_H
19 
20 /*
21     This header serves for 3 purposes:
22 
23         1. Declaring standard memory allocation rourines in OS-independent way.
24         2. Passing source location info through memory allocation wrappers.
25         3. Enabling native memory debugging capabilities.
26 
27 
28     1. Declaring standard memory allocation rourines in OS-independent way.
29     -----------------------------------------------------------------------
30 
31     On Linux* OS, alloca() function is declared in <alloca.h> header, while on Windows* OS there is no
32     <alloca.h> header, function _alloca() (note underscore!) is declared in <malloc.h>. This header
33     eliminates these differences, so client code incluiding "kmp_wrapper_malloc.h" can rely on
34     following routines:
35 
36         malloc
37         calloc
38         realloc
39         free
40         alloca
41 
42     in OS-independent way. It also enables memory tracking capabilities in debug build. (Currently
43     it is available only on Windows* OS.)
44 
45 
46     2. Passing source location info through memory allocation wrappers.
47     -------------------------------------------------------------------
48 
49     Some tools may help debugging memory errors, for example, report memory leaks. However, memory
50     allocation wrappers may hinder source location.
51 
52     For example:
53 
54         void * aligned_malloc( int size ) {
55             void * ptr = malloc( size ); // All the memory leaks will be reported at this line.
56             // some adjustments...
57             return ptr;
58         };
59 
60         ptr = aligned_malloc( size );    // Memory leak will *not* be detected here. :-(
61 
62     To overcome the problem, information about original source location should be passed through all
63     the memory allocation wrappers, for example:
64 
65         void * aligned_malloc( int size, char const * file, int line ) {
66             void * ptr = _malloc_dbg( size, file, line );
67             // some adjustments...
68             return ptr;
69         };
70 
71         void * ptr = aligned_malloc( size, __FILE__, __LINE__ );
72 
73     This is a good idea for debug, but passing additional arguments impacts performance. Disabling
74     extra arguments in release version of the software introduces too many conditional compilation,
75     which makes code unreadable. This header defines few macros and functions facilitating it:
76 
77         void * _aligned_malloc( int size KMP_SRC_LOC_DECL ) {
78             void * ptr = malloc_src_loc( size KMP_SRC_LOC_PARM );
79             // some adjustments...
80             return ptr;
81         };
82         #define aligned_malloc( size ) _aligned_malloc( (size) KMP_SRC_LOC_CURR )
83             // Use macro instead of direct call to function.
84 
85         void * ptr = aligned_malloc( size );  // Bingo! Memory leak will be reported at this line.
86 
87 
88     3. Enabling native memory debugging capabilities.
89     -------------------------------------------------
90 
91     Some platforms may offer memory debugging capabilities. For example, debug version of Microsoft
92     RTL tracks all memory allocations and can report memory leaks. This header enables this, and
93     makes report more useful (see "Passing source location info through memory allocation
94     wrappers").
95 
96 */
97 
98 #include <stdlib.h>
99 
100 #include "kmp_os.h"
101 
102 // Include alloca() declaration.
103 #if KMP_OS_WINDOWS
104     #include <malloc.h>        // Windows* OS: _alloca() declared in "malloc.h".
105     #define alloca _alloca     // Allow to use alloca() with no underscore.
106 #elif KMP_OS_FREEBSD || KMP_OS_NETBSD
107     // Declared in "stdlib.h".
108 #elif KMP_OS_UNIX
109     #include <alloca.h>        // Linux* OS and OS X*: alloc() declared in "alloca".
110 #else
111     #error Unknown or unsupported OS.
112 #endif
113 
114 /*
115     KMP_SRC_LOC_DECL -- Declaring source location paramemters, to be used in function declaration.
116     KMP_SRC_LOC_PARM -- Source location paramemters, to be used to pass parameters to underlying
117         levels.
118     KMP_SRC_LOC_CURR -- Source location arguments describing current location, to be used at
119         top-level.
120 
121     Typical usage:
122 
123         void * _aligned_malloc( int size KMP_SRC_LOC_DECL ) {
124             // Note: Comma is missed before KMP_SRC_LOC_DECL.
125             KE_TRACE( 25, ( "called from %s:%d\n", KMP_SRC_LOC_PARM ) );
126             ...
127         }
128         #define aligned_malloc( size ) _aligned_malloc( (size) KMP_SRC_LOC_CURR )
129             // Use macro instead of direct call to function -- macro passes info about current
130             // source location to the func.
131 */
132 #if KMP_DEBUG
133     #define KMP_SRC_LOC_DECL    , char const * _file_, int _line_
134     #define KMP_SRC_LOC_PARM    , _file_, _line_
135     #define KMP_SRC_LOC_CURR    , __FILE__, __LINE__
136 #else
137     #define KMP_SRC_LOC_DECL
138     #define KMP_SRC_LOC_PARM
139     #define KMP_SRC_LOC_CURR
140 #endif // KMP_DEBUG
141 
142 /*
143     malloc_src_loc() and free_src_loc() are pseudo-functions (really macros) with accepts extra
144     arguments (source location info) in debug mode. They should be used in place of malloc() and
145     free(), this allows enabling native memory debugging capabilities (if any).
146 
147     Typical usage:
148 
149         ptr = malloc_src_loc( size KMP_SRC_LOC_PARM );
150             // Inside memory allocation wrapper, or
151         ptr = malloc_src_loc( size KMP_SRC_LOC_CURR );
152             // Outside of memory allocation wrapper.
153 
154 
155 */
156 #define malloc_src_loc( args )    _malloc_src_loc( args )
157 #define free_src_loc(   args )    _free_src_loc(   args )
158     /*
159         Depending on build mode (debug or release), malloc_src_loc is declared with 1 or 3
160         parameters, but calls to malloc_src_loc() are always the same:
161 
162             ... malloc_src_loc( size KMP_SRC_LOC_PARM ); // or KMP_SRC_LOC_CURR
163 
164         Compiler issues warning/error "too few arguments in macro invocation". Declaring two
165         macroses, malloc_src_loc() and _malloc_src_loc() overcomes the problem.
166     */
167 
168 #if KMP_DEBUG
169 
170     #if KMP_OS_WINDOWS && _DEBUG
171         // KMP_DEBUG != _DEBUG. MS debug RTL is available only if _DEBUG is defined.
172 
173         // Windows* OS has native memory debugging capabilities. Enable them.
174 
175         #include <crtdbg.h>
176 
177         #define KMP_MEM_BLOCK           _CLIENT_BLOCK
178         #define malloc( size )          _malloc_dbg( (size), KMP_MEM_BLOCK, __FILE__, __LINE__ )
179         #define calloc( num, size )     _calloc_dbg( (num), (size), KMP_MEM_BLOCK, __FILE__, __LINE__ )
180         #define realloc( ptr, size )    _realloc_dbg( (ptr), (size), KMP_MEM_BLOCK, __FILE__, __LINE__ )
181         #define free( ptr )             _free_dbg( (ptr), KMP_MEM_BLOCK )
182 
183         #define _malloc_src_loc( size, file, line )  _malloc_dbg( (size), KMP_MEM_BLOCK, (file), (line) )
184         #define _free_src_loc(    ptr, file, line )  _free_dbg(   (ptr),  KMP_MEM_BLOCK                 )
185 
186     #else
187 
188         // Linux* OS, OS X*, or non-debug Windows* OS.
189 
190         #define _malloc_src_loc( size, file, line )    malloc( (size) )
191         #define _free_src_loc( ptr, file, line )       free( (ptr) )
192 
193     #endif
194 
195 #else
196 
197     // In release build malloc_src_loc() and free_src_loc() do not have extra parameters.
198     #define _malloc_src_loc( size )    malloc( (size) )
199     #define _free_src_loc( ptr )       free( (ptr) )
200 
201 #endif // KMP_DEBUG
202 
203 #endif // KMP_WRAPPER_MALLOC_H
204 
205 // end of file //
206