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