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
|
/*
* duk_hbuffer allocation and freeing.
*/
#include "duk_internal.h"
/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
* (NULL on error). Write buffer data pointer to 'out_bufdata' (only if
* allocation successful).
*/
DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
duk_hbuffer *res = NULL;
duk_size_t header_size;
duk_size_t alloc_size;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(out_bufdata != NULL);
DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));
/* Size sanity check. Should not be necessary because caller is
* required to check this, but we don't want to cause a segfault
* if the size wraps either in duk_size_t computation or when
* storing the size in a 16-bit field.
*/
if (size > DUK_HBUFFER_MAX_BYTELEN) {
DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
return NULL; /* no need to write 'out_bufdata' */
}
if (flags & DUK_BUF_FLAG_EXTERNAL) {
header_size = sizeof(duk_hbuffer_external);
alloc_size = sizeof(duk_hbuffer_external);
} else if (flags & DUK_BUF_FLAG_DYNAMIC) {
header_size = sizeof(duk_hbuffer_dynamic);
alloc_size = sizeof(duk_hbuffer_dynamic);
} else {
header_size = sizeof(duk_hbuffer_fixed);
alloc_size = sizeof(duk_hbuffer_fixed) + size;
DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */
}
res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
if (DUK_UNLIKELY(res == NULL)) {
goto alloc_error;
}
/* zero everything unless requested not to do so */
#if defined(DUK_USE_ZERO_BUFFER_DATA)
duk_memzero((void *) res, (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
#else
duk_memzero((void *) res, header_size);
#endif
if (flags & DUK_BUF_FLAG_EXTERNAL) {
duk_hbuffer_external *h;
h = (duk_hbuffer_external *) res;
DUK_UNREF(h);
*out_bufdata = NULL;
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
#if defined(DUK_USE_HEAPPTR16)
/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
#else
DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
#endif
#endif
DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
} else if (flags & DUK_BUF_FLAG_DYNAMIC) {
duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
void *ptr;
if (size > 0) {
DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */
DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
#if defined(DUK_USE_ZERO_BUFFER_DATA)
ptr = DUK_ALLOC_ZEROED(heap, size);
#else
ptr = DUK_ALLOC(heap, size);
#endif
if (DUK_UNLIKELY(ptr == NULL)) {
/* Because size > 0, NULL check is correct */
goto alloc_error;
}
*out_bufdata = ptr;
DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
} else {
*out_bufdata = NULL;
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
#if defined(DUK_USE_HEAPPTR16)
/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
#else
DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
#endif
#endif
DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
}
} else {
*out_bufdata = (void *) ((duk_hbuffer_fixed *) (void *) res + 1);
}
DUK_HBUFFER_SET_SIZE(res, size);
DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
if (flags & DUK_BUF_FLAG_DYNAMIC) {
DUK_HBUFFER_SET_DYNAMIC(res);
if (flags & DUK_BUF_FLAG_EXTERNAL) {
DUK_HBUFFER_SET_EXTERNAL(res);
}
} else {
DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
}
DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
return res;
alloc_error:
DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
DUK_FREE(heap, res);
return NULL; /* no need to write 'out_bufdata' */
}
/* For indirect allocs. */
DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud;
DUK_UNREF(heap);
return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
}
|