-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxmalloc.h
288 lines (274 loc) · 14.2 KB
/
xmalloc.h
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#ifndef RBIMPL_XMALLOC_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_XMALLOC_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Declares ::ruby_xmalloc().
*/
#include "ruby/internal/config.h"
#ifdef STDC_HEADERS
# include <stddef.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include "ruby/internal/attr/alloc_size.h"
#include "ruby/internal/attr/nodiscard.h"
#include "ruby/internal/attr/noexcept.h"
#include "ruby/internal/attr/restrict.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/dllexport.h"
/**
* @private
* @warning Do not touch this macro.
* @warning It is an implementation detail.
* @warning It was a failure at the first place to let you know about it.
* @warning The value of this macro must match for ruby itself and all
* extension libraries, otherwise serious memory corruption shall
* occur.
*/
#ifndef USE_GC_MALLOC_OBJ_INFO_DETAILS
# define USE_GC_MALLOC_OBJ_INFO_DETAILS 0
#endif
#define xmalloc ruby_xmalloc /**< @old{ruby_xmalloc} */
#define xmalloc2 ruby_xmalloc2 /**< @old{ruby_xmalloc2} */
#define xcalloc ruby_xcalloc /**< @old{ruby_xcalloc} */
#define xrealloc ruby_xrealloc /**< @old{ruby_xrealloc} */
#define xrealloc2 ruby_xrealloc2 /**< @old{ruby_xrealloc2} */
#define xfree ruby_xfree /**< @old{ruby_xfree} */
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NODISCARD()
RBIMPL_ATTR_RESTRICT()
RBIMPL_ATTR_RETURNS_NONNULL()
RBIMPL_ATTR_ALLOC_SIZE((1))
/**
* Allocates a storage instance. It is largely the same as system malloc(),
* except:
*
* - It raises Ruby exceptions instead of returning NULL, and
* - In case of `ENOMEM` it tries to GC to make some room.
*
* @param[in] size Requested amount of memory.
* @exception rb_eNoMemError No space left for `size` bytes allocation.
* @return A valid pointer to an allocated storage instance; which has at
* least `size` bytes width, with appropriate alignment detected by
* the underlying malloc() routine.
* @note It doesn't return NULL.
* @note Unlike some malloc() implementations, it allocates something and
* returns a meaningful value even when `size` is equal to zero.
* @warning The return value shall be invalidated exactly once by either
* ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
* failure to pass it to system free(), because the system and Ruby
* might or might not share the same malloc() implementation.
*/
void *ruby_xmalloc(size_t size)
RBIMPL_ATTR_NOEXCEPT(malloc(size))
;
RBIMPL_ATTR_NODISCARD()
RBIMPL_ATTR_RESTRICT()
RBIMPL_ATTR_RETURNS_NONNULL()
RBIMPL_ATTR_ALLOC_SIZE((1,2))
/**
* Identical to ruby_xmalloc(), except it allocates `nelems` * `elemsiz` bytes.
* This is needed because the multiplication could integer overflow. On such
* situations Ruby does not try to allocate at all but raises Ruby level
* exceptions instead. If there is no integer overflow the behaviour is
* exactly the same as `ruby_xmalloc(nelems*elemsiz)`.
*
* @param[in] nelems Number of elements.
* @param[in] elemsiz Size of an element.
* @exception rb_eNoMemError No space left for allocation.
* @exception rb_eArgError `nelems` * `elemsiz` would overflow.
* @return A valid pointer to an allocated storage instance; which has at
* least `nelems` * `elemsiz` bytes width, with appropriate
* alignment detected by the underlying malloc() routine.
* @note It doesn't return NULL.
* @note Unlike some malloc() implementations, it allocates something and
* returns a meaningful value even when `nelems` or `elemsiz` or
* both are zero.
* @warning The return value shall be invalidated exactly once by either
* ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
* failure to pass it to system free(), because the system and Ruby
* might or might not share the same malloc() implementation.
*/
void *ruby_xmalloc2(size_t nelems, size_t elemsiz)
RBIMPL_ATTR_NOEXCEPT(malloc(nelems * elemsiz))
;
RBIMPL_ATTR_NODISCARD()
RBIMPL_ATTR_RESTRICT()
RBIMPL_ATTR_RETURNS_NONNULL()
RBIMPL_ATTR_ALLOC_SIZE((1,2))
/**
* Identical to ruby_xmalloc2(), except it returns a zero-filled storage
* instance. It can also be seen as a routine identical to ruby_xmalloc(),
* except it calls calloc() instead of malloc().
*
* @param[in] nelems Number of elements.
* @param[in] elemsiz Size of an element.
* @exception rb_eNoMemError No space left for allocation.
* @exception rb_eArgError `nelems` * `elemsiz` would overflow.
* @return A valid pointer to an allocated storage instance; which has at
* least `nelems` * `elemsiz` bytes width, with appropriate
* alignment detected by the underlying calloc() routine.
* @post The returned storage instance is filled with zeros.
* @note It doesn't return NULL.
* @note Unlike some calloc() implementations, it allocates something and
* returns a meaningful value even when `nelems` or `elemsiz` or
* both are zero.
* @warning The return value shall be invalidated exactly once by either
* ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
* failure to pass it to system free(), because the system and Ruby
* might or might not share the same malloc() implementation.
*/
void *ruby_xcalloc(size_t nelems, size_t elemsiz)
RBIMPL_ATTR_NOEXCEPT(calloc(nelems, elemsiz))
;
RBIMPL_ATTR_NODISCARD()
RBIMPL_ATTR_RETURNS_NONNULL()
RBIMPL_ATTR_ALLOC_SIZE((2))
/**
* Resize the storage instance.
*
* @param[in] ptr A valid pointer to a storage instance that was
* previously returned from either:
* - ruby_xmalloc(),
* - ruby_xmalloc2(),
* - ruby_xcalloc(),
* - ruby_xrealloc(), or
* - ruby_xrealloc2().
* @param[in] newsiz Requested new amount of memory.
* @exception rb_eNoMemError No space left for `newsiz` bytes allocation.
* @return A valid pointer to a (possibly newly allocated) storage
* instance; which has at least `newsiz` bytes width, with
* appropriate alignment detected by the underlying realloc()
* routine.
* @pre The passed pointer must point to a valid live storage instance.
* It is a failure to pass an already freed pointer.
* @post In case the function returns the passed pointer as-is, the
* storage instance that the pointer holds is either grown or
* shrunken to have at least `newsiz` bytes. Otherwise a valid
* pointer to a newly allocated storage instance is returned. In
* this case `ptr` is invalidated as if it was passed to
* ruby_xfree().
* @note It doesn't return NULL.
* @warning Unlike some realloc() implementations, passing zero to `newsiz`
* is not the same as calling ruby_xfree(), because this function
* never returns NULL. Something meaningful still returns then.
* @warning It is a failure not to check the return value. Do not assume
* anything on it. It could be either identical to, or distinct
* form the passed argument.
* @warning Do not assume anything on the alignment of the return value.
* There is no guarantee that it inherits the passed argument's
* one.
* @warning The return value shall be invalidated exactly once by either
* ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
* failure to pass it to system free(), because the system and Ruby
* might or might not share the same malloc() implementation.
*/
void *ruby_xrealloc(void *ptr, size_t newsiz)
RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newsiz))
;
RBIMPL_ATTR_NODISCARD()
RBIMPL_ATTR_RETURNS_NONNULL()
RBIMPL_ATTR_ALLOC_SIZE((2,3))
/**
* Identical to ruby_xrealloc(), except it resizes the given storage instance
* to `newelems` * `newsiz` bytes. This is needed because the multiplication
* could integer overflow. On such situations Ruby does not try to touch the
* contents of argument pointer at all but raises Ruby level exceptions
* instead. If there is no integer overflow the behaviour is exactly the same
* as `ruby_xrealloc(ptr,nelems*elemsiz)`.
*
* This is roughly the same as reallocarray() function that OpenBSD
* etc. provides, but also interacts with our GC.
*
* @param[in] ptr A valid pointer to a storage instance that was
* previously returned from either:
* - ruby_xmalloc(),
* - ruby_xmalloc2(),
* - ruby_xcalloc(),
* - ruby_xrealloc(), or
* - ruby_xrealloc2().
* @param[in] newelems Requested new number of elements.
* @param[in] newsiz Requested new size of each element.
* @exception rb_eNoMemError No space left for allocation.
* @exception rb_eArgError `newelems` * `newsiz` would overflow.
* @return A valid pointer to a (possibly newly allocated) storage
* instance; which has at least `newelems` * `newsiz` bytes width,
* with appropriate alignment detected by the underlying realloc()
* routine.
* @pre The passed pointer must point to a valid live storage instance.
* It is a failure to pass an already freed pointer.
* @post In case the function returns the passed pointer as-is, the
* storage instance that the pointer holds is either grown or
* shrunken to have at least `newelems` * `newsiz` bytes.
* Otherwise a valid pointer to a newly allocated storage instance
* is returned. In this case `ptr` is invalidated as if it was
* passed to ruby_xfree().
* @note It doesn't return NULL.
* @warning Unlike some realloc() implementations, passing zero to either
* `newelems` or `elemsiz` are not the same as calling
* ruby_xfree(), because this function never returns NULL.
* Something meaningful still returns then.
* @warning It is a failure not to check the return value. Do not assume
* anything on it. It could be either identical to, or distinct
* form the passed argument.
* @warning Do not assume anything on the alignment of the return value.
* There is no guarantee that it inherits the passed argument's
* one.
* @warning The return value shall be invalidated exactly once by either
* ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
* failure to pass it to system free(), because the system and Ruby
* might or might not share the same malloc() implementation.
*/
void *ruby_xrealloc2(void *ptr, size_t newelems, size_t newsiz)
RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newelems * newsiz))
;
/**
* Deallocates a storage instance.
*
* @param[out] ptr Either
* - NULL, or
* - a valid pointer previously returned from one of:
* - ruby_xmalloc(),
* - ruby_xmalloc2(),
* - ruby_xcalloc(),
* - ruby_xrealloc(), or
* - ruby_xrealloc2().
* @pre The passed pointer must point to a valid live storage instance.
* It is a failure to pass an already freed pointer.
* @post The storage instance pointed by the passed pointer gets
* invalidated; it is no longer addressable.
* @warning Every single storage instance that was previously allocated by
* either ruby_xmalloc(), ruby_xmalloc2(), ruby_xcalloc(),
* ruby_xrealloc(), or ruby_xrealloc2() shall be invalidated
* exactly once by either passing it to ruby_xfree(), or passing
* it to either ruby_xrealloc(), ruby_xrealloc2() then check the
* return value for invalidation.
* @warning Do not pass anything other than pointers described above. For
* instance pointers returned from malloc() or mmap() shall not be
* passed to this function, because the underlying memory
* management mechanism could differ.
* @warning Do not pass any invalid pointers to this function e.g. by
* calling it twice with a same argument.
*/
void ruby_xfree(void *ptr)
RBIMPL_ATTR_NOEXCEPT(free(ptr))
;
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_XMALLOC_H */