Handle serialization endianness transparently (#152)

Change JS_WriteObject() and JS_WriteObject2() to write little-endian
data and update JS_ReadObject() to byte-swap data when running on a
big-endian system.

Obsoletes the JS_WRITE_OBJ_BSWAP flag, it is now a no-op.

Fixes: https://github.com/quickjs-ng/quickjs/issues/125
This commit is contained in:
Ben Noordhuis 2023-11-28 22:49:01 +01:00 committed by GitHub
parent 0ecb2c86b5
commit a6e73ca73c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 18 additions and 36 deletions

View file

@ -167,9 +167,6 @@ find the name of the dynamically loaded modules.
Add initialization code for an external C module. See the
@code{c_module} example.
@item -x
Byte swapped output (only used for cross compilation).
@item -flto
Use link time optimization. The compilation is slower but the
executable is smaller and faster. This option is automatically set

13
qjsc.c
View file

@ -51,7 +51,6 @@ static namelist_t cname_list;
static namelist_t cmodule_list;
static namelist_t init_module_list;
static FILE *outfile;
static BOOL byte_swap;
static const char *c_ident_prefix = "qjsc_";
@ -152,11 +151,8 @@ static void output_object_code(JSContext *ctx,
{
uint8_t *out_buf;
size_t out_buf_len;
int flags;
flags = JS_WRITE_OBJ_BYTECODE;
if (byte_swap)
flags |= JS_WRITE_OBJ_BSWAP;
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, JS_WRITE_OBJ_BYTECODE);
if (!out_buf) {
js_std_dump_error(ctx);
exit(1);
@ -322,7 +318,6 @@ void help(void)
"-m compile as Javascript module (default=autodetect)\n"
"-D module_name compile a dynamically loaded module or worker\n"
"-M module_name[,cname] add initialization code for an external C module\n"
"-x byte swapped output\n"
"-p prefix set the prefix of the generated C names\n"
"-S n set the maximum stack size to 'n' bytes (default=%d)\n",
JS_GetVersion(),
@ -352,7 +347,6 @@ int main(int argc, char **argv)
output_type = OUTPUT_C;
cname = NULL;
module = -1;
byte_swap = FALSE;
verbose = 0;
stack_size = 0;
memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
@ -399,9 +393,6 @@ int main(int argc, char **argv)
case 'D':
namelist_add(&dynamic_module_list, optarg, NULL, 0);
break;
case 'x':
byte_swap = TRUE;
break;
case 'v':
verbose++;
break;

View file

@ -31664,18 +31664,11 @@ typedef enum BCTagEnum {
BC_TAG_OBJECT_REFERENCE,
} BCTagEnum;
#define BC_BASE_VERSION 2
#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
#define BC_VERSION 3
typedef struct BCWriterState {
JSContext *ctx;
DynBuf dbuf;
BOOL byte_swap : 8;
BOOL allow_bytecode : 8;
BOOL allow_sab : 8;
BOOL allow_reference : 8;
@ -31717,6 +31710,15 @@ static const char * const bc_tag_str[] = {
};
#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);
@ -31724,21 +31726,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));
}
@ -31908,7 +31910,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);
@ -32405,15 +32407,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++) {
@ -32446,8 +32443,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);
@ -33531,7 +33526,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);

View file

@ -838,7 +838,7 @@ JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
/* Object Writer/Reader (currently only used to handle precompiled code) */
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
#define JS_WRITE_OBJ_BSWAP (0) /* byte swapped output (obsolete, handled transparently) */
#define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to
encode arbitrary object