Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / ep / ep_mem.c @ master

History | View | Annotate | Download (9.27 KB)

1 a901db09 Eric Allman
/* vim: set ai sw=8 sts=8 ts=8 :*/
2 0c663d10 Eric Allman
3 055d3009 Eric Allman
/***********************************************************************
4
**  ----- BEGIN LICENSE BLOCK -----
5
**        LIBEP: Enhanced Portability Library (Reduced Edition)
6
**
7 c87dd166 Eric Allman
**        Copyright (c) 2008-2019, Eric P. Allman.  All rights reserved.
8
**        Copyright (c) 2015-2019, Regents of the University of California.
9 6bd5476b Eric Allman
**        All rights reserved.
10 055d3009 Eric Allman
**
11 6bd5476b Eric Allman
**        Permission is hereby granted, without written agreement and without
12
**        license or royalty fees, to use, copy, modify, and distribute this
13
**        software and its documentation for any purpose, provided that the above
14
**        copyright notice and the following two paragraphs appear in all copies
15
**        of this software.
16 055d3009 Eric Allman
**
17 6bd5476b Eric Allman
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
18
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
19
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
20
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 055d3009 Eric Allman
**
22 6bd5476b Eric Allman
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
23 055d3009 Eric Allman
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 6bd5476b Eric Allman
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
25
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
26
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
27
**        OR MODIFICATIONS.
28 055d3009 Eric Allman
**  ----- END LICENSE BLOCK -----
29
***********************************************************************/
30
31 47c6ea64 Eric Allman
#include <ep.h>
32
#include <ep_mem.h>
33
#include <unistd.h>
34
#include <errno.h>
35
#include <string.h>
36
37
static struct ep_malloc_functions        DefaultMallocFunctions =
38
{
39
        &malloc,
40
        &realloc,
41
        &valloc,
42
        &free,
43
};
44
45
static struct ep_malloc_functions        *SystemMallocFunctions =
46
                                                &DefaultMallocFunctions;
47
48 1f3c460e Eric Allman
static void        (*MemoryRecoveryFunc)(void);
49
50 47c6ea64 Eric Allman
51
/*
52
**  EP_SET_MALLOC_FUNCTIONS --- set the malloc functions
53
**
54
*/
55
56
57
void
58 80662ee3 Eric Allman
ep_mem_set_malloc_functions(struct ep_malloc_functions *mf)
59 47c6ea64 Eric Allman
{
60
        SystemMallocFunctions = mf;
61
}
62
63
64 1f3c460e Eric Allman
/*
65
**  EP_MEM_SET_RECOVERY_FUNC --- set an "out of memory" recovery function
66
*/
67
68
void
69
ep_mem_set_recovery_func(void (*f)(void))
70
{
71
        MemoryRecoveryFunc = f;
72
}
73
74 47c6ea64 Eric Allman
75
/*
76
**  SYSTEM_MALLOC -- access system memory allocator
77
**
78
**        Parameters:
79
**                nbytes -- the number of bytes to allocate
80
**                curmem -- a current pointer (for realloc)
81
**                aligned -- set if we want page-aligned memory
82
**
83
**        Returns:
84 9e55d093 Eric Allman
**                A pointer to that memory; NULL if not available
85 47c6ea64 Eric Allman
*/
86
87
static void *
88
system_malloc(
89
        size_t nbytes,
90
        void *curmem,
91
        bool aligned)
92
{
93
        void *p;
94
95 9e55d093 Eric Allman
        if (curmem != NULL)
96 47c6ea64 Eric Allman
                p = (SystemMallocFunctions->m_realloc)(curmem, nbytes);
97
#ifdef EP_OSCF_SYSTEM_VALLOC
98
        else if (aligned)
99
                p = (SystemMallocFunctions->m_valloc)(nbytes);
100
#endif
101
        else
102
                p = (SystemMallocFunctions->m_malloc)(nbytes);
103
        return p;
104
}
105
106
107
/*
108
**  SYSTEM_MFREE -- access system memory deallocator
109
**
110
**        Parameters:
111
**                p -- the memory to free
112
**
113
**        Returns:
114
**                none.
115
*/
116
117
static void
118
system_mfree(void *p)
119
{
120
        // we assume system deallocator does its own mutex
121
        (*SystemMallocFunctions->m_free)(p);
122
}
123
124
125
/*
126 eacd6759 Eric Allman
**  MCHECK_INIT -- initialize memory subsystem
127
**
128
**        Only needed for debugging.
129
**        Unfortunately, mcheck initialization always seems to fail,
130
**        so we don't bother to compile this in.
131
*/
132
133
#undef EP_OSCF_HAS_MCHECK
134
#if EP_OSCF_HAS_MCHECK
135
# include <mcheck.h>
136
# include <ep_assert.h>
137
138
static void EP_ATTR_NORETURN
139
mem_abort(enum mcheck_status mstatus)
140
{
141
        const char *msg;
142
143
        switch (mstatus)
144
        {
145
          case MCHECK_OK:
146
                msg = "memory OK";
147
                break;
148
          case MCHECK_DISABLED:
149
                msg = "mcheck disabled";
150
                break;
151
          case MCHECK_HEAD:
152
                msg = "memory clobbered before block";
153
                break;
154
          case MCHECK_TAIL:
155
                msg = "memory clobbered after block";
156
                break;
157
          case MCHECK_FREE:
158
                msg = "double free";
159
                break;
160
          default:
161
                msg = NULL;
162
                break;
163
        }
164
        if (msg == NULL)
165
                EP_ASSERT_FAILURE("mcheck: bogus status %d", mstatus);
166
        else
167
                EP_ASSERT_FAILURE("mcheck error: %s", msg);
168
}
169
170
static void __attribute__((constructor))
171
mcheck_init(void)
172
{
173
        bool enable_debugging = false;
174
        static bool initialized = false;
175
        if (initialized)
176
                return;
177
        int i = 0;
178
        const char *m = getenv("EP_USE_MCHECK");
179
        if (m != NULL)
180
                enable_debugging = true;
181
        if (m != NULL && strcmp(m, "pedantic") == 0)
182
                i = mcheck_pedantic(mem_abort);
183
        else if (enable_debugging)
184
                i = mcheck(mem_abort);
185
        if (i != 0)
186
                fprintf(stderr, "Warning: mcheck initialization failed\n");
187
        initialized = true;
188
}
189
#endif // EP_OSCF_HAS_MCHECK
190
191
192
/*
193 47c6ea64 Eric Allman
**  EP_MEM_IALLOC -- allocate memory from the heap (internal)
194
**
195
**        This is the routine that does all the real work.
196
**
197
**        This always succeeds, unless the EP_MEM_F_FAILOK flag bit
198
**        is set.  If memory cannot be allocated, it posts an error
199
**        condition.  The condition handler has four choices:
200
**        it can do some memory cleanup and return
201
**        EP_STAT_MEM_TRYAGAIN to retry the allocation.  It can
202
**        clean up and abort the thread (i.e., not return) -- for
203
**        example, by dropping the current connection and releasing
204
**        any memory associated with it, presumably also terminating
205
**        the associated task.  Or it can return another status to
206
**        cause us to abort the process.
207
**
208
**        Parameters:
209
**                nbytes -- how much memory to allocate
210
**                curmem -- a current memory pointer (for realloc)
211
**                flags -- flags to modify operation
212
**                file -- file name of caller (for debugging)
213
**                line -- line number of caller (for debugging)
214
**
215
**        Returns:
216
**                the memory
217
*/
218
219
void *
220
ep_mem_ialloc(
221
        size_t nbytes,
222
        void *curmem,
223
        uint32_t flags,
224
        const char *file,
225
        int line)
226
{
227
        void *p;
228
229
        // always require at least one pointer worth of data
230
        if (nbytes < sizeof (void *))
231
                nbytes = sizeof (void *);
232
233
        // see if this request wants page alignment
234
//        if ((nbytes & (EP_OSCF_MEM_PAGESIZE - 1)) == 0)
235
//                flags |= EP_MEM_F_ALIGN;
236
237
        // get the memory itself
238 b70995e7 Eric Allman
        p = system_malloc(nbytes, curmem, EP_UT_BITSET(EP_MEM_F_ALIGN, flags));
239 47c6ea64 Eric Allman
240 9e55d093 Eric Allman
        if (p == NULL)
241 47c6ea64 Eric Allman
        {
242
                char e1buf[80];
243
244
                if (EP_UT_BITSET(EP_MEM_F_FAILOK, flags))
245
                        goto done;
246
247 1f3c460e Eric Allman
                // attempt recovery
248
                if (MemoryRecoveryFunc != NULL)
249
                {
250
                        (*MemoryRecoveryFunc)();
251
                        p = system_malloc(nbytes, curmem,
252
                                        EP_UT_BITSET(EP_MEM_F_ALIGN, flags));
253
                }
254
255
                if (p == NULL)
256
                {
257
                        // no luck ...  bail out
258 bfecf573 Eric Allman
                        (void) (0 == strerror_r(errno, e1buf, sizeof e1buf));
259 8d7fc458 Eric Allman
                        ep_assert_failure(file, line,
260 1f3c460e Eric Allman
                                        "Out of memory: %s", e1buf);
261
                        /*NOTREACHED*/
262
                }
263 47c6ea64 Eric Allman
        }
264
265
        // zero or trash memory if requested
266
        if ( EP_UT_BITSET(EP_MEM_F_ZERO, flags))
267
                memset(p, 0, nbytes);
268
        else if (EP_UT_BITSET(EP_MEM_F_TRASH, flags))
269
                ep_mem_trash(p, nbytes);
270
271
        // return pointer to allocated memory
272
done:
273
        return p;
274
}
275
276
277
278
279
/*
280
**  EP_MEM_[MZR]ALLOC_F -- malloc to plug into function pointer
281
**
282
**        Used for other libraries that require a pointer to a routine
283
**        taking one size argument.  Essentially this is plain old malloc.
284
*/
285
286
void *
287
ep_mem_malloc_f(size_t nbytes)
288
{
289 9e55d093 Eric Allman
        return ep_mem_ialloc(nbytes, NULL, 0, NULL, 0);
290 47c6ea64 Eric Allman
}
291
292
void *
293
ep_mem_zalloc_f(size_t nbytes)
294
{
295 9e55d093 Eric Allman
        return ep_mem_ialloc(nbytes, NULL, EP_MEM_F_ZERO, NULL, 0);
296 47c6ea64 Eric Allman
}
297
298
void *
299
ep_mem_ralloc_f(size_t nbytes)
300
{
301 9e55d093 Eric Allman
        return ep_mem_ialloc(nbytes, NULL, EP_MEM_F_TRASH, NULL, 0);
302 47c6ea64 Eric Allman
}
303
304
void *
305
ep_mem_realloc_f(size_t nbytes,
306
        void *curmem)
307
{
308 9e55d093 Eric Allman
        return ep_mem_ialloc(nbytes, curmem, 0, NULL, 0);
309 47c6ea64 Eric Allman
}
310
311 5b07c525 Eric Allman
void *
312
ep_mem_zrealloc_f(size_t nbytes,
313
        void *curmem)
314
{
315
        return ep_mem_ialloc(nbytes, curmem, EP_MEM_F_ZERO, NULL, 0);
316
}
317
318 47c6ea64 Eric Allman
319
/*
320
**  EP_MEM_[MZR]ALLOC -- same thing, but just in the non-debugging case
321
*/
322
323
#undef ep_mem_malloc
324
325
void *
326
ep_mem_malloc(size_t nbytes)
327
{
328 9e55d093 Eric Allman
        return ep_mem_ialloc(nbytes, NULL, 0, NULL, 0);
329 47c6ea64 Eric Allman
}
330
331
#undef ep_mem_zalloc
332
333
void *
334
ep_mem_zalloc(size_t nbytes)
335
{
336
        void *p;
337
338 9e55d093 Eric Allman
        p = ep_mem_ialloc(nbytes, NULL, EP_MEM_F_ZERO, NULL, 0);
339 47c6ea64 Eric Allman
        return p;
340
}
341
342
#undef ep_mem_ralloc
343
344
void *
345
ep_mem_ralloc(size_t nbytes)
346
{
347
        void *p;
348
349 9e55d093 Eric Allman
        p = ep_mem_ialloc(nbytes, NULL, EP_MEM_F_TRASH, NULL, 0);
350 47c6ea64 Eric Allman
        return p;
351
}
352
353
#undef ep_mem_realloc
354
355
void *
356
ep_mem_realloc(
357
        void *curmem,
358
        size_t nbytes)
359
{
360 9e55d093 Eric Allman
        return ep_mem_ialloc(nbytes, curmem, 0, NULL, 0);
361 47c6ea64 Eric Allman
}
362
363 5b07c525 Eric Allman
#undef ep_mem_zrealloc
364
365
void *
366
ep_mem_zrealloc(
367
        void *curmem,
368
        size_t nbytes)
369
{
370
        return ep_mem_ialloc(nbytes, curmem, EP_MEM_F_ZERO, NULL, 0);
371
}
372
373 47c6ea64 Eric Allman
374
/*
375
**  EP_MEM_TSTRDUP -- save a string onto a heap (tagged)
376
**
377
**        paramters:
378
**                s -- the string to duplicate
379
**                slen -- the maximum length of s to copy -- -1 => all
380
**                flags -- as usual
381
**                grp -- an arbitrary group number (for debugging)
382
**                file -- the file name (for debugging)
383
**                line -- the line number (for debugging)
384
*/
385
386
char *
387
ep_mem_istrdup(
388
        const char *s,
389 80662ee3 Eric Allman
        ssize_t slen,
390 47c6ea64 Eric Allman
        uint32_t flags,
391
        const char *file,
392
        int line)
393
{
394 80662ee3 Eric Allman
        ssize_t l;
395 47c6ea64 Eric Allman
        char *p;
396
397 9e55d093 Eric Allman
        if (s == NULL)
398
                return NULL;
399 47c6ea64 Eric Allman
        l = strlen(s);
400
        if (slen >= 0 && l > slen)
401
                l = slen;
402 2a8cda22 Eric Allman
        EP_ASSERT(l + 1 > l);
403 fc0cbc23 Eric Allman
        p = (char *) ep_mem_ialloc(l + 1, NULL, flags, file, line);
404 9e55d093 Eric Allman
        if (p != NULL)
405 47c6ea64 Eric Allman
        {
406
                memcpy(p, s, l);
407
                p[l] = '\0';
408
        }
409
        return p;
410
}
411
412
/*
413
**  EP_MEM_STRDUP -- only used if memory debugging is not compiled in
414
*/
415
416
#undef ep_mem_strdup
417
418
char *
419
ep_mem_strdup(const char *s)
420
{
421 9e55d093 Eric Allman
        return ep_mem_istrdup(s, -1, 0, NULL, 0);
422 47c6ea64 Eric Allman
}
423
424
/*
425
**  EP_MEM_TRASH -- set memory to random values
426
**
427
**        No gurantees here: the memory might be set to pseudo-random
428
**        bytes, it might be set to 0xDEADBEEF, or might be untouched.
429
**        If you require specific semantics, take care of it yourself.
430
**
431
**        Parameters:
432
**                p -- pointer to the memory
433
**                nbytes -- size of memory
434
**
435
**        Returns:
436
**                nothing
437
*/
438
439
void
440
ep_mem_trash(void *p,
441
        size_t nbytes)
442
{
443 1f3c460e Eric Allman
        if (nbytes > 0)
444
                memset(p, 0xA5, nbytes);
445 47c6ea64 Eric Allman
}
446
447
448
449
/*
450
**  EP_MEM_FREE -- free allocated memory
451
**
452
**        Parameters:
453
**                p -- the memory to free
454
**
455
**        Returns:
456
**                void
457
*/
458
459
void
460
ep_mem_free(void *p)
461
{
462
        system_mfree(p);
463
}