commit c5f8e260e160e0ecc23d916d137738b0da5faedc
parent 8bcdc561a338d9f0fab3c8e906e5a2cd4db5cbcf
Author: Charlie Gordon <github@chqrlie.org>
Date: Sun, 18 Feb 2024 08:29:04 +0100
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()`
Diffstat:
2 files changed, 58 insertions(+), 61 deletions(-)
diff --git a/quickjs/cutils.h b/quickjs/cutils.h
@@ -28,9 +28,6 @@
#include <stdlib.h>
#include <inttypes.h>
-/* 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/quickjs.c b/quickjs/quickjs.c
@@ -34773,8 +34773,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,
@@ -34784,24 +34782,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;
@@ -34831,8 +34826,6 @@ static const char * const bc_tag_str[] = {
"object",
"array",
"bigint",
- "bigfloat",
- "bigdecimal",
"template",
"function",
"module",
@@ -34842,9 +34835,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);
@@ -34852,21 +34858,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));
}
@@ -35036,7 +35042,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);
@@ -35127,20 +35133,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 {
@@ -35183,14 +35183,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);
}
}
}
@@ -35603,15 +35603,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++) {
@@ -35644,8 +35639,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);
@@ -35766,33 +35759,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;
}
@@ -35902,10 +35907,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
@@ -35944,6 +35954,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];
@@ -36064,15 +36077,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;
}
@@ -36780,7 +36787,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);
@@ -55154,12 +55160,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);
@@ -55283,12 +55286,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);