From bbf36d5b84460a4f39c93f1b81ea87f9a9f8f2fe Mon Sep 17 00:00:00 2001 From: Charlie Gordon Date: Sun, 18 Feb 2024 08:29:04 +0100 Subject: [PATCH] Fix big endian serialization Big endian serialization was broken because: - it partially relied on `WORDS_ENDIAN` (unconditionally undef'd in cutils.h) - endianness was not handled at all in the bc reader. Modifications: - remove `WORDS_ENDIAN` - use `bc_put_u32()` / `bc_put_u64()` in `JS_WriteBigInt()` - use `bc_get_u32()` / `bc_get_u64()` in `JS_ReadBigInt()` - handle host endianness in `bc_get_u16()`, `bc_get_u32()`, `bc_get_u64()` and `JS_ReadFunctionBytecode()` - handle optional littleEndian argument as specified in `js_dataview_getValue()` and `js_dataview_setValue()` --- cutils.h | 3 -- quickjs.c | 116 +++++++++++++++++++++++++++--------------------------- 2 files changed, 58 insertions(+), 61 deletions(-) diff --git a/cutils.h b/cutils.h index a9077f5..ea7a760 100644 --- a/cutils.h +++ b/cutils.h @@ -28,9 +28,6 @@ #include #include -/* set if CPU is big endian */ -#undef WORDS_BIGENDIAN - #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #define force_inline inline __attribute__((always_inline)) diff --git a/quickjs.c b/quickjs.c index 6a34940..c820b0a 100644 --- a/quickjs.c +++ b/quickjs.c @@ -34582,8 +34582,6 @@ typedef enum BCTagEnum { BC_TAG_OBJECT, BC_TAG_ARRAY, BC_TAG_BIG_INT, - BC_TAG_BIG_FLOAT, - BC_TAG_BIG_DECIMAL, BC_TAG_TEMPLATE_OBJECT, BC_TAG_FUNCTION_BYTECODE, BC_TAG_MODULE, @@ -34593,24 +34591,21 @@ typedef enum BCTagEnum { BC_TAG_DATE, BC_TAG_OBJECT_VALUE, BC_TAG_OBJECT_REFERENCE, +#ifdef CONFIG_BIGNUM + BC_TAG_BIG_FLOAT, + BC_TAG_BIG_DECIMAL, +#endif } BCTagEnum; #ifdef CONFIG_BIGNUM -#define BC_BASE_VERSION 2 +#define BC_VERSION 0x43 #else -#define BC_BASE_VERSION 1 -#endif -#define BC_BE_VERSION 0x40 -#ifdef WORDS_BIGENDIAN -#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION) -#else -#define BC_VERSION BC_BASE_VERSION +#define BC_VERSION 3 #endif typedef struct BCWriterState { JSContext *ctx; DynBuf dbuf; - BOOL byte_swap : 8; BOOL allow_bytecode : 8; BOOL allow_sab : 8; BOOL allow_reference : 8; @@ -34640,8 +34635,6 @@ static const char * const bc_tag_str[] = { "object", "array", "bigint", - "bigfloat", - "bigdecimal", "template", "function", "module", @@ -34651,9 +34644,22 @@ static const char * const bc_tag_str[] = { "Date", "ObjectValue", "ObjectReference", +#ifdef CONFIG_BIGNUM + "bigfloat", + "bigdecimal", +#endif }; #endif +static inline BOOL is_be(void) +{ + union { + uint16_t a; + uint8_t b; + } u = {0x100}; + return u.b; +} + static void bc_put_u8(BCWriterState *s, uint8_t v) { dbuf_putc(&s->dbuf, v); @@ -34661,21 +34667,21 @@ static void bc_put_u8(BCWriterState *s, uint8_t v) static void bc_put_u16(BCWriterState *s, uint16_t v) { - if (s->byte_swap) + if (is_be()) v = bswap16(v); dbuf_put_u16(&s->dbuf, v); } static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v) { - if (s->byte_swap) + if (is_be()) v = bswap32(v); dbuf_put_u32(&s->dbuf, v); } static void bc_put_u64(BCWriterState *s, uint64_t v) { - if (s->byte_swap) + if (is_be()) v = bswap64(v); dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v)); } @@ -34845,7 +34851,7 @@ static int JS_WriteFunctionBytecode(BCWriterState *s, pos += len; } - if (s->byte_swap) + if (is_be()) bc_byte_swap(bc_buf, bc_len); dbuf_put(&s->dbuf, bc_buf, bc_len); @@ -34936,20 +34942,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) bc_put_leb128(s, len); /* always saved in byte based little endian representation */ for(j = 0; j < n1; j++) { - dbuf_putc(&s->dbuf, v >> (j * 8)); + bc_put_u8(s, v >> (j * 8)); } for(; i < a->len; i++) { limb_t v = a->tab[i]; #if LIMB_BITS == 32 -#ifdef WORDS_BIGENDIAN - v = bswap32(v); -#endif - dbuf_put_u32(&s->dbuf, v); + bc_put_u32(s, v); #else -#ifdef WORDS_BIGENDIAN - v = bswap64(v); -#endif - dbuf_put_u64(&s->dbuf, v); + bc_put_u64(s, v); #endif } } else { @@ -34992,14 +34992,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) v8 = d; bpos = 1; } else { - dbuf_putc(&s->dbuf, v8 | (d << 4)); + bc_put_u8(s, v8 | (d << 4)); bpos = 0; } } } /* flush the last digit */ if (bpos) { - dbuf_putc(&s->dbuf, v8); + bc_put_u8(s, v8); } } } @@ -35412,15 +35412,10 @@ static int JS_WriteObjectAtoms(BCWriterState *s) JSRuntime *rt = s->ctx->rt; DynBuf dbuf1; int i, atoms_size; - uint8_t version; dbuf1 = s->dbuf; js_dbuf_init(s->ctx, &s->dbuf); - - version = BC_VERSION; - if (s->byte_swap) - version ^= BC_BE_VERSION; - bc_put_u8(s, version); + bc_put_u8(s, BC_VERSION); bc_put_leb128(s, s->idx_to_atom_count); for(i = 0; i < s->idx_to_atom_count; i++) { @@ -35453,8 +35448,6 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, memset(s, 0, sizeof(*s)); s->ctx = ctx; - /* XXX: byte swapped output is untested */ - s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0); s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0); s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0); s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0); @@ -35575,33 +35568,45 @@ static int bc_get_u8(BCReaderState *s, uint8_t *pval) static int bc_get_u16(BCReaderState *s, uint16_t *pval) { + uint16_t v; if (unlikely(s->buf_end - s->ptr < 2)) { *pval = 0; /* avoid warning */ return bc_read_error_end(s); } - *pval = get_u16(s->ptr); + v = get_u16(s->ptr); + if (is_be()) + v = bswap16(v); + *pval = v; s->ptr += 2; return 0; } static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval) { + uint32_t v; if (unlikely(s->buf_end - s->ptr < 4)) { *pval = 0; /* avoid warning */ return bc_read_error_end(s); } - *pval = get_u32(s->ptr); + v = get_u32(s->ptr); + if (is_be()) + v = bswap32(v); + *pval = v; s->ptr += 4; return 0; } static int bc_get_u64(BCReaderState *s, uint64_t *pval) { + uint64_t v; if (unlikely(s->buf_end - s->ptr < 8)) { *pval = 0; /* avoid warning */ return bc_read_error_end(s); } - *pval = get_u64(s->ptr); + v = get_u64(s->ptr); + if (is_be()) + v = bswap64(v); + *pval = v; s->ptr += 8; return 0; } @@ -35711,10 +35716,15 @@ static JSString *JS_ReadString(BCReaderState *s) js_free_string(s->ctx->rt, p); return NULL; } - // XXX: potential endianness issue memcpy(p->u.str8, s->ptr, size); s->ptr += size; - if (!is_wide_char) { + if (is_wide_char) { + if (is_be()) { + uint32_t i; + for (i = 0; i < len; i++) + p->u.str16[i] = bswap16(p->u.str16[i]); + } + } else { p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */ } #ifdef DUMP_READ_OBJECT @@ -35753,6 +35763,9 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b, } b->byte_code_buf = bc_buf; + if (is_be()) + bc_byte_swap(bc_buf, bc_len); + pos = 0; while (pos < bc_len) { op = bc_buf[pos]; @@ -35873,15 +35886,9 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) #if LIMB_BITS == 32 if (bc_get_u32(s, &v)) goto fail; -#ifdef WORDS_BIGENDIAN - v = bswap32(v); -#endif #else if (bc_get_u64(s, &v)) goto fail; -#ifdef WORDS_BIGENDIAN - v = bswap64(v); -#endif #endif a->tab[i] = v; } @@ -36589,7 +36596,6 @@ static int JS_ReadObjectAtoms(BCReaderState *s) if (bc_get_u8(s, &v8)) return -1; - /* XXX: could support byte swapped input */ if (v8 != BC_VERSION) { JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)", v8, BC_VERSION); @@ -54857,12 +54863,9 @@ static JSValue js_dataview_getValue(JSContext *ctx, size = 1 << typed_array_size_log2(class_id); if (JS_ToIndex(ctx, &pos, argv[0])) return JS_EXCEPTION; - is_swap = FALSE; + is_swap = TRUE; if (argc > 1) - is_swap = JS_ToBool(ctx, argv[1]); -#ifndef WORDS_BIGENDIAN - is_swap ^= 1; -#endif + is_swap = !JS_ToBool(ctx, argv[1]); abuf = ta->buffer->u.array_buffer; if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); @@ -54986,12 +54989,9 @@ static JSValue js_dataview_setValue(JSContext *ctx, v64 = u.u64; } } - is_swap = FALSE; + is_swap = TRUE; if (argc > 2) - is_swap = JS_ToBool(ctx, argv[2]); -#ifndef WORDS_BIGENDIAN - is_swap ^= 1; -#endif + is_swap = !JS_ToBool(ctx, argv[2]); abuf = ta->buffer->u.array_buffer; if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);