Skip to content

Commit bbf36d5

Browse files
committedFeb 18, 2024
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()`
1 parent 530ba6a commit bbf36d5

File tree

2 files changed

+58
-61
lines changed

2 files changed

+58
-61
lines changed
 

‎cutils.h

-3
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@
2828
#include <stdlib.h>
2929
#include <inttypes.h>
3030

31-
/* set if CPU is big endian */
32-
#undef WORDS_BIGENDIAN
33-
3431
#define likely(x) __builtin_expect(!!(x), 1)
3532
#define unlikely(x) __builtin_expect(!!(x), 0)
3633
#define force_inline inline __attribute__((always_inline))

‎quickjs.c

+58-58
Original file line numberDiff line numberDiff line change
@@ -34582,8 +34582,6 @@ typedef enum BCTagEnum {
3458234582
BC_TAG_OBJECT,
3458334583
BC_TAG_ARRAY,
3458434584
BC_TAG_BIG_INT,
34585-
BC_TAG_BIG_FLOAT,
34586-
BC_TAG_BIG_DECIMAL,
3458734585
BC_TAG_TEMPLATE_OBJECT,
3458834586
BC_TAG_FUNCTION_BYTECODE,
3458934587
BC_TAG_MODULE,
@@ -34593,24 +34591,21 @@ typedef enum BCTagEnum {
3459334591
BC_TAG_DATE,
3459434592
BC_TAG_OBJECT_VALUE,
3459534593
BC_TAG_OBJECT_REFERENCE,
34594+
#ifdef CONFIG_BIGNUM
34595+
BC_TAG_BIG_FLOAT,
34596+
BC_TAG_BIG_DECIMAL,
34597+
#endif
3459634598
} BCTagEnum;
3459734599

3459834600
#ifdef CONFIG_BIGNUM
34599-
#define BC_BASE_VERSION 2
34601+
#define BC_VERSION 0x43
3460034602
#else
34601-
#define BC_BASE_VERSION 1
34602-
#endif
34603-
#define BC_BE_VERSION 0x40
34604-
#ifdef WORDS_BIGENDIAN
34605-
#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION)
34606-
#else
34607-
#define BC_VERSION BC_BASE_VERSION
34603+
#define BC_VERSION 3
3460834604
#endif
3460934605

3461034606
typedef struct BCWriterState {
3461134607
JSContext *ctx;
3461234608
DynBuf dbuf;
34613-
BOOL byte_swap : 8;
3461434609
BOOL allow_bytecode : 8;
3461534610
BOOL allow_sab : 8;
3461634611
BOOL allow_reference : 8;
@@ -34640,8 +34635,6 @@ static const char * const bc_tag_str[] = {
3464034635
"object",
3464134636
"array",
3464234637
"bigint",
34643-
"bigfloat",
34644-
"bigdecimal",
3464534638
"template",
3464634639
"function",
3464734640
"module",
@@ -34651,31 +34644,44 @@ static const char * const bc_tag_str[] = {
3465134644
"Date",
3465234645
"ObjectValue",
3465334646
"ObjectReference",
34647+
#ifdef CONFIG_BIGNUM
34648+
"bigfloat",
34649+
"bigdecimal",
34650+
#endif
3465434651
};
3465534652
#endif
3465634653

34654+
static inline BOOL is_be(void)
34655+
{
34656+
union {
34657+
uint16_t a;
34658+
uint8_t b;
34659+
} u = {0x100};
34660+
return u.b;
34661+
}
34662+
3465734663
static void bc_put_u8(BCWriterState *s, uint8_t v)
3465834664
{
3465934665
dbuf_putc(&s->dbuf, v);
3466034666
}
3466134667

3466234668
static void bc_put_u16(BCWriterState *s, uint16_t v)
3466334669
{
34664-
if (s->byte_swap)
34670+
if (is_be())
3466534671
v = bswap16(v);
3466634672
dbuf_put_u16(&s->dbuf, v);
3466734673
}
3466834674

3466934675
static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
3467034676
{
34671-
if (s->byte_swap)
34677+
if (is_be())
3467234678
v = bswap32(v);
3467334679
dbuf_put_u32(&s->dbuf, v);
3467434680
}
3467534681

3467634682
static void bc_put_u64(BCWriterState *s, uint64_t v)
3467734683
{
34678-
if (s->byte_swap)
34684+
if (is_be())
3467934685
v = bswap64(v);
3468034686
dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
3468134687
}
@@ -34845,7 +34851,7 @@ static int JS_WriteFunctionBytecode(BCWriterState *s,
3484534851
pos += len;
3484634852
}
3484734853

34848-
if (s->byte_swap)
34854+
if (is_be())
3484934855
bc_byte_swap(bc_buf, bc_len);
3485034856

3485134857
dbuf_put(&s->dbuf, bc_buf, bc_len);
@@ -34936,20 +34942,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
3493634942
bc_put_leb128(s, len);
3493734943
/* always saved in byte based little endian representation */
3493834944
for(j = 0; j < n1; j++) {
34939-
dbuf_putc(&s->dbuf, v >> (j * 8));
34945+
bc_put_u8(s, v >> (j * 8));
3494034946
}
3494134947
for(; i < a->len; i++) {
3494234948
limb_t v = a->tab[i];
3494334949
#if LIMB_BITS == 32
34944-
#ifdef WORDS_BIGENDIAN
34945-
v = bswap32(v);
34946-
#endif
34947-
dbuf_put_u32(&s->dbuf, v);
34950+
bc_put_u32(s, v);
3494834951
#else
34949-
#ifdef WORDS_BIGENDIAN
34950-
v = bswap64(v);
34951-
#endif
34952-
dbuf_put_u64(&s->dbuf, v);
34952+
bc_put_u64(s, v);
3495334953
#endif
3495434954
}
3495534955
} else {
@@ -34992,14 +34992,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
3499234992
v8 = d;
3499334993
bpos = 1;
3499434994
} else {
34995-
dbuf_putc(&s->dbuf, v8 | (d << 4));
34995+
bc_put_u8(s, v8 | (d << 4));
3499634996
bpos = 0;
3499734997
}
3499834998
}
3499934999
}
3500035000
/* flush the last digit */
3500135001
if (bpos) {
35002-
dbuf_putc(&s->dbuf, v8);
35002+
bc_put_u8(s, v8);
3500335003
}
3500435004
}
3500535005
}
@@ -35412,15 +35412,10 @@ static int JS_WriteObjectAtoms(BCWriterState *s)
3541235412
JSRuntime *rt = s->ctx->rt;
3541335413
DynBuf dbuf1;
3541435414
int i, atoms_size;
35415-
uint8_t version;
3541635415

3541735416
dbuf1 = s->dbuf;
3541835417
js_dbuf_init(s->ctx, &s->dbuf);
35419-
35420-
version = BC_VERSION;
35421-
if (s->byte_swap)
35422-
version ^= BC_BE_VERSION;
35423-
bc_put_u8(s, version);
35418+
bc_put_u8(s, BC_VERSION);
3542435419

3542535420
bc_put_leb128(s, s->idx_to_atom_count);
3542635421
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,
3545335448

3545435449
memset(s, 0, sizeof(*s));
3545535450
s->ctx = ctx;
35456-
/* XXX: byte swapped output is untested */
35457-
s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0);
3545835451
s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
3545935452
s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
3546035453
s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
@@ -35575,33 +35568,45 @@ static int bc_get_u8(BCReaderState *s, uint8_t *pval)
3557535568

3557635569
static int bc_get_u16(BCReaderState *s, uint16_t *pval)
3557735570
{
35571+
uint16_t v;
3557835572
if (unlikely(s->buf_end - s->ptr < 2)) {
3557935573
*pval = 0; /* avoid warning */
3558035574
return bc_read_error_end(s);
3558135575
}
35582-
*pval = get_u16(s->ptr);
35576+
v = get_u16(s->ptr);
35577+
if (is_be())
35578+
v = bswap16(v);
35579+
*pval = v;
3558335580
s->ptr += 2;
3558435581
return 0;
3558535582
}
3558635583

3558735584
static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
3558835585
{
35586+
uint32_t v;
3558935587
if (unlikely(s->buf_end - s->ptr < 4)) {
3559035588
*pval = 0; /* avoid warning */
3559135589
return bc_read_error_end(s);
3559235590
}
35593-
*pval = get_u32(s->ptr);
35591+
v = get_u32(s->ptr);
35592+
if (is_be())
35593+
v = bswap32(v);
35594+
*pval = v;
3559435595
s->ptr += 4;
3559535596
return 0;
3559635597
}
3559735598

3559835599
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
3559935600
{
35601+
uint64_t v;
3560035602
if (unlikely(s->buf_end - s->ptr < 8)) {
3560135603
*pval = 0; /* avoid warning */
3560235604
return bc_read_error_end(s);
3560335605
}
35604-
*pval = get_u64(s->ptr);
35606+
v = get_u64(s->ptr);
35607+
if (is_be())
35608+
v = bswap64(v);
35609+
*pval = v;
3560535610
s->ptr += 8;
3560635611
return 0;
3560735612
}
@@ -35711,10 +35716,15 @@ static JSString *JS_ReadString(BCReaderState *s)
3571135716
js_free_string(s->ctx->rt, p);
3571235717
return NULL;
3571335718
}
35714-
// XXX: potential endianness issue
3571535719
memcpy(p->u.str8, s->ptr, size);
3571635720
s->ptr += size;
35717-
if (!is_wide_char) {
35721+
if (is_wide_char) {
35722+
if (is_be()) {
35723+
uint32_t i;
35724+
for (i = 0; i < len; i++)
35725+
p->u.str16[i] = bswap16(p->u.str16[i]);
35726+
}
35727+
} else {
3571835728
p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
3571935729
}
3572035730
#ifdef DUMP_READ_OBJECT
@@ -35753,6 +35763,9 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
3575335763
}
3575435764
b->byte_code_buf = bc_buf;
3575535765

35766+
if (is_be())
35767+
bc_byte_swap(bc_buf, bc_len);
35768+
3575635769
pos = 0;
3575735770
while (pos < bc_len) {
3575835771
op = bc_buf[pos];
@@ -35873,15 +35886,9 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
3587335886
#if LIMB_BITS == 32
3587435887
if (bc_get_u32(s, &v))
3587535888
goto fail;
35876-
#ifdef WORDS_BIGENDIAN
35877-
v = bswap32(v);
35878-
#endif
3587935889
#else
3588035890
if (bc_get_u64(s, &v))
3588135891
goto fail;
35882-
#ifdef WORDS_BIGENDIAN
35883-
v = bswap64(v);
35884-
#endif
3588535892
#endif
3588635893
a->tab[i] = v;
3588735894
}
@@ -36589,7 +36596,6 @@ static int JS_ReadObjectAtoms(BCReaderState *s)
3658936596

3659036597
if (bc_get_u8(s, &v8))
3659136598
return -1;
36592-
/* XXX: could support byte swapped input */
3659336599
if (v8 != BC_VERSION) {
3659436600
JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
3659536601
v8, BC_VERSION);
@@ -54857,12 +54863,9 @@ static JSValue js_dataview_getValue(JSContext *ctx,
5485754863
size = 1 << typed_array_size_log2(class_id);
5485854864
if (JS_ToIndex(ctx, &pos, argv[0]))
5485954865
return JS_EXCEPTION;
54860-
is_swap = FALSE;
54866+
is_swap = TRUE;
5486154867
if (argc > 1)
54862-
is_swap = JS_ToBool(ctx, argv[1]);
54863-
#ifndef WORDS_BIGENDIAN
54864-
is_swap ^= 1;
54865-
#endif
54868+
is_swap = !JS_ToBool(ctx, argv[1]);
5486654869
abuf = ta->buffer->u.array_buffer;
5486754870
if (abuf->detached)
5486854871
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
@@ -54986,12 +54989,9 @@ static JSValue js_dataview_setValue(JSContext *ctx,
5498654989
v64 = u.u64;
5498754990
}
5498854991
}
54989-
is_swap = FALSE;
54992+
is_swap = TRUE;
5499054993
if (argc > 2)
54991-
is_swap = JS_ToBool(ctx, argv[2]);
54992-
#ifndef WORDS_BIGENDIAN
54993-
is_swap ^= 1;
54994-
#endif
54994+
is_swap = !JS_ToBool(ctx, argv[2]);
5499554995
abuf = ta->buffer->u.array_buffer;
5499654996
if (abuf->detached)
5499754997
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);

0 commit comments

Comments
 (0)