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()`
This commit is contained in:
parent
530ba6a631
commit
bbf36d5b84
2 changed files with 58 additions and 61 deletions
3
cutils.h
3
cutils.h
|
@ -28,9 +28,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
/* set if CPU is big endian */
|
|
||||||
#undef WORDS_BIGENDIAN
|
|
||||||
|
|
||||||
#define likely(x) __builtin_expect(!!(x), 1)
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
#define force_inline inline __attribute__((always_inline))
|
#define force_inline inline __attribute__((always_inline))
|
||||||
|
|
116
quickjs.c
116
quickjs.c
|
@ -34582,8 +34582,6 @@ typedef enum BCTagEnum {
|
||||||
BC_TAG_OBJECT,
|
BC_TAG_OBJECT,
|
||||||
BC_TAG_ARRAY,
|
BC_TAG_ARRAY,
|
||||||
BC_TAG_BIG_INT,
|
BC_TAG_BIG_INT,
|
||||||
BC_TAG_BIG_FLOAT,
|
|
||||||
BC_TAG_BIG_DECIMAL,
|
|
||||||
BC_TAG_TEMPLATE_OBJECT,
|
BC_TAG_TEMPLATE_OBJECT,
|
||||||
BC_TAG_FUNCTION_BYTECODE,
|
BC_TAG_FUNCTION_BYTECODE,
|
||||||
BC_TAG_MODULE,
|
BC_TAG_MODULE,
|
||||||
|
@ -34593,24 +34591,21 @@ typedef enum BCTagEnum {
|
||||||
BC_TAG_DATE,
|
BC_TAG_DATE,
|
||||||
BC_TAG_OBJECT_VALUE,
|
BC_TAG_OBJECT_VALUE,
|
||||||
BC_TAG_OBJECT_REFERENCE,
|
BC_TAG_OBJECT_REFERENCE,
|
||||||
|
#ifdef CONFIG_BIGNUM
|
||||||
|
BC_TAG_BIG_FLOAT,
|
||||||
|
BC_TAG_BIG_DECIMAL,
|
||||||
|
#endif
|
||||||
} BCTagEnum;
|
} BCTagEnum;
|
||||||
|
|
||||||
#ifdef CONFIG_BIGNUM
|
#ifdef CONFIG_BIGNUM
|
||||||
#define BC_BASE_VERSION 2
|
#define BC_VERSION 0x43
|
||||||
#else
|
#else
|
||||||
#define BC_BASE_VERSION 1
|
#define BC_VERSION 3
|
||||||
#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
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct BCWriterState {
|
typedef struct BCWriterState {
|
||||||
JSContext *ctx;
|
JSContext *ctx;
|
||||||
DynBuf dbuf;
|
DynBuf dbuf;
|
||||||
BOOL byte_swap : 8;
|
|
||||||
BOOL allow_bytecode : 8;
|
BOOL allow_bytecode : 8;
|
||||||
BOOL allow_sab : 8;
|
BOOL allow_sab : 8;
|
||||||
BOOL allow_reference : 8;
|
BOOL allow_reference : 8;
|
||||||
|
@ -34640,8 +34635,6 @@ static const char * const bc_tag_str[] = {
|
||||||
"object",
|
"object",
|
||||||
"array",
|
"array",
|
||||||
"bigint",
|
"bigint",
|
||||||
"bigfloat",
|
|
||||||
"bigdecimal",
|
|
||||||
"template",
|
"template",
|
||||||
"function",
|
"function",
|
||||||
"module",
|
"module",
|
||||||
|
@ -34651,9 +34644,22 @@ static const char * const bc_tag_str[] = {
|
||||||
"Date",
|
"Date",
|
||||||
"ObjectValue",
|
"ObjectValue",
|
||||||
"ObjectReference",
|
"ObjectReference",
|
||||||
|
#ifdef CONFIG_BIGNUM
|
||||||
|
"bigfloat",
|
||||||
|
"bigdecimal",
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
#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)
|
static void bc_put_u8(BCWriterState *s, uint8_t v)
|
||||||
{
|
{
|
||||||
dbuf_putc(&s->dbuf, 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)
|
static void bc_put_u16(BCWriterState *s, uint16_t v)
|
||||||
{
|
{
|
||||||
if (s->byte_swap)
|
if (is_be())
|
||||||
v = bswap16(v);
|
v = bswap16(v);
|
||||||
dbuf_put_u16(&s->dbuf, v);
|
dbuf_put_u16(&s->dbuf, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
|
static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
|
||||||
{
|
{
|
||||||
if (s->byte_swap)
|
if (is_be())
|
||||||
v = bswap32(v);
|
v = bswap32(v);
|
||||||
dbuf_put_u32(&s->dbuf, v);
|
dbuf_put_u32(&s->dbuf, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bc_put_u64(BCWriterState *s, uint64_t v)
|
static void bc_put_u64(BCWriterState *s, uint64_t v)
|
||||||
{
|
{
|
||||||
if (s->byte_swap)
|
if (is_be())
|
||||||
v = bswap64(v);
|
v = bswap64(v);
|
||||||
dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
|
dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
|
||||||
}
|
}
|
||||||
|
@ -34845,7 +34851,7 @@ static int JS_WriteFunctionBytecode(BCWriterState *s,
|
||||||
pos += len;
|
pos += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->byte_swap)
|
if (is_be())
|
||||||
bc_byte_swap(bc_buf, bc_len);
|
bc_byte_swap(bc_buf, bc_len);
|
||||||
|
|
||||||
dbuf_put(&s->dbuf, 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);
|
bc_put_leb128(s, len);
|
||||||
/* always saved in byte based little endian representation */
|
/* always saved in byte based little endian representation */
|
||||||
for(j = 0; j < n1; j++) {
|
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++) {
|
for(; i < a->len; i++) {
|
||||||
limb_t v = a->tab[i];
|
limb_t v = a->tab[i];
|
||||||
#if LIMB_BITS == 32
|
#if LIMB_BITS == 32
|
||||||
#ifdef WORDS_BIGENDIAN
|
bc_put_u32(s, v);
|
||||||
v = bswap32(v);
|
|
||||||
#endif
|
|
||||||
dbuf_put_u32(&s->dbuf, v);
|
|
||||||
#else
|
#else
|
||||||
#ifdef WORDS_BIGENDIAN
|
bc_put_u64(s, v);
|
||||||
v = bswap64(v);
|
|
||||||
#endif
|
|
||||||
dbuf_put_u64(&s->dbuf, v);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -34992,14 +34992,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
|
||||||
v8 = d;
|
v8 = d;
|
||||||
bpos = 1;
|
bpos = 1;
|
||||||
} else {
|
} else {
|
||||||
dbuf_putc(&s->dbuf, v8 | (d << 4));
|
bc_put_u8(s, v8 | (d << 4));
|
||||||
bpos = 0;
|
bpos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* flush the last digit */
|
/* flush the last digit */
|
||||||
if (bpos) {
|
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;
|
JSRuntime *rt = s->ctx->rt;
|
||||||
DynBuf dbuf1;
|
DynBuf dbuf1;
|
||||||
int i, atoms_size;
|
int i, atoms_size;
|
||||||
uint8_t version;
|
|
||||||
|
|
||||||
dbuf1 = s->dbuf;
|
dbuf1 = s->dbuf;
|
||||||
js_dbuf_init(s->ctx, &s->dbuf);
|
js_dbuf_init(s->ctx, &s->dbuf);
|
||||||
|
bc_put_u8(s, BC_VERSION);
|
||||||
version = BC_VERSION;
|
|
||||||
if (s->byte_swap)
|
|
||||||
version ^= BC_BE_VERSION;
|
|
||||||
bc_put_u8(s, version);
|
|
||||||
|
|
||||||
bc_put_leb128(s, s->idx_to_atom_count);
|
bc_put_leb128(s, s->idx_to_atom_count);
|
||||||
for(i = 0; i < s->idx_to_atom_count; i++) {
|
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));
|
memset(s, 0, sizeof(*s));
|
||||||
s->ctx = ctx;
|
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_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
|
||||||
s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
|
s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
|
||||||
s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 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)
|
static int bc_get_u16(BCReaderState *s, uint16_t *pval)
|
||||||
{
|
{
|
||||||
|
uint16_t v;
|
||||||
if (unlikely(s->buf_end - s->ptr < 2)) {
|
if (unlikely(s->buf_end - s->ptr < 2)) {
|
||||||
*pval = 0; /* avoid warning */
|
*pval = 0; /* avoid warning */
|
||||||
return bc_read_error_end(s);
|
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;
|
s->ptr += 2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
|
static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
|
||||||
{
|
{
|
||||||
|
uint32_t v;
|
||||||
if (unlikely(s->buf_end - s->ptr < 4)) {
|
if (unlikely(s->buf_end - s->ptr < 4)) {
|
||||||
*pval = 0; /* avoid warning */
|
*pval = 0; /* avoid warning */
|
||||||
return bc_read_error_end(s);
|
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;
|
s->ptr += 4;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
|
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
|
||||||
{
|
{
|
||||||
|
uint64_t v;
|
||||||
if (unlikely(s->buf_end - s->ptr < 8)) {
|
if (unlikely(s->buf_end - s->ptr < 8)) {
|
||||||
*pval = 0; /* avoid warning */
|
*pval = 0; /* avoid warning */
|
||||||
return bc_read_error_end(s);
|
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;
|
s->ptr += 8;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -35711,10 +35716,15 @@ static JSString *JS_ReadString(BCReaderState *s)
|
||||||
js_free_string(s->ctx->rt, p);
|
js_free_string(s->ctx->rt, p);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// XXX: potential endianness issue
|
|
||||||
memcpy(p->u.str8, s->ptr, size);
|
memcpy(p->u.str8, s->ptr, size);
|
||||||
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 */
|
p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
|
||||||
}
|
}
|
||||||
#ifdef DUMP_READ_OBJECT
|
#ifdef DUMP_READ_OBJECT
|
||||||
|
@ -35753,6 +35763,9 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
|
||||||
}
|
}
|
||||||
b->byte_code_buf = bc_buf;
|
b->byte_code_buf = bc_buf;
|
||||||
|
|
||||||
|
if (is_be())
|
||||||
|
bc_byte_swap(bc_buf, bc_len);
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
while (pos < bc_len) {
|
while (pos < bc_len) {
|
||||||
op = bc_buf[pos];
|
op = bc_buf[pos];
|
||||||
|
@ -35873,15 +35886,9 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
|
||||||
#if LIMB_BITS == 32
|
#if LIMB_BITS == 32
|
||||||
if (bc_get_u32(s, &v))
|
if (bc_get_u32(s, &v))
|
||||||
goto fail;
|
goto fail;
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
v = bswap32(v);
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
if (bc_get_u64(s, &v))
|
if (bc_get_u64(s, &v))
|
||||||
goto fail;
|
goto fail;
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
v = bswap64(v);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
a->tab[i] = v;
|
a->tab[i] = v;
|
||||||
}
|
}
|
||||||
|
@ -36589,7 +36596,6 @@ static int JS_ReadObjectAtoms(BCReaderState *s)
|
||||||
|
|
||||||
if (bc_get_u8(s, &v8))
|
if (bc_get_u8(s, &v8))
|
||||||
return -1;
|
return -1;
|
||||||
/* XXX: could support byte swapped input */
|
|
||||||
if (v8 != BC_VERSION) {
|
if (v8 != BC_VERSION) {
|
||||||
JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
|
JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
|
||||||
v8, BC_VERSION);
|
v8, BC_VERSION);
|
||||||
|
@ -54857,12 +54863,9 @@ static JSValue js_dataview_getValue(JSContext *ctx,
|
||||||
size = 1 << typed_array_size_log2(class_id);
|
size = 1 << typed_array_size_log2(class_id);
|
||||||
if (JS_ToIndex(ctx, &pos, argv[0]))
|
if (JS_ToIndex(ctx, &pos, argv[0]))
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
is_swap = FALSE;
|
is_swap = TRUE;
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
is_swap = JS_ToBool(ctx, argv[1]);
|
is_swap = !JS_ToBool(ctx, argv[1]);
|
||||||
#ifndef WORDS_BIGENDIAN
|
|
||||||
is_swap ^= 1;
|
|
||||||
#endif
|
|
||||||
abuf = ta->buffer->u.array_buffer;
|
abuf = ta->buffer->u.array_buffer;
|
||||||
if (abuf->detached)
|
if (abuf->detached)
|
||||||
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
|
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
|
||||||
|
@ -54986,12 +54989,9 @@ static JSValue js_dataview_setValue(JSContext *ctx,
|
||||||
v64 = u.u64;
|
v64 = u.u64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is_swap = FALSE;
|
is_swap = TRUE;
|
||||||
if (argc > 2)
|
if (argc > 2)
|
||||||
is_swap = JS_ToBool(ctx, argv[2]);
|
is_swap = !JS_ToBool(ctx, argv[2]);
|
||||||
#ifndef WORDS_BIGENDIAN
|
|
||||||
is_swap ^= 1;
|
|
||||||
#endif
|
|
||||||
abuf = ta->buffer->u.array_buffer;
|
abuf = ta->buffer->u.array_buffer;
|
||||||
if (abuf->detached)
|
if (abuf->detached)
|
||||||
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
|
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
|
||||||
|
|
Loading…
Reference in a new issue