Browse Source

Further cleanup for memory helpers

* Convert memory helpers like duk_memcmp() to macros where possible: for some
  reason automatic inlining with -Os doesn't do the right thing and the
  footprint impact is over 1kB.  The duk_memcmp() helper is an inlined
  function because it returns a value and assertions would otherwise lead
  to multiple evaluation of arguments.

* Differentiate between C99+ and "unsafe" call sites.  For example, use
  duk_memcpy() when the call site obeys C99+ restrictions, and
  duk_memcpy_unsafe() when either pointer may be NULL when the size is zero.
  Same for all helpers.
pull/1798/head
Sami Vaarala 7 years ago
parent
commit
fea88e64fd
  1. 9
      src-input/duk_api_bytecode.c
  2. 12
      src-input/duk_api_stack.c
  3. 46
      src-input/duk_bi_buffer.c
  4. 6
      src-input/duk_bi_string.c
  5. 3
      src-input/duk_bi_symbol.c
  6. 2
      src-input/duk_debug_fixedbuffer.c
  7. 1
      src-input/duk_debug_vsnprintf.c
  8. 1
      src-input/duk_debugger.c
  9. 2
      src-input/duk_error.h
  10. 3
      src-input/duk_hbufobj.h
  11. 1
      src-input/duk_heap_memory.c
  12. 5
      src-input/duk_heap_stringtable.c
  13. 6
      src-input/duk_hobject_props.c
  14. 8
      src-input/duk_js_ops.c
  15. 1
      src-input/duk_numconv.c
  16. 149
      src-input/duk_util.h
  17. 47
      src-input/duk_util_bufwriter.c
  18. 71
      src-input/duk_util_memory.c

9
src-input/duk_api_bytecode.c

@ -74,9 +74,10 @@ DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, d
DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */
tmp32 = (duk_uint32_t) len;
DUK_RAW_WRITE_U32_BE(p, tmp32);
duk_memcpy((void *) p,
(const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
len);
/* When len == 0, buffer data pointer may be NULL. */
duk_memcpy_unsafe((void *) p,
(const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
len);
p += len;
return p;
}
@ -288,7 +289,7 @@ static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bu
ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func);
DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
#if defined(DUK_USE_INTEGER_BE)
duk_memcpy((void *) p, (const void *) ins, (size_t) (ins_end - ins));
duk_memcpy_unsafe((void *) p, (const void *) ins, (size_t) (ins_end - ins));
p += (size_t) (ins_end - ins);
#else
while (ins != ins_end) {

12
src-input/duk_api_stack.c

@ -1392,8 +1392,8 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr,
DUK_WO_NORETURN(return;);
}
/* copy values (no overlap even if to_thr == from_thr; that's not
* allowed now anyway)
/* Copy values (no overlap even if to_thr == from_thr; that's not
* allowed now anyway).
*/
DUK_ASSERT(nbytes > 0);
duk_memcpy((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
@ -3417,7 +3417,8 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t
}
dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
duk_memcpy((void *) dst_data, (const void *) src_data, (size_t) src_size);
/* dst_data may be NULL if size is zero. */
duk_memcpy_unsafe((void *) dst_data, (const void *) src_data, (size_t) src_size);
duk_replace(thr, idx);
skip_copy:
@ -5293,6 +5294,7 @@ DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len)
DUK_ASSERT_API_ENTRY(thr);
ptr = duk_push_buffer_raw(thr, len, 0);
DUK_ASSERT(ptr != NULL);
#if !defined(DUK_USE_ZERO_BUFFER_DATA)
/* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
* is not set.
@ -5952,7 +5954,7 @@ DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) {
* any refcount updates: net refcount changes are zero.
*/
tv_src = thr->valstack_top - count - 1;
duk_memcpy((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
/* Overwrite result array to final value stack location and wipe
* the rest; no refcount operations needed.
@ -6614,7 +6616,7 @@ DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_
DUK_UNREF(thr);
DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */
duk_memcpy((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
tv = tv_dst;
while (count-- > 0) {

46
src-input/duk_bi_buffer.c

@ -443,6 +443,7 @@ DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_h
DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
DUK_ASSERT(elem_size > 0);
duk_memcpy((void *) du.uc, (const void *) p, (size_t) elem_size);
switch (h_bufobj->elem_type) {
@ -524,6 +525,7 @@ DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_b
DUK_UNREACHABLE();
}
DUK_ASSERT(elem_size > 0);
duk_memcpy((void *) p, (const void *) du.uc, (size_t) elem_size);
}
@ -953,7 +955,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
(void *) p_src, (void *) p_dst, (long) byte_length));
duk_memcpy((void *) p_dst, (const void *) p_src, (size_t) byte_length);
duk_memcpy_unsafe((void *) p_dst, (const void *) p_src, (size_t) byte_length);
break;
}
case 1: {
@ -1220,9 +1222,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) {
*/
DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length));
duk_memcpy((void *) buf_slice,
(const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
(size_t) slice_length);
duk_memcpy_unsafe((void *) buf_slice,
(const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
(size_t) slice_length);
/* Use the equivalent of: new TextEncoder().encode(this) to convert the
* string. Result will be valid UTF-8; non-CESU-8 inputs are currently
@ -1384,7 +1386,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) {
/* Handle single character fills as memset() even when
* the fill data comes from a one-char argument.
*/
duk_memset((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
duk_memset_unsafe((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
} else if (fill_str_len > 1) {
duk_size_t i, n, t;
@ -1435,9 +1437,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) {
if (DUK_HBUFOBJ_VALID_SLICE(h_this)) {
/* Cannot overlap. */
duk_memcpy((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
(const void *) str_data,
(size_t) length);
duk_memcpy_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
(const void *) str_data,
(size_t) length);
} else {
DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
}
@ -1533,9 +1535,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) {
/* Must use memmove() because copy area may overlap (source and target
* buffer may be the same, or from different slices.
*/
duk_memmove((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
(const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
(size_t) copy_size);
duk_memmove_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
(const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
(size_t) copy_size);
} else {
DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
}
@ -1721,7 +1723,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
DUK_ASSERT(src_length == dst_length);
DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible"));
duk_memmove((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
duk_memmove_unsafe((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
return 0;
}
DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
@ -1764,7 +1766,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length);
DUK_ASSERT(p_src_copy != NULL);
duk_memcpy((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
duk_memcpy_unsafe((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
p_src_base = p_src_copy; /* use p_src_base from now on */
}
@ -1891,9 +1893,9 @@ DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val
DUK_ASSERT(p_copy != NULL);
copy_length = slice_length;
duk_memcpy((void *) p_copy,
(const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
copy_length);
duk_memcpy_unsafe((void *) p_copy,
(const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
copy_length);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@ -2015,9 +2017,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) {
* is left as zero.
*/
copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length);
duk_memcpy((void *) p_copy,
(const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
copy_length);
duk_memcpy_unsafe((void *) p_copy,
(const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
copy_length);
h_val = duk_known_hbuffer(thr, -1);
@ -2209,9 +2211,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) {
if (h_bufobj->buf != NULL &&
DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
duk_memcpy((void *) p,
(const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
copy_size);
duk_memcpy_unsafe((void *) p,
(const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
copy_size);
} else {
/* Just skip, leaving zeroes in the result. */
;

6
src-input/duk_bi_string.c

@ -1378,12 +1378,14 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) {
/* Temporary fixed buffer, later converted to string. */
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len);
DUK_ASSERT(buf != NULL);
src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
DUK_ASSERT(src != NULL);
#if defined(DUK_USE_PREFER_SIZE)
p = buf;
while (count-- > 0) {
duk_memcpy((void *) p, (const void *) src, input_blen); /* copy size may be zero */
duk_memcpy((void *) p, (const void *) src, input_blen); /* copy size may be zero, but pointers are valid */
p += input_blen;
}
#else /* DUK_USE_PREFER_SIZE */
@ -1400,7 +1402,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) {
(long) result_len));
if (remain <= copy_size) {
/* If result_len is zero, this case is taken and does
* a zero size copy.
* a zero size copy (with valid pointers).
*/
duk_memcpy((void *) p, (const void *) src, remain);
break;

3
src-input/duk_bi_symbol.c

@ -37,9 +37,10 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) {
* +1 0xff after unique suffix for symbols with undefined description
*/
buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1);
DUK_ASSERT(buf != NULL);
p = buf + 1;
DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */
duk_memcpy((void *) p, (const void *) desc, len);
duk_memcpy_unsafe((void *) p, (const void *) desc, len);
p += len;
if (magic == 0) {
/* Symbol(): create unique symbol. Use two 32-bit values

2
src-input/duk_debug_fixedbuffer.c

@ -18,7 +18,7 @@ DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffe
} else {
copylen = length;
}
duk_memcpy(fb->buffer + fb->offset, buffer, copylen);
duk_memcpy_unsafe(fb->buffer + fb->offset, buffer, copylen);
fb->offset += copylen;
}

1
src-input/duk_debug_vsnprintf.c

@ -1019,6 +1019,7 @@ DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_u
duk_uint8_t *p = (duk_uint8_t *) buf;
duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1);
DUK_ASSERT(buf != NULL);
duk_memzero(buf, buf_size);
for (i = 0; i < fptr_size; i++) {

1
src-input/duk_debugger.c

@ -309,6 +309,7 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_
DUK_ASSERT(thr != NULL);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(data != NULL);
if (heap->dbg_read_cb == NULL) {
DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));

2
src-input/duk_error.h

@ -423,7 +423,7 @@
#if defined(DUK_USE_ASSERTIONS)
#define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \
duk_memset((void *) (ptr), 0x5a, size); \
duk_memset_unsafe((void *) (ptr), 0x5a, size); \
} while (0)
#else
#define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0)

3
src-input/duk_hbufobj.h

@ -47,7 +47,8 @@
} while (0)
/* Get the current data pointer (caller must ensure buf != NULL) as a
* duk_uint8_t ptr.
* duk_uint8_t ptr. Note that the result may be NULL if the underlying
* buffer has zero size and is not a fixed buffer.
*/
#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \

1
src-input/duk_heap_memory.c

@ -127,7 +127,6 @@ DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
res = DUK_ALLOC(heap, size);
if (DUK_LIKELY(res != NULL)) {
/* assume memset with zero size is OK */
duk_memzero(res, size);
}
return res;

5
src-input/duk_heap_stringtable.c

@ -690,7 +690,7 @@ DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_ui
while (curr != NULL) {
if (strhash == DUK_HSTRING_GET_HASH(curr) &&
blen == DUK_HSTRING_GET_BYTELEN(curr) &&
duk_memcmp((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) {
duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) {
DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr)));
return curr;
@ -710,6 +710,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin
/* Preliminaries. */
/* XXX: maybe just require 'str != NULL' even for zero size? */
DUK_ASSERT(heap != NULL);
DUK_ASSERT(blen == 0 || str != NULL);
DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */
@ -728,7 +729,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin
while (h != NULL) {
if (DUK_HSTRING_GET_HASH(h) == strhash &&
DUK_HSTRING_GET_BYTELEN(h) == blen &&
duk_memcmp((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
/* Found existing entry. */
DUK_STATS_INC(heap, stats_strtab_intern_hit);
return h;

6
src-input/duk_hobject_props.c

@ -811,9 +811,9 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
DUK_ASSERT(new_a != NULL || array_copy_size == 0U);
DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || array_copy_size == 0U);
DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0 || array_copy_size == 0U);
duk_memcpy((void *) new_a,
(const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj),
array_copy_size);
duk_memcpy_unsafe((void *) new_a,
(const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj),
array_copy_size);
for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
duk_tval *tv = &new_a[i];

8
src-input/duk_js_ops.c

@ -727,11 +727,11 @@ DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const
prefix_len = (len1 <= len2 ? len1 : len2);
/* duk_memcmp() is guaranteed to return zero (equal) for zero length
* inputs so no zero length check is needed.
* inputs.
*/
rc = duk_memcmp((const void *) buf1,
(const void *) buf2,
(size_t) prefix_len);
rc = duk_memcmp_unsafe((const void *) buf1,
(const void *) buf2,
(size_t) prefix_len);
if (rc < 0) {
return -1;

1
src-input/duk_numconv.c

@ -674,6 +674,7 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x
duk_small_int_t dig;
duk_uint32_t t;
DUK_ASSERT(buf != NULL);
DUK_ASSERT(radix >= 2 && radix <= 36);
/* A 32-bit unsigned integer formats to at most 32 digits (the

149
src-input/duk_util.h

@ -315,12 +315,13 @@ struct duk_bufwriter_ctx {
(bw_ctx)->p += duk__enc_len; \
} while (0)
/* XXX: add temporary duk__p pointer here too; sharing */
/* XXX: avoid unsafe variants */
#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
const void *duk__valptr; \
duk_size_t duk__valsz; \
duk__valptr = (const void *) (valptr); \
duk__valsz = (duk_size_t) (valsz); \
duk_memcpy((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
(bw_ctx)->p += duk__valsz; \
} while (0)
#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
@ -328,31 +329,31 @@ struct duk_bufwriter_ctx {
duk_size_t duk__val_len; \
duk__val = (const duk_uint8_t *) (val); \
duk__val_len = DUK_STRLEN((const char *) duk__val); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
@ -416,13 +417,14 @@ struct duk_bufwriter_ctx {
DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
} while (0)
/* XXX: add temporary duk__p pointer here too; sharing */
/* XXX: avoid unsafe */
#define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \
const void *duk__valptr; \
duk_size_t duk__valsz; \
duk__valptr = (const void *) (valptr); \
duk__valsz = (duk_size_t) (valsz); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
duk_memcpy((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
(bw_ctx)->p += duk__valsz; \
} while (0)
#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
@ -431,35 +433,35 @@ struct duk_bufwriter_ctx {
duk__val = (const duk_uint8_t *) (val); \
duk__val_len = DUK_STRLEN((const char *) duk__val); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
duk_memcpy((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
@ -542,11 +544,126 @@ DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val
DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
#endif
DUK_INTERNAL_DECL void duk_memcpy(void *dst, const void *src, duk_size_t len);
DUK_INTERNAL_DECL void duk_memmove(void *dst, const void *src, duk_size_t len);
/* memcpy(), memmove() etc wrappers. The plain variants like duk_memcpy()
* assume C99+ and 'src' and 'dst' pointers must be non-NULL even when the
* operation size is zero. The unsafe variants like duk_memcpy_safe() deal
* with the zero size case explicitly, and allow NULL pointers in that case
* (which is undefined behavior in C99+). For the majority of actual targets
* a NULL pointer with a zero length is fine in practice. These wrappers are
* macros to force inlining; because there are hundreds of call sites, even a
* few extra bytes per call site adds up to ~1kB footprint.
*/
#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
#define duk_memcpy(dst,src,len) do { \
void *duk__dst = (dst); \
const void *duk__src = (src); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
(void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
} while (0)
#define duk_memcpy_unsafe(dst,src,len) duk_memcpy((dst), (src), (len))
#define duk_memmove(dst,src,len) do { \
void *duk__dst = (dst); \
const void *duk__src = (src); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
(void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
} while (0)
#define duk_memmove_unsafe(dst,src,len) duk_memmove((dst), (src), (len))
#define duk_memset(dst,val,len) do { \
void *duk__dst = (dst); \
duk_small_int_t duk__val = (val); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
(void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
} while (0)
#define duk_memset_unsafe(dst,val,len) duk_memset((dst), (val), (len))
#define duk_memzero(dst,len) do { \
void *duk__dst = (dst); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
(void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
} while (0)
#define duk_memzero_unsafe(dst,len) duk_memzero((dst), (len))
#else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
#define duk_memcpy(dst,src,len) do { \
void *duk__dst = (dst); \
const void *duk__src = (src); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL); \
DUK_ASSERT(duk__src != NULL); \
(void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
} while (0)
#define duk_memcpy_unsafe(dst,src,len) do { \
void *duk__dst = (dst); \
const void *duk__src = (src); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
if (DUK_LIKELY(duk__len > 0U)) { \
DUK_ASSERT(duk__dst != NULL); \
DUK_ASSERT(duk__src != NULL); \
(void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
} \
} while (0)
#define duk_memmove(dst,src,len) do { \
void *duk__dst = (dst); \
const void *duk__src = (src); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL); \
DUK_ASSERT(duk__src != NULL); \
(void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
} while (0)
#define duk_memmove_unsafe(dst,src,len) do { \
void *duk__dst = (dst); \
const void *duk__src = (src); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
if (DUK_LIKELY(duk__len > 0U)) { \
DUK_ASSERT(duk__dst != NULL); \
DUK_ASSERT(duk__src != NULL); \
(void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
} \
} while (0)
#define duk_memset(dst,val,len) do { \
void *duk__dst = (dst); \
duk_small_int_t duk__val = (val); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL); \
(void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
} while (0)
#define duk_memset_unsafe(dst,val,len) do { \
void *duk__dst = (dst); \
duk_small_int_t duk__val = (val); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
if (DUK_LIKELY(duk__len > 0U)) { \
DUK_ASSERT(duk__dst != NULL); \
(void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
} \
} while (0)
#define duk_memzero(dst,len) do { \
void *duk__dst = (dst); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL); \
(void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
} while (0)
#define duk_memzero_unsafe(dst,len) do { \
void *duk__dst = (dst); \
duk_size_t duk__len = (len); \
DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
if (DUK_LIKELY(duk__len > 0U)) { \
DUK_ASSERT(duk__dst != NULL); \
(void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
} \
} while (0)
#endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
DUK_INTERNAL_DECL duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len);
DUK_INTERNAL_DECL void duk_memset(void *s, duk_small_int_t c, duk_size_t len);
DUK_INTERNAL_DECL void duk_memzero(void *s, duk_size_t len);
DUK_INTERNAL_DECL duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len);
DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival);
DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival);

47
src-input/duk_util_bufwriter.c

@ -4,6 +4,10 @@
#include "duk_internal.h"
/* XXX: Avoid duk_{memcmp,memmove}_unsafe() by imposing a minimum length of
* >0 for the underlying dynamic buffer.
*/
/*
* Macro support functions (use only macros in calling code)
*/
@ -15,6 +19,9 @@ DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx,
DUK_ASSERT(bw_ctx != NULL);
DUK_UNREF(thr);
/* 'p' might be NULL when the underlying buffer is zero size. If so,
* the resulting pointers are not used unsafely.
*/
p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf);
DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0));
bw_ctx->p = p + curr_offset;
@ -23,7 +30,6 @@ DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx,
}
DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(bw_ctx != NULL);
DUK_ASSERT(h_buf != NULL);
@ -38,6 +44,7 @@ DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ct
(void) duk_push_dynamic_buffer(thr, buf_size);
bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
DUK_ASSERT(bw_ctx->buf != NULL);
duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
}
@ -105,9 +112,9 @@ DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw
DUK_UNREF(thr);
p_base = bw->p_base;
duk_memcpy((void *) bw->p,
(const void *) (p_base + src_off),
(size_t) len);
duk_memcpy_unsafe((void *) bw->p,
(const void *) (p_base + src_off),
(size_t) len);
bw->p += len;
}
@ -137,12 +144,12 @@ DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *b
move_sz = buf_sz - dst_off;
DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
duk_memmove((void *) (p_base + dst_off + len),
(const void *) (p_base + dst_off),
(size_t) move_sz);
duk_memcpy((void *) (p_base + dst_off),
(const void *) buf,
(size_t) len);
duk_memmove_unsafe((void *) (p_base + dst_off + len),
(const void *) (p_base + dst_off),
(size_t) move_sz);
duk_memcpy_unsafe((void *) (p_base + dst_off),
(const void *) buf,
(size_t) len);
bw->p += len;
}
@ -184,12 +191,12 @@ DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b
move_sz = buf_sz - dst_off;
DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
duk_memmove((void *) (p_base + dst_off + len),
(const void *) (p_base + dst_off),
(size_t) move_sz);
duk_memcpy((void *) (p_base + dst_off),
(const void *) (p_base + src_off),
(size_t) len);
duk_memmove_unsafe((void *) (p_base + dst_off + len),
(const void *) (p_base + dst_off),
(size_t) move_sz);
duk_memcpy_unsafe((void *) (p_base + dst_off),
(const void *) (p_base + src_off),
(size_t) len);
bw->p += len;
}
@ -222,7 +229,7 @@ DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter
move_sz = buf_sz - off;
p_dst = p_base + off + len;
p_src = p_base + off;
duk_memmove((void *) p_dst, (const void *) p_src, (size_t) move_sz);
duk_memmove_unsafe((void *) p_dst, (const void *) p_src, (size_t) move_sz);
return p_src; /* point to start of 'reserved area' */
}
@ -253,9 +260,9 @@ DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b
p_dst = p_base + off;
p_src = p_dst + len;
move_sz = (duk_size_t) (bw->p - p_src);
duk_memmove((void *) p_dst,
(const void *) p_src,
(size_t) move_sz);
duk_memmove_unsafe((void *) p_dst,
(const void *) p_src,
(size_t) move_sz);
bw->p -= len;
}

71
src-input/duk_util_memory.c

@ -1,67 +1,36 @@
/*
* Memcpy() etc.
* Memory utils.
*/
#include "duk_internal.h"
DUK_INTERNAL void duk_memcpy(void *dst, const void *src, duk_size_t len) {
#if !defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
/* For portability reasons both 'src' and 'dst' must be valid and
* non-NULL even if len is zero. Check for that explicitly to avoid
* depending on platform specific behavior. For the vast majority of
* actual targets a NULL pointer with a zero length is fine.
*/
if (DUK_UNLIKELY(len == 0U)) {
return;
}
DUK_ASSERT(src != NULL);
DUK_ASSERT(dst != NULL);
#else
DUK_ASSERT(src != NULL || len == 0U);
DUK_ASSERT(dst != NULL || len == 0U);
#endif
(void) DUK_MEMCPY(dst, src, (size_t) len);
#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) {
DUK_ASSERT(s1 != NULL || len == 0U);
DUK_ASSERT(s2 != NULL || len == 0U);
return DUK_MEMCMP(s1, s2, (size_t) len);
}
DUK_INTERNAL void duk_memmove(void *dst, const void *src, duk_size_t len) {
#if !defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
if (DUK_UNLIKELY(len == 0U)) {
return;
}
DUK_ASSERT(src != NULL);
DUK_ASSERT(dst != NULL);
#else
DUK_ASSERT(src != NULL || len == 0U);
DUK_ASSERT(dst != NULL || len == 0U);
#endif
(void) DUK_MEMMOVE(dst, src, (size_t) len);
DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) {
DUK_ASSERT(s1 != NULL);
DUK_ASSERT(s2 != NULL);
return DUK_MEMCMP(s1, s2, (size_t) len);
}
DUK_INTERNAL duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) {
duk_small_int_t ret;
#if !defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
#else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) {
DUK_ASSERT(s1 != NULL || len == 0U);
DUK_ASSERT(s2 != NULL || len == 0U);
if (DUK_UNLIKELY(len == 0U)) {
return 0;
}
DUK_ASSERT(s1 != NULL);
DUK_ASSERT(s2 != NULL);
#else
DUK_ASSERT(s1 != NULL || len == 0U);
DUK_ASSERT(s2 != NULL || len == 0U);
#endif
ret = (duk_small_int_t) DUK_MEMCMP(s1, s2, (size_t) len);
DUK_ASSERT(ret == 0 || len > 0); /* If len == 0, must compare equal. */
return ret;
}
DUK_INTERNAL void duk_memset(void *s, duk_small_int_t c, duk_size_t len) {
(void) DUK_MEMSET(s, (int) c, (size_t) len);
return duk_memcmp(s1, s2, len);
}
DUK_INTERNAL void duk_memzero(void *s, duk_size_t len) {
(void) DUK_MEMZERO(s, (size_t) len);
DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) {
DUK_ASSERT(s1 != NULL);
DUK_ASSERT(s2 != NULL);
return DUK_MEMCMP(s1, s2, (size_t) len);
}
#endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */

Loading…
Cancel
Save