-
Notifications
You must be signed in to change notification settings - Fork 12
/
smalloc.3
495 lines (434 loc) · 13.2 KB
/
smalloc.3
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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
.Dd 19Aug2017
.Dt SMALLOC 3
.Os R2
.Sh NAME
.Nm smalloc
: sm_malloc, sm_zalloc, sm_free, sm_realloc, sm_realloc_move, sm_calloc, sm_szalloc
.Nd allocate, manage, resize, query size and free dynamic memory which is allocated from user pointed static memory area;
sm_alloc_valid - query object validity;
sm_malloc_stats - get attached pool statistics;
sm_set_default_pool, sm_release_default_pool - attach and release pool;
sm_set_ub_handler - set global
.Nm
undefined behavior handler.
.Sh SYNOPSIS
.In errno.h
.In smalloc.h
.Fn "void *sm_malloc" "size_t n"
.Fn "void *sm_zalloc" "size_t n"
.Fn "void sm_free" "void *p"
.Fn "void *sm_realloc" "void *p" "size_t n"
.Fn "void *sm_realloc_move" "void *p" "size_t n"
.Fn "void *sm_calloc" "size_t y" "size_t x"
.Fn "size_t sm_szalloc" "void *p"
.Fn "int sm_alloc_valid" "void *p"
.Fn "int sm_malloc_stats" "size_t *total" "size_t *user" "size_t *free" "int *nr_obj"
.Fn "int sm_set_default_pool" "void *pool" "size_t pool_size" "int do_zero" "smalloc_oom_handler oom_handler_fn"
.Fn "int sm_release_default_pool" "void"
.Fn "void sm_set_ub_handler" "smalloc_ub_handler ub_handler"
.Sh DESCRIPTION
.Nm
is a portable and simple memory management package which is intended to be used especially with user provided memory regions. It is like a normal
.Xr malloc 3
provided by any modern system today (and you should expect conventional behavior), but it extends it by allowing the user to specify memory area,
.Em a custom heap ,
in which all the allocations will be stored.
.Sy sm_malloc, sm_zalloc, sm_calloc
allocate memory.
.Sy sm_zalloc
and
.Sy sm_calloc
guarantee zero-fill of newly created object.
.Sy sm_malloc
may return object containing garbage (usually, if pool is static storage, it contains zeroes after program start, but after extensive usage it will contain garbage).
.Sy sm_realloc
change already allocated object size, but also can be used to allocate and free memory too.
.Sy sm_realloc_move
works like
.Sy sm_realloc ,
but fails if physical reallocation (move) of the object is required.
.Sy sm_free
deallocates
.Nm
allocated memory.
.Sy sm_szalloc
queries a
.Em valid
.Nm
memory block size.
.Sy sm_alloc_valid
tests if a pointer belongs to valid
.Nm
object within the pool.
.Sy sm_malloc_stats
accept four pointers to numbers where it stores current pool state:
.Fa *total
accepts total used bytes in pool: user data with any overhead added by
.Nm ,
.Fa *user
accepts total user bytes with any user overhead,
.Fa *free
accepts total free bytes still available, and
.Fa *nr_obj
accepts number of already allocated objects within the pool.
.Sy sm_set_default_pool
takes
.Fa *pool
pool of
.Fa pool_size
size and registers it as a global default pool.
Nonzero
.Fa do_zero
instructs
.Nm
to zero-fill pool before use,
.Em and also zero any newly allocated objects before returning them, and zero any to be freed objects upon to returning them back to the pool.
If
.Fa do_zero
is 0, then only
.Sy sm_zalloc
and
.Sy sm_calloc
zero-fill object before returning them to caller, but
.Sy sm_malloc
will return object possibly containing garbage.
.Fa oom_handler_fn
can be either
.Em NULL
or a pointer to OOM handler function (see
.Sx ERROR HANDLERS
for a description). In case of
.Em NULL ,
no OOM handler is called at all on an OOM condition.
.Sy sm_release_default_pool
deregisters current pool and zero-fills it (erases) if
.Fa do_zero
argument to
.Sy sm_set_default_pool
was nonzero. All further calls to any allocation or freeing functions will fail without registered pool.
.Sy sm_set_ub_handler
sets global undefined behavior handler. It's description is given in
.Sx ERROR HANDLERS
section.
If
.Em NULL
is passed as
.Fa ub_handler ,
then internal UB handler is reset to
.Nm
default one: crashing the program.
.Sh RETURN VALUE
.Sy sm_malloc, sm_zalloc, sm_calloc
return a pointer to newly created object on success. The data it poins to can be used only up to
.Fa n
argument passed to them (or
.Fa y * x
in case of
.Sy sm_calloc )
If
.Fa n
is 0, these functions return a pointer to newly created object
.Em which content should be never accessed .
.
They return
.Em NULL
on failure to allocate memory and set
.Va errno
to
.Em ENOMEM .
.Sy sm_realloc
returns a pointer to object which size was adjusted.
.Em The object address may differ from passed in address .
If
.Fa p
is
.Em NULL ,
then the call is equivalent to
.Fn "sm_malloc" "n" .
If
.Fa p
is a pointer to existing object and
.Fa n
is 0, then the call is equivalent to
.Fn "sm_free" "p" .
On failure to relocate or size change, it will return
.Em NULL
and set
.Va errno
to
.Em ENOMEM .
.Sy sm_realloc_move
works exactly as
.Sy sm_realloc ,
but fails if physical reallocation (move) of the object is required. In such case,
.Em NULL
is returned and
.Va errno
is set to
.Em ERANGE .
Original object of question is not touched, it's size is not changed and it can be used as before.
.Sy sm_free
does not return a value, but may change
.Va errno
in cases described in
.Sx NOTES
section.
.Sy sm_szalloc
return an exact object size of object pointed to by
.Fa p
(the argument
.Fa n
passed to any of:
.Sy sm_malloc, sm_zalloc, sm_realloc, sm_realloc_move
and
.Fa y * x
result of
.Sy sm_calloc )
.
.Em This is the only permitted area that the caller may use.
For
.Em NULL
as argument,
.Sy sm_szalloc
returns 0.
For unique object of 0 size created with
.Fn "sm_malloc" "0"
(or equivalent), the return value is 1,
.Em but this may be changed in future .
.Sy sm_alloc_valid
returns 1 if object pointed to by
.Fa p
is valid reference, 0 otherwise. It does not permit to differentiate between multiple pools.
.Sy sm_malloc_stats
return 1 when the pool contains at least one object, thus numbers stored are not zeroes, 0 if no objects are in pool or
.Em all arguments are NULLs ,
or -1 on any other error described in
.Sx NOTES
section.
.Sy sm_set_default_pool
returns 1 on success (pool was registered), 0 if pool is very small to use. In this situation, an
.Va errno
will be also set to
.Em ENOSPC .
.Sy sm_release_default_pool
returns 1 on success (an existing pool was successfully deregistered), 0 otherwise, with
.Va errno
set to
.Em EINVAL .
.Sy sm_set_ub_handler
always succeeds and does not return any value.
.Sh NOTES
If pool was never registered, or recently was deregistered with
.Sy sm_release_default_pool ,
then all memory management functions will fail by returning their error values:
.Em NULL
or
.Em 0
or
.Em -1
or
.Em (size_t)-1 ,
or
.Em (void)
and
.Va errno
will be set to
.Em EINVAL .
All functions working on existing objects which take pointers to them, except
.Sy sm_alloc_valid ,
will check the pointer to be a valid reference to existing object belonging to registered pool.
If an invalid pointer is catched, then
.Nm
calls an
.Em undefined behavior
handler. The default
.Nm
embedded UB handler is set to crash the program to bring programmer's attention as early as possible. This handler can be overriden with
.Sy sm_set_ub_handler
for a lifetime of program until next call to this function.
.Sy sm_alloc_valid
does not call UB handler in case of invalid pointer reference: it was specially designed to answer the question:
.Dq Is this pointer a valid object reference?
One can implement a classic but more precise malloc on top of
.Nm
by using
.Xr brk 2
as a custom heap and extending it on each OOM handler call.
.Sh ERROR HANDLERS
.Sy smalloc_oom_handler
Out Of Memory handler is defined as follows:
.Bd -literal -offset 8n
typedef size_t (*smalloc_oom_handler)(struct smalloc_pool *, size_t);
size_t oom_handler(struct smalloc_pool *spool, size_t failed_alloc_req);
.Ed
It takes a pool descriptor
.Fa *spool
(see
.Sx MULTIPLE POOLS
section)
and
.Fa failed_alloc_req ,
which is size of object that failed to be created (the
.Fa n
argument to allocation functions).
The task of OOM handler is either to report an abnormal condition, possibly (and often) with program abortion or other way to exit, or to extend the pool, if possible (if pool is static, but resizeable).
In case of refuse to extend, but without abortion, the handler must return 0. Otherwise handler must return a
.Em new size of pool after successful extension .
.Em IMPORTANT! The pool CANNOT BE RELOCATED IF IT CONTAINS ALLOCATED OBJECTS
with functions such as
.Xr realloc 3 .
Relocation of pool will lead to bad references to the objects stored inside pointers across your program! You must ensure that pool will never be relocated once used when resizing the pool.
Returning a size lesser than current pool size will not lead to extension of pool, the effect will be the same as if handler would return 0. Returned size may or may not be not aligned: the function will align the new size automatically.
.Sy smalloc_ub_handler
Undefined Behavior handler is defined as follows:
.Bd -literal -offset 8n
typedef void (*smalloc_ub_handler)(struct smalloc_pool *, const void *);
void ub_handler(struct smalloc_pool *spool, const void *offender);
.Ed
It takes a pool descriptor
.Fa *spool
(see
.Sx MULTIPLE POOLS
section)
and
.Fa *offender
pointer which is an exact pointer value that caused an UB exception.
The task of UB handler is to report the condition as fast as possible and abort the program. An UB handler can
.Em ignore
abnormal condition, but it is highly discouraged.
Default UB handler embedded into
.Nm
itself is to cause program crash by writing to NULL pointer. It does not report condition somewhere just not to depend on libc's stdio package (or something other, possibly platform specific).
.Sh MULTIPLE POOLS
.Nm
supports using multiple pools in parallel (but not in multithreaded environment however). There are versions of described functions above which names end with
.Sq _pool
suffix and have prepended their first argument as
.Fa "struct smalloc_pool *" ,
which is a pool descriptor of this format:
.Bd -literal -offset 8n
struct smalloc_pool {
void *pool;
size_t pool_size;
int do_zero;
smalloc_oom_handler oomfn;
};
.Ed
Manual fill of the structure is
.Em NOT RECOMMENDED ,
it is best to use a pool aware
.Sy sm_set_pool
function, which is just the
.Sy sm_set_default_pool
variant with
.Fa "struct smalloc_pool *"
as it's first argument.
Releasing such a pool is done with
.Sy sm_release_pool ,
which takes
.Fa "struct smalloc_pool *"
as it's only single argument.
Memory behind these descriptors is not allocated by
.Nm ,
it is task of the caller to store pool descriptors somewhere.
Then caller may turn normal functions into pool versions, for example:
.Fn "sm_realloc" "void *p" "size_t n"
turns into
.Fn "sm_realloc_pool" "struct smalloc_pool *spool" "void *p" "size_t n" ,
and so on.
There is a
.Sy sm_align_pool
function, which takes a pool descriptor and adjusts it's
.Va pool_size
member to a value best fit for a
.Nm .
This function is provided only for manual fill of the pool descriptor.
.Em Unaligned pool descriptors will be rejected
by
.Nm
and
.Va errno
will be set to
.Em EINVAL
in such cases.
.Sy smalloc_curr_pool
symbol points to global pool descriptor which is used by
.Sy sm_set_default_pool
and
.Sy sm_release_default_pool ,
as well as by
.Sq non-pool
functions.
.Sh FILES
See
.Pa smalloc.h ,
.Pa smalloc_test_so.c ,
and source code.
.Sh EXAMPLE
This is the minimal example of how to use the library:
.Bd -literal -offset 8n
#include <smalloc.h>
static char my_pool[16384];
int main(void)
{
char *s, *d;
size_t n;
if (!sm_set_default_pool(my_pool, sizeof(my_pool), 0, NULL)) return 1;
s = sm_malloc(40);
if (s) {
n = sm_szalloc(s);
memset(s, 'X', n);
}
d = sm_malloc(700);
if (d) memset(d, 'Y', sm_szalloc(d));
s = sm_realloc(s, n+30);
if (s) memset(s+n, 'x', sm_szalloc(s)-n);
d = sm_realloc(d, 14000);
if (d) memset(d, 'y', sm_szalloc(d));
sm_free(s);
sm_free(d);
sm_release_default_pool();
return 0;
}
.Ed
.Sh BUGS
Returned objects may or may not be aligned to be used for any kind of variable. However it places objects exactly so at least integers and pointers can be placed and used without harm within them.
Allocations lesser than 12 bytes on 32 bit systems (typ.) are not so efficient: the object header takes 12 bytes and minimum overhead size is also 12 bytes. So per each, for example, 4 byte request there will be a 20 byte of overhead. On 64 bit systems it's even worse, things usually double.
True multithreading with locking was not implemented and is not currently a planned task.
Unlike highly promoted Linux's behavior about always succeeding
.Sy malloc ,
the memory in
.Nm
is managed directly by programmer.
.Sh CONFORMING TO
.Sy sm_malloc, sm_calloc, sm_realloc
and
.Sy sm_free
are fully compatible with usual
.Sy malloc, calloc, realloc
and
.Sy free .
Their behavior on normal/failed situations is same (or should be same - report a bug if not).
Programmer should not bother about UB because good program does not invoke UB.
.Sy sm_zalloc, sm_szalloc, sm_realloc_move
and
.Sy sm_alloc_valid
are
.Nm
extensions. They're not implemented in other malloc type packages, thus their usage is not portable.
.Sh AUTHORS
.Nm
was written in spare time by
.An Andrey Rys Aq Mt [email protected]
This library is available at
.Lk https://github.com/electrorys/smalloc/ .
The code, unlike any other programs written by Rys is MIT licensed:
.Em Copyright (c) 2017 Andrey Rys <[email protected]> .
See
.Em COPYRIGHT
file in the source distribution for complete terms.
.Sh SEE ALSO
.Xr malloc 3 ,
.Xr calloc 3 ,
.Xr free 3 ,
.Xr realloc 3 .