1 /*
2  * Copyright (C) by Argonne National Laboratory
3  *     See COPYRIGHT in top-level directory
4  */
5 
6 #ifndef MPIR_MEM_H_INCLUDED
7 #define MPIR_MEM_H_INCLUDED
8 
9 #include "mpichconf.h"
10 
11 /* Make sure that we have the definitions for the malloc routines and size_t */
12 #include <stdio.h>
13 #include <stdlib.h>
14 /* strdup is often declared in string.h, so if we plan to redefine strdup,
15    we need to include string first.  That is done below, only in the
16    case where we redefine strdup */
17 
18 #if defined(__cplusplus)
19 extern "C" {
20 #endif
21 
22 #include "mpl.h"
23 
24 /* Define attribute as empty if it has no definition */
25 #ifndef ATTRIBUTE
26 #define ATTRIBUTE(a)
27 #endif
28 
29 #if defined (MPL_USE_DBG_LOGGING)
30     extern MPL_dbg_class MPIR_DBG_STRING;
31 #endif                          /* MPL_USE_DBG_LOGGING */
32 
33 /* ------------------------------------------------------------------------- */
34 /* mpir_mem.h */
35 /* ------------------------------------------------------------------------- */
36 /* Memory allocation */
37 /* style: allow:malloc:2 sig:0 */
38 /* style: allow:free:2 sig:0 */
39 /* style: allow:strdup:2 sig:0 */
40 /* style: allow:calloc:2 sig:0 */
41 /* style: allow:realloc:1 sig:0 */
42 /* style: allow:alloca:1 sig:0 */
43 /* style: define:__strdup:1 sig:0 */
44 /* style: define:strdup:1 sig:0 */
45     /* style: allow:fprintf:5 sig:0 *//* For handle debugging ONLY */
46 /* style: allow:snprintf:1 sig:0 */
47 
48 /*D
49   Memory - Memory Management Routines
50 
51   Rules for memory management:
52 
53   MPICH explicity prohibits the appearence of 'malloc', 'free',
54   'calloc', 'realloc', or 'strdup' in any code implementing a device or
55   MPI call (of course, users may use any of these calls in their code).
56   Instead, you must use 'MPL_malloc' etc.; if these are defined
57   as 'malloc', that is allowed, but an explicit use of 'malloc' instead of
58   'MPL_malloc' in the source code is not allowed.  This restriction is
59   made to simplify the use of portable tools to test for memory leaks,
60   overwrites, and other consistency checks.
61 
62   Most memory should be allocated at the time that 'MPID_Init' is
63   called and released with 'MPID_Finalize' is called.  If at all possible,
64   no other routine should fail because memory could not be allocated
65   (for example, because the user has allocated large arrays after 'MPI_Init').
66 
67   The implementation of the MPI routines will strive to avoid memory allocation
68   as well; however, operations such as 'MPI_Type_index' that create a new
69   data type that reflects data that must be copied from an array of arbitrary
70   size will have to allocate memory (and can fail; note that there is an
71   MPI error class for out-of-memory).
72 
73   Question:
74   Do we want to have an aligned allocation routine?  E.g., one that
75   aligns memory on a cache-line.
76   D*/
77 
78 /* Define the string copy and duplication functions */
79 /* ------------------------------------------------------------------------- */
80 
81 #define MPIR_Memcpy(dst, src, len)              \
82     do {                                        \
83         CHECK_MEMCPY((dst),(src),(len));        \
84         memcpy((dst), (src), (len));            \
85     } while (0)
86 
87 /* Memory allocation macros. See document. */
88 
89 /* Standard macro for generating error codes.  We set the error to be
90  * recoverable by default, but this can be changed. */
91 #ifdef HAVE_ERROR_CHECKING
92 #define MPIR_CHKMEM_SETERR(rc_,nbytes_,name_)                           \
93     rc_=MPIR_Err_create_code(MPI_SUCCESS,                               \
94                              MPIR_ERR_RECOVERABLE, __func__, __LINE__,    \
95                              MPI_ERR_OTHER, "**nomem2", "**nomem2 %d %s", nbytes_, name_)
96 #else                           /* HAVE_ERROR_CHECKING */
97 #define MPIR_CHKMEM_SETERR(rc_,nbytes_,name_) rc_=MPI_ERR_OTHER
98 #endif                          /* HAVE_ERROR_CHECKING */
99 
100     /* CHKPMEM_REGISTER is used for memory allocated within another routine */
101 
102 /* Memory used and freed within the current scope (alloca if feasible) */
103 /* Configure with --enable-alloca to set USE_ALLOCA */
104 #if defined(HAVE_ALLOCA) && defined(USE_ALLOCA)
105 #ifdef HAVE_ALLOCA_H
106 #include <alloca.h>
107 #endif                          /* HAVE_ALLOCA_H */
108 /* Define decl with a dummy definition to allow us to put a semi-colon
109    after the macro without causing the declaration block to end (restriction
110    imposed by C) */
111 #define MPIR_CHKLMEM_DECL(n_) int dummy_ ATTRIBUTE((unused))
112 #define MPIR_CHKLMEM_FREEALL()
113 #define MPIR_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
114     {                                                                   \
115         pointer_ = (type_)alloca(nbytes_);                              \
116         if (!(pointer_) && (nbytes_ > 0)) {                             \
117             MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
118             stmt_;                                                      \
119         }                                                               \
120     }
121 #else                           /* defined(HAVE_ALLOCA) && defined(USE_ALLOCA) */
122 #define MPIR_CHKLMEM_DECL(n_)                                   \
123     void *(mpiu_chklmem_stk_[n_]) = { NULL };                   \
124     int mpiu_chklmem_stk_sp_=0;                                 \
125     MPIR_AssertDeclValue(const int mpiu_chklmem_stk_sz_,n_)
126 
127 #define MPIR_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
128     {                                                                   \
129         pointer_ = (type_)MPL_malloc(nbytes_,class_);                   \
130         if (pointer_) {                                                 \
131             MPIR_Assert(mpiu_chklmem_stk_sp_<mpiu_chklmem_stk_sz_);     \
132             mpiu_chklmem_stk_[mpiu_chklmem_stk_sp_++] = (void *) pointer_; \
133         } else if (nbytes_ > 0) {                                       \
134             MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
135             stmt_;                                                      \
136         }                                                               \
137     }
138 #define MPIR_CHKLMEM_FREEALL()                                          \
139     do {                                                                \
140         while (mpiu_chklmem_stk_sp_ > 0) {                              \
141             MPL_free(mpiu_chklmem_stk_[--mpiu_chklmem_stk_sp_]);        \
142         }                                                               \
143     } while (0)
144 #endif                          /* defined(HAVE_ALLOCA) && defined(USE_ALLOCA) */
145 #define MPIR_CHKLMEM_MALLOC(pointer_,type_,nbytes_,rc_,name_,class_)    \
146     MPIR_CHKLMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_)
147 #define MPIR_CHKLMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_) \
148     MPIR_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,goto fn_fail)
149 
150 /* Persistent memory that we may want to recover if something goes wrong */
151 #define MPIR_CHKPMEM_DECL(n_)                                   \
152     void *(mpiu_chkpmem_stk_[n_]) = { NULL };                   \
153     int mpiu_chkpmem_stk_sp_=0;                                 \
154     MPIR_AssertDeclValue(const int mpiu_chkpmem_stk_sz_,n_)
155 #define MPIR_CHKPMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
156     {                                                                   \
157         pointer_ = (type_)MPL_malloc(nbytes_,class_);                   \
158         if (pointer_) {                                                 \
159             MPIR_Assert(mpiu_chkpmem_stk_sp_<mpiu_chkpmem_stk_sz_);     \
160             mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_;       \
161         } else if (nbytes_ > 0) {                                       \
162             MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
163             stmt_;                                                      \
164         }                                                               \
165     }
166 #define MPIR_CHKPMEM_REGISTER(pointer_)                         \
167     {                                                           \
168         MPIR_Assert(mpiu_chkpmem_stk_sp_<mpiu_chkpmem_stk_sz_); \
169         mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_;   \
170     }
171 #define MPIR_CHKPMEM_REAP()                                             \
172     {                                                                   \
173         while (mpiu_chkpmem_stk_sp_ > 0) {                              \
174             MPL_free(mpiu_chkpmem_stk_[--mpiu_chkpmem_stk_sp_]);        \
175         }                                                               \
176     }
177 #define MPIR_CHKPMEM_COMMIT()                   \
178     mpiu_chkpmem_stk_sp_ = 0
179 #define MPIR_CHKPMEM_MALLOC(pointer_,type_,nbytes_,rc_,name_,class_)    \
180     MPIR_CHKPMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_)
181 #define MPIR_CHKPMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_) \
182     MPIR_CHKPMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,goto fn_fail)
183 
184 /* now the CALLOC version for zeroed memory */
185 #define MPIR_CHKPMEM_CALLOC(pointer_,type_,nbytes_,rc_,name_,class_)    \
186     MPIR_CHKPMEM_CALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_)
187 #define MPIR_CHKPMEM_CALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_) \
188     MPIR_CHKPMEM_CALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,goto fn_fail)
189 #define MPIR_CHKPMEM_CALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
190     do {                                                                \
191         pointer_ = (type_)MPL_calloc(1, (nbytes_), (class_));           \
192         if (pointer_) {                                                 \
193             MPIR_Assert(mpiu_chkpmem_stk_sp_<mpiu_chkpmem_stk_sz_);     \
194             mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_;       \
195         }                                                               \
196         else if (nbytes_ > 0) {                                         \
197             MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
198             stmt_;                                                      \
199         }                                                               \
200     } while (0)
201 
202 /* A special version for routines that only allocate one item */
203 #define MPIR_CHKPMEM_MALLOC1(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
204     {                                                                   \
205         pointer_ = (type_)MPL_malloc(nbytes_,class_);                   \
206         if (!(pointer_) && (nbytes_ > 0)) {                             \
207             MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
208             stmt_;                                                      \
209         }                                                               \
210     }
211 
212 /* Provides a easy way to use realloc safely and avoid the temptation to use
213  * realloc unsafely (direct ptr assignment).  Zero-size reallocs returning NULL
214  * are handled and are not considered an error. */
215 #define MPIR_REALLOC_ORJUMP(ptr_,size_,class_,rc_)                      \
216     do {                                                                \
217         void *realloc_tmp_ = MPL_realloc((ptr_), (size_), (class_));    \
218         if (size_ != 0)                                                 \
219             MPIR_ERR_CHKANDJUMP2(!realloc_tmp_,rc_,MPI_ERR_OTHER,"**nomem2","**nomem2 %d %s",(size_),MPL_QUOTE(ptr_)); \
220         (ptr_) = realloc_tmp_;                                          \
221     } while (0)
222 
223 #if defined(HAVE_STRNCASECMP)
224 #define MPIR_Strncasecmp strncasecmp
225 #elif defined(HAVE_STRNICMP)
226 #define MPIR_Strncasecmp strnicmp
227 #else
228 /* FIXME: Provide a fallback function ? */
229 #error "No function defined for case-insensitive strncmp"
230 #endif
231 
232 /* Evaluates to a boolean expression, true if the given byte ranges overlap,
233  * false otherwise.  That is, true iff [a_,a_+a_len_) overlaps with [b_,b_+b_len_) */
234 #define MPIR_MEM_RANGES_OVERLAP(a_,a_len_,b_,b_len_)                    \
235     (((char *)(a_) >= (char *)(b_) && ((char *)(a_) < ((char *)(b_) + (b_len_)))) || \
236      ((char *)(b_) >= (char *)(a_) && ((char *)(b_) < ((char *)(a_) + (a_len_)))))
237 #if (!defined(NDEBUG) && defined(HAVE_ERROR_CHECKING))
238 
239 /* May be used to perform sanity and range checking on memcpy and mempcy-like
240    function calls.  This macro will bail out much like an MPIR_Assert if any of
241    the checks fail. */
242 #define CHECK_MEMCPY(dst_,src_,len_)                                    \
243     do {                                                                \
244         if (len_ != 0) {                                                \
245             MPL_VG_CHECK_MEM_IS_ADDRESSABLE((dst_),(len_));             \
246             MPL_VG_CHECK_MEM_IS_ADDRESSABLE((src_),(len_));             \
247             if (MPIR_MEM_RANGES_OVERLAP((dst_),(len_),(src_),(len_))) { \
248                 MPIR_Assert_fmt_msg(FALSE,("memcpy argument memory ranges overlap, dst_=%p src_=%p len_=%ld\n", \
249                                            (dst_), (src_), (long)(len_))); \
250             }                                                           \
251         }                                                               \
252     } while (0)
253 #else
254 #define CHECK_MEMCPY(dst_,src_,len_) do {} while (0)
255 #endif
256 
257 /* valgrind macros are now provided by MPL (via mpl.h included in mpiimpl.h) */
258 
259 /* ------------------------------------------------------------------------- */
260 /* end of mpir_mem.h */
261 /* ------------------------------------------------------------------------- */
262 
263 #if defined(__cplusplus)
264 }
265 #endif
266 #endif                          /* MPIR_MEM_H_INCLUDED */
267