]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * duk_hbuffer allocation and freeing. | |
3 | */ | |
4 | ||
5 | #include "duk_internal.h" | |
6 | ||
7 | /* Allocate a new duk_hbuffer of a certain type and return a pointer to it | |
8 | * (NULL on error). Write buffer data pointer to 'out_bufdata' (only if | |
9 | * allocation successful). | |
10 | */ | |
11 | DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) { | |
12 | duk_hbuffer *res = NULL; | |
13 | duk_size_t header_size; | |
14 | duk_size_t alloc_size; | |
15 | ||
16 | DUK_ASSERT(heap != NULL); | |
17 | DUK_ASSERT(out_bufdata != NULL); | |
18 | ||
19 | DUK_DDD(DUK_DDDPRINT("allocate hbuffer")); | |
20 | ||
21 | /* Size sanity check. Should not be necessary because caller is | |
22 | * required to check this, but we don't want to cause a segfault | |
23 | * if the size wraps either in duk_size_t computation or when | |
24 | * storing the size in a 16-bit field. | |
25 | */ | |
26 | if (size > DUK_HBUFFER_MAX_BYTELEN) { | |
27 | DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size)); | |
28 | return NULL; /* no need to write 'out_bufdata' */ | |
29 | } | |
30 | ||
31 | if (flags & DUK_BUF_FLAG_EXTERNAL) { | |
32 | header_size = sizeof(duk_hbuffer_external); | |
33 | alloc_size = sizeof(duk_hbuffer_external); | |
11fdf7f2 | 34 | } else if (flags & DUK_BUF_FLAG_DYNAMIC) { |
7c673cae FG |
35 | header_size = sizeof(duk_hbuffer_dynamic); |
36 | alloc_size = sizeof(duk_hbuffer_dynamic); | |
37 | } else { | |
38 | header_size = sizeof(duk_hbuffer_fixed); | |
39 | alloc_size = sizeof(duk_hbuffer_fixed) + size; | |
40 | DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */ | |
41 | } | |
42 | ||
43 | res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size); | |
44 | if (!res) { | |
45 | goto error; | |
46 | } | |
47 | ||
48 | /* zero everything unless requested not to do so */ | |
49 | #if defined(DUK_USE_ZERO_BUFFER_DATA) | |
50 | DUK_MEMZERO((void *) res, | |
51 | (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size); | |
52 | #else | |
53 | DUK_MEMZERO((void *) res, header_size); | |
54 | #endif | |
55 | ||
56 | if (flags & DUK_BUF_FLAG_EXTERNAL) { | |
57 | duk_hbuffer_external *h; | |
58 | h = (duk_hbuffer_external *) res; | |
59 | DUK_UNREF(h); | |
60 | *out_bufdata = NULL; | |
61 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) | |
62 | #if defined(DUK_USE_HEAPPTR16) | |
63 | /* the compressed pointer is zeroed which maps to NULL, so nothing to do. */ | |
64 | #else | |
65 | DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL); | |
66 | #endif | |
67 | #endif | |
68 | DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL); | |
69 | } else if (flags & DUK_BUF_FLAG_DYNAMIC) { | |
70 | duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res; | |
71 | void *ptr; | |
72 | ||
73 | if (size > 0) { | |
74 | DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */ | |
75 | DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer")); | |
76 | #ifdef DUK_USE_ZERO_BUFFER_DATA | |
77 | ptr = DUK_ALLOC_ZEROED(heap, size); | |
78 | #else | |
79 | ptr = DUK_ALLOC(heap, size); | |
80 | #endif | |
81 | if (!ptr) { | |
82 | /* Because size > 0, NULL check is correct */ | |
83 | goto error; | |
84 | } | |
85 | *out_bufdata = ptr; | |
86 | ||
87 | DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr); | |
88 | } else { | |
89 | *out_bufdata = NULL; | |
90 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) | |
91 | #if defined(DUK_USE_HEAPPTR16) | |
92 | /* the compressed pointer is zeroed which maps to NULL, so nothing to do. */ | |
93 | #else | |
94 | DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL); | |
95 | #endif | |
96 | #endif | |
97 | DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL); | |
98 | } | |
99 | } else { | |
100 | *out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1); | |
101 | } | |
102 | ||
103 | DUK_HBUFFER_SET_SIZE(res, size); | |
104 | ||
105 | DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER); | |
106 | if (flags & DUK_BUF_FLAG_DYNAMIC) { | |
107 | DUK_HBUFFER_SET_DYNAMIC(res); | |
108 | if (flags & DUK_BUF_FLAG_EXTERNAL) { | |
109 | DUK_HBUFFER_SET_EXTERNAL(res); | |
110 | } | |
111 | } else { | |
112 | DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); | |
113 | } | |
114 | DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr); | |
115 | ||
116 | DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res)); | |
117 | return res; | |
118 | ||
119 | error: | |
120 | DUK_DD(DUK_DDPRINT("hbuffer allocation failed")); | |
121 | ||
122 | DUK_FREE(heap, res); | |
123 | return NULL; /* no need to write 'out_bufdata' */ | |
124 | } | |
125 | ||
126 | /* For indirect allocs. */ | |
127 | ||
128 | DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) { | |
129 | duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud; | |
130 | DUK_UNREF(heap); | |
131 | return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf); | |
132 | } |