10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric  * kmp_wrapper_malloc.h -- Wrappers for memory allocation routines
30b57cec5SDimitry Andric  *                         (malloc(), free(), and others).
40b57cec5SDimitry Andric  */
50b57cec5SDimitry Andric 
60b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
70b57cec5SDimitry Andric //
80b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
90b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
100b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef KMP_WRAPPER_MALLOC_H
150b57cec5SDimitry Andric #define KMP_WRAPPER_MALLOC_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric /* This header serves for 3 purposes:
185ffd83dbSDimitry Andric    1. Declaring standard memory allocation routines in OS-independent way.
190b57cec5SDimitry Andric    2. Passing source location info through memory allocation wrappers.
200b57cec5SDimitry Andric    3. Enabling native memory debugging capabilities.
210b57cec5SDimitry Andric 
225ffd83dbSDimitry Andric    1. Declaring standard memory allocation routines in OS-independent way.
230b57cec5SDimitry Andric    -----------------------------------------------------------------------
240b57cec5SDimitry Andric    On Linux* OS, alloca() function is declared in <alloca.h> header, while on
250b57cec5SDimitry Andric    Windows* OS there is no <alloca.h> header, function _alloca() (note
260b57cec5SDimitry Andric    underscore!) is declared in <malloc.h>. This header eliminates these
27480093f4SDimitry Andric    differences, so client code including "kmp_wrapper_malloc.h" can rely on
280b57cec5SDimitry Andric    following routines:
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric         malloc
310b57cec5SDimitry Andric         calloc
320b57cec5SDimitry Andric         realloc
330b57cec5SDimitry Andric         free
340b57cec5SDimitry Andric         alloca
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric    in OS-independent way. It also enables memory tracking capabilities in debug
370b57cec5SDimitry Andric    build. (Currently it is available only on Windows* OS.)
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric    2. Passing source location info through memory allocation wrappers.
400b57cec5SDimitry Andric    -------------------------------------------------------------------
410b57cec5SDimitry Andric    Some tools may help debugging memory errors, for example, report memory
420b57cec5SDimitry Andric    leaks. However, memory allocation wrappers may hinder source location.
430b57cec5SDimitry Andric    For example:
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric    void * aligned_malloc( int size ) {
460b57cec5SDimitry Andric      void * ptr = malloc( size ); // All the memory leaks will be reported at
470b57cec5SDimitry Andric                                   // this line.
480b57cec5SDimitry Andric      // some adjustments...
490b57cec5SDimitry Andric      return ptr;
500b57cec5SDimitry Andric    };
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric    ptr = aligned_malloc( size ); // Memory leak will *not* be detected here. :-(
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric    To overcome the problem, information about original source location should
550b57cec5SDimitry Andric    be passed through all the memory allocation wrappers, for example:
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric    void * aligned_malloc( int size, char const * file, int line ) {
580b57cec5SDimitry Andric      void * ptr = _malloc_dbg( size, file, line );
590b57cec5SDimitry Andric      // some adjustments...
600b57cec5SDimitry Andric      return ptr;
610b57cec5SDimitry Andric    };
620b57cec5SDimitry Andric    void * ptr = aligned_malloc( size, __FILE__, __LINE__ );
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric    This is a good idea for debug, but passing additional arguments impacts
650b57cec5SDimitry Andric    performance. Disabling extra arguments in release version of the software
660b57cec5SDimitry Andric    introduces too many conditional compilation, which makes code unreadable.
670b57cec5SDimitry Andric    This header defines few macros and functions facilitating it:
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric    void * _aligned_malloc( int size KMP_SRC_LOC_DECL ) {
700b57cec5SDimitry Andric      void * ptr = malloc_src_loc( size KMP_SRC_LOC_PARM );
710b57cec5SDimitry Andric      // some adjustments...
720b57cec5SDimitry Andric      return ptr;
730b57cec5SDimitry Andric    };
740b57cec5SDimitry Andric    #define aligned_malloc( size ) _aligned_malloc( (size) KMP_SRC_LOC_CURR )
750b57cec5SDimitry Andric    // Use macro instead of direct call to function.
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric    void * ptr = aligned_malloc( size );  // Bingo! Memory leak will be
780b57cec5SDimitry Andric                                          // reported at this line.
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric    3. Enabling native memory debugging capabilities.
810b57cec5SDimitry Andric    -------------------------------------------------
820b57cec5SDimitry Andric    Some platforms may offer memory debugging capabilities. For example, debug
830b57cec5SDimitry Andric    version of Microsoft RTL tracks all memory allocations and can report memory
840b57cec5SDimitry Andric    leaks. This header enables this, and makes report more useful (see "Passing
850b57cec5SDimitry Andric    source location info through memory allocation wrappers").
860b57cec5SDimitry Andric */
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric #include <stdlib.h>
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric #include "kmp_os.h"
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric // Include alloca() declaration.
930b57cec5SDimitry Andric #if KMP_OS_WINDOWS
940b57cec5SDimitry Andric #include <malloc.h> // Windows* OS: _alloca() declared in "malloc.h".
950b57cec5SDimitry Andric #if KMP_MSVC_COMPAT
960b57cec5SDimitry Andric #define alloca _alloca // Allow to use alloca() with no underscore.
970b57cec5SDimitry Andric #endif
980b57cec5SDimitry Andric #elif KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_OPENBSD
990b57cec5SDimitry Andric // Declared in "stdlib.h".
1000b57cec5SDimitry Andric #elif KMP_OS_UNIX
1010b57cec5SDimitry Andric #include <alloca.h> // Linux* OS and OS X*: alloc() declared in "alloca".
1020b57cec5SDimitry Andric #else
1030b57cec5SDimitry Andric #error Unknown or unsupported OS.
1040b57cec5SDimitry Andric #endif
1050b57cec5SDimitry Andric 
1065ffd83dbSDimitry Andric /* KMP_SRC_LOC_DECL -- Declaring source location parameters, to be used in
1070b57cec5SDimitry Andric    function declaration.
1085ffd83dbSDimitry Andric    KMP_SRC_LOC_PARM -- Source location parameters, to be used to pass
1090b57cec5SDimitry Andric    parameters to underlying levels.
1100b57cec5SDimitry Andric    KMP_SRC_LOC_CURR -- Source location arguments describing current location,
1110b57cec5SDimitry Andric    to be used at top-level.
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric    Typical usage:
1140b57cec5SDimitry Andric    void * _aligned_malloc( int size KMP_SRC_LOC_DECL ) {
1150b57cec5SDimitry Andric      // Note: Comma is missed before KMP_SRC_LOC_DECL.
1160b57cec5SDimitry Andric      KE_TRACE( 25, ( "called from %s:%d\n", KMP_SRC_LOC_PARM ) );
1170b57cec5SDimitry Andric      ...
1180b57cec5SDimitry Andric    }
1190b57cec5SDimitry Andric    #define aligned_malloc( size ) _aligned_malloc( (size) KMP_SRC_LOC_CURR )
1200b57cec5SDimitry Andric    // Use macro instead of direct call to function -- macro passes info
1210b57cec5SDimitry Andric    // about current source location to the func.
1220b57cec5SDimitry Andric */
1230b57cec5SDimitry Andric #if KMP_DEBUG
1240b57cec5SDimitry Andric #define KMP_SRC_LOC_DECL , char const *_file_, int _line_
1250b57cec5SDimitry Andric #define KMP_SRC_LOC_PARM , _file_, _line_
1260b57cec5SDimitry Andric #define KMP_SRC_LOC_CURR , __FILE__, __LINE__
1270b57cec5SDimitry Andric #else
1280b57cec5SDimitry Andric #define KMP_SRC_LOC_DECL
1290b57cec5SDimitry Andric #define KMP_SRC_LOC_PARM
1300b57cec5SDimitry Andric #define KMP_SRC_LOC_CURR
1310b57cec5SDimitry Andric #endif // KMP_DEBUG
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric /* malloc_src_loc() and free_src_loc() are pseudo-functions (really macros)
1340b57cec5SDimitry Andric    with accepts extra arguments (source location info) in debug mode. They
1350b57cec5SDimitry Andric    should be used in place of malloc() and free(), this allows enabling native
1360b57cec5SDimitry Andric    memory debugging capabilities (if any).
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric    Typical usage:
1390b57cec5SDimitry Andric    ptr = malloc_src_loc( size KMP_SRC_LOC_PARM );
1400b57cec5SDimitry Andric    // Inside memory allocation wrapper, or
1410b57cec5SDimitry Andric    ptr = malloc_src_loc( size KMP_SRC_LOC_CURR );
1420b57cec5SDimitry Andric    // Outside of memory allocation wrapper.
1430b57cec5SDimitry Andric */
1440b57cec5SDimitry Andric #define malloc_src_loc(args) _malloc_src_loc(args)
1450b57cec5SDimitry Andric #define free_src_loc(args) _free_src_loc(args)
1460b57cec5SDimitry Andric /* Depending on build mode (debug or release), malloc_src_loc is declared with
1470b57cec5SDimitry Andric    1 or 3 parameters, but calls to malloc_src_loc() are always the same:
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric    ... malloc_src_loc( size KMP_SRC_LOC_PARM ); // or KMP_SRC_LOC_CURR
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric    Compiler issues warning/error "too few arguments in macro invocation".
1520b57cec5SDimitry Andric    Declaring two macros, malloc_src_loc() and _malloc_src_loc(), overcomes the
1530b57cec5SDimitry Andric    problem. */
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric #if KMP_DEBUG
1560b57cec5SDimitry Andric 
157bdd1243dSDimitry Andric #if KMP_OS_WINDOWS && _DEBUG && !defined(__MINGW32__)
1580b57cec5SDimitry Andric // KMP_DEBUG != _DEBUG. MS debug RTL is available only if _DEBUG is defined.
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric // Windows* OS has native memory debugging capabilities. Enable them.
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric #include <crtdbg.h>
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric #define KMP_MEM_BLOCK _CLIENT_BLOCK
1650b57cec5SDimitry Andric #define malloc(size) _malloc_dbg((size), KMP_MEM_BLOCK, __FILE__, __LINE__)
1660b57cec5SDimitry Andric #define calloc(num, size)                                                      \
1670b57cec5SDimitry Andric   _calloc_dbg((num), (size), KMP_MEM_BLOCK, __FILE__, __LINE__)
1680b57cec5SDimitry Andric #define realloc(ptr, size)                                                     \
1690b57cec5SDimitry Andric   _realloc_dbg((ptr), (size), KMP_MEM_BLOCK, __FILE__, __LINE__)
1700b57cec5SDimitry Andric #define free(ptr) _free_dbg((ptr), KMP_MEM_BLOCK)
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric #define _malloc_src_loc(size, file, line)                                      \
1730b57cec5SDimitry Andric   _malloc_dbg((size), KMP_MEM_BLOCK, (file), (line))
1740b57cec5SDimitry Andric #define _free_src_loc(ptr, file, line) _free_dbg((ptr), KMP_MEM_BLOCK)
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric #else
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric // Linux* OS, OS X*, or non-debug Windows* OS.
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric #define _malloc_src_loc(size, file, line) malloc((size))
1810b57cec5SDimitry Andric #define _free_src_loc(ptr, file, line) free((ptr))
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric #endif
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric #else
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric // In release build malloc_src_loc() and free_src_loc() do not have extra
1880b57cec5SDimitry Andric // parameters.
1890b57cec5SDimitry Andric #define _malloc_src_loc(size) malloc((size))
1900b57cec5SDimitry Andric #define _free_src_loc(ptr) free((ptr))
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric #endif // KMP_DEBUG
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric #endif // KMP_WRAPPER_MALLOC_H
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric // end of file //
197