Skip to content

Commit 37d7439

Browse files
authored
[refactoring] Extract read leb to a separate file, share the code between loader and mini loader (bytecodealliance#3701)
There's probably a number of other places where the bh_leb_read could be used (e.g. aot loader) but I'm making the change as small as possible. Further refactoring can be done later.
1 parent a83adcc commit 37d7439

File tree

9 files changed

+223
-159
lines changed

9 files changed

+223
-159
lines changed

core/iwasm/common/wasm_loader_common.c

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44
*/
55
#include "wasm_loader_common.h"
6+
#include "bh_leb128.h"
67
#include "bh_log.h"
78
#if WASM_ENABLE_GC != 0
89
#include "../common/gc/gc_type.h"
910
#endif
1011

11-
static void
12-
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string,
13-
bool is_aot)
12+
void
13+
wasm_loader_set_error_buf(char *error_buf, uint32 error_buf_size,
14+
const char *string, bool is_aot)
1415
{
1516
if (error_buf != NULL) {
1617
snprintf(error_buf, error_buf_size, "%s module load failed: %s",
@@ -29,30 +30,30 @@ wasm_memory_check_flags(const uint8 mem_flag, char *error_buf,
2930
if (mem_flag & SHARED_MEMORY_FLAG) {
3031
LOG_VERBOSE("shared memory flag was found, please enable shared "
3132
"memory, lib-pthread or lib-wasi-threads");
32-
set_error_buf(error_buf, error_buf_size, "invalid limits flags",
33-
is_aot);
33+
wasm_loader_set_error_buf(error_buf, error_buf_size,
34+
"invalid limits flags", is_aot);
3435
return false;
3536
}
3637
#endif
3738
#if WASM_ENABLE_MEMORY64 == 0
3839
if (mem_flag & MEMORY64_FLAG) {
3940
LOG_VERBOSE("memory64 flag was found, please enable memory64");
40-
set_error_buf(error_buf, error_buf_size, "invalid limits flags",
41-
is_aot);
41+
wasm_loader_set_error_buf(error_buf, error_buf_size,
42+
"invalid limits flags", is_aot);
4243
return false;
4344
}
4445
#endif
4546
}
4647

4748
if (mem_flag > MAX_PAGE_COUNT_FLAG + SHARED_MEMORY_FLAG + MEMORY64_FLAG) {
48-
set_error_buf(error_buf, error_buf_size, "invalid limits flags",
49-
is_aot);
49+
wasm_loader_set_error_buf(error_buf, error_buf_size,
50+
"invalid limits flags", is_aot);
5051
return false;
5152
}
5253
else if ((mem_flag & SHARED_MEMORY_FLAG)
5354
&& !(mem_flag & MAX_PAGE_COUNT_FLAG)) {
54-
set_error_buf(error_buf, error_buf_size,
55-
"shared memory must have maximum", is_aot);
55+
wasm_loader_set_error_buf(error_buf, error_buf_size,
56+
"shared memory must have maximum", is_aot);
5657
return false;
5758
}
5859

@@ -130,3 +131,33 @@ is_indices_overflow(uint32 import, uint32 other, char *error_buf,
130131

131132
return false;
132133
}
134+
135+
bool
136+
read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign,
137+
uint64 *p_result, char *error_buf, uint32 error_buf_size)
138+
{
139+
size_t offset = 0;
140+
bh_leb_read_status_t status =
141+
bh_leb_read(*p_buf, buf_end, maxbits, sign, p_result, &offset);
142+
143+
switch (status) {
144+
case BH_LEB_READ_SUCCESS:
145+
*p_buf += offset;
146+
return true;
147+
case BH_LEB_READ_TOO_LONG:
148+
wasm_loader_set_error_buf(error_buf, error_buf_size,
149+
"integer representation too long", false);
150+
return false;
151+
case BH_LEB_READ_OVERFLOW:
152+
wasm_loader_set_error_buf(error_buf, error_buf_size,
153+
"integer too large", false);
154+
return false;
155+
case BH_LEB_READ_UNEXPECTED_END:
156+
wasm_loader_set_error_buf(error_buf, error_buf_size,
157+
"unexpected end", false);
158+
return false;
159+
default:
160+
bh_assert(false);
161+
return false;
162+
}
163+
}

core/iwasm/common/wasm_loader_common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ bool
3030
is_indices_overflow(uint32 import, uint32 other, char *error_buf,
3131
uint32 error_buf_size);
3232

33+
bool
34+
read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign,
35+
uint64 *p_result, char *error_buf, uint32 error_buf_size);
36+
37+
void
38+
wasm_loader_set_error_buf(char *error_buf, uint32 error_buf_size,
39+
const char *string, bool is_aot);
40+
3341
#ifdef __cplusplus
3442
}
3543
#endif

core/iwasm/interpreter/wasm_loader.c

Lines changed: 1 addition & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,7 @@ has_module_memory64(WASMModule *module)
5656
static void
5757
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
5858
{
59-
if (error_buf != NULL) {
60-
snprintf(error_buf, error_buf_size, "WASM module load failed: %s",
61-
string);
62-
}
59+
wasm_loader_set_error_buf(error_buf, error_buf_size, string, false);
6360
}
6461

6562
#if WASM_ENABLE_MEMORY64 != 0
@@ -131,82 +128,6 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length,
131128
#define skip_leb_int32(p, p_end) skip_leb(p)
132129
#define skip_leb_mem_offset(p, p_end) skip_leb(p)
133130

134-
static bool
135-
read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign,
136-
uint64 *p_result, char *error_buf, uint32 error_buf_size)
137-
{
138-
const uint8 *buf = *p_buf;
139-
uint64 result = 0;
140-
uint32 shift = 0;
141-
uint32 offset = 0, bcnt = 0;
142-
uint64 byte;
143-
144-
while (true) {
145-
/* uN or SN must not exceed ceil(N/7) bytes */
146-
if (bcnt + 1 > (maxbits + 6) / 7) {
147-
set_error_buf(error_buf, error_buf_size,
148-
"integer representation too long");
149-
return false;
150-
}
151-
152-
CHECK_BUF(buf, buf_end, offset + 1);
153-
byte = buf[offset];
154-
offset += 1;
155-
result |= ((byte & 0x7f) << shift);
156-
shift += 7;
157-
bcnt += 1;
158-
if ((byte & 0x80) == 0) {
159-
break;
160-
}
161-
}
162-
163-
if (!sign && maxbits == 32 && shift >= maxbits) {
164-
/* The top bits set represent values > 32 bits */
165-
if (((uint8)byte) & 0xf0)
166-
goto fail_integer_too_large;
167-
}
168-
else if (sign && maxbits == 32) {
169-
if (shift < maxbits) {
170-
/* Sign extend, second-highest bit is the sign bit */
171-
if ((uint8)byte & 0x40)
172-
result |= (~((uint64)0)) << shift;
173-
}
174-
else {
175-
/* The top bits should be a sign-extension of the sign bit */
176-
bool sign_bit_set = ((uint8)byte) & 0x8;
177-
int top_bits = ((uint8)byte) & 0xf0;
178-
if ((sign_bit_set && top_bits != 0x70)
179-
|| (!sign_bit_set && top_bits != 0))
180-
goto fail_integer_too_large;
181-
}
182-
}
183-
else if (sign && maxbits == 64) {
184-
if (shift < maxbits) {
185-
/* Sign extend, second-highest bit is the sign bit */
186-
if ((uint8)byte & 0x40)
187-
result |= (~((uint64)0)) << shift;
188-
}
189-
else {
190-
/* The top bits should be a sign-extension of the sign bit */
191-
bool sign_bit_set = ((uint8)byte) & 0x1;
192-
int top_bits = ((uint8)byte) & 0xfe;
193-
194-
if ((sign_bit_set && top_bits != 0x7e)
195-
|| (!sign_bit_set && top_bits != 0))
196-
goto fail_integer_too_large;
197-
}
198-
}
199-
200-
*p_buf += offset;
201-
*p_result = result;
202-
return true;
203-
204-
fail_integer_too_large:
205-
set_error_buf(error_buf, error_buf_size, "integer too large");
206-
fail:
207-
return false;
208-
}
209-
210131
#define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p)
211132
#define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p)
212133

core/iwasm/interpreter/wasm_mini_loader.c

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ has_module_memory64(WASMModule *module)
4444
static void
4545
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
4646
{
47-
if (error_buf != NULL)
48-
snprintf(error_buf, error_buf_size, "WASM module load failed: %s",
49-
string);
47+
wasm_loader_set_error_buf(error_buf, error_buf_size, string, false);
5048
}
5149

5250
#define CHECK_BUF(buf, buf_end, length) \
@@ -95,71 +93,6 @@ is_byte_a_type(uint8 type)
9593
|| (type == VALUE_TYPE_VOID);
9694
}
9795

98-
static void
99-
read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign,
100-
uint64 *p_result, char *error_buf, uint32 error_buf_size)
101-
{
102-
const uint8 *buf = *p_buf;
103-
uint64 result = 0;
104-
uint32 shift = 0;
105-
uint32 offset = 0, bcnt = 0;
106-
uint64 byte;
107-
108-
while (true) {
109-
bh_assert(bcnt + 1 <= (maxbits + 6) / 7);
110-
CHECK_BUF(buf, buf_end, offset + 1);
111-
byte = buf[offset];
112-
offset += 1;
113-
result |= ((byte & 0x7f) << shift);
114-
shift += 7;
115-
bcnt += 1;
116-
if ((byte & 0x80) == 0) {
117-
break;
118-
}
119-
}
120-
121-
if (!sign && maxbits == 32 && shift >= maxbits) {
122-
/* The top bits set represent values > 32 bits */
123-
bh_assert(!(((uint8)byte) & 0xf0));
124-
}
125-
else if (sign && maxbits == 32) {
126-
if (shift < maxbits) {
127-
/* Sign extend, second-highest bit is the sign bit */
128-
if ((uint8)byte & 0x40)
129-
result |= (~((uint64)0)) << shift;
130-
}
131-
else {
132-
/* The top bits should be a sign-extension of the sign bit */
133-
bool sign_bit_set = ((uint8)byte) & 0x8;
134-
int top_bits = ((uint8)byte) & 0xf0;
135-
bh_assert(!((sign_bit_set && top_bits != 0x70)
136-
|| (!sign_bit_set && top_bits != 0)));
137-
(void)top_bits;
138-
(void)sign_bit_set;
139-
}
140-
}
141-
else if (sign && maxbits == 64) {
142-
if (shift < maxbits) {
143-
/* Sign extend, second-highest bit is the sign bit */
144-
if ((uint8)byte & 0x40)
145-
result |= (~((uint64)0)) << shift;
146-
}
147-
else {
148-
/* The top bits should be a sign-extension of the sign bit */
149-
bool sign_bit_set = ((uint8)byte) & 0x1;
150-
int top_bits = ((uint8)byte) & 0xfe;
151-
152-
bh_assert(!((sign_bit_set && top_bits != 0x7e)
153-
|| (!sign_bit_set && top_bits != 0)));
154-
(void)top_bits;
155-
(void)sign_bit_set;
156-
}
157-
}
158-
159-
*p_buf += offset;
160-
*p_result = result;
161-
}
162-
16396
#define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p)
16497
#define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p)
16598
#define read_bool(p) TEMPLATE_READ_VALUE(bool, p)

core/shared/utils/bh_leb128.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (C) 2019 Intel Corporation. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#include "bh_leb128.h"
7+
8+
bh_leb_read_status_t
9+
bh_leb_read(const uint8 *buf, const uint8 *buf_end, uint32 maxbits, bool sign,
10+
uint64 *p_result, size_t *p_offset)
11+
{
12+
uint64 result = 0;
13+
uint32 shift = 0;
14+
uint32 offset = 0, bcnt = 0;
15+
uint64 byte;
16+
17+
while (true) {
18+
/* uN or SN must not exceed ceil(N/7) bytes */
19+
if (bcnt + 1 > (maxbits + 6) / 7) {
20+
return BH_LEB_READ_TOO_LONG;
21+
}
22+
23+
if ((uintptr_t)buf + offset + 1 < (uintptr_t)buf
24+
|| (uintptr_t)buf + offset + 1 > (uintptr_t)buf_end) {
25+
return BH_LEB_READ_UNEXPECTED_END;
26+
}
27+
byte = buf[offset];
28+
offset += 1;
29+
result |= ((byte & 0x7f) << shift);
30+
shift += 7;
31+
bcnt += 1;
32+
if ((byte & 0x80) == 0) {
33+
break;
34+
}
35+
}
36+
37+
if (!sign && maxbits == 32 && shift >= maxbits) {
38+
/* The top bits set represent values > 32 bits */
39+
if (((uint8)byte) & 0xf0)
40+
return BH_LEB_READ_OVERFLOW;
41+
}
42+
else if (sign && maxbits == 32) {
43+
if (shift < maxbits) {
44+
/* Sign extend, second-highest bit is the sign bit */
45+
if ((uint8)byte & 0x40)
46+
result |= (~((uint64)0)) << shift;
47+
}
48+
else {
49+
/* The top bits should be a sign-extension of the sign bit */
50+
bool sign_bit_set = ((uint8)byte) & 0x8;
51+
int top_bits = ((uint8)byte) & 0xf0;
52+
if ((sign_bit_set && top_bits != 0x70)
53+
|| (!sign_bit_set && top_bits != 0))
54+
return BH_LEB_READ_OVERFLOW;
55+
}
56+
}
57+
else if (sign && maxbits == 64) {
58+
if (shift < maxbits) {
59+
/* Sign extend, second-highest bit is the sign bit */
60+
if ((uint8)byte & 0x40)
61+
result |= (~((uint64)0)) << shift;
62+
}
63+
else {
64+
/* The top bits should be a sign-extension of the sign bit */
65+
bool sign_bit_set = ((uint8)byte) & 0x1;
66+
int top_bits = ((uint8)byte) & 0xfe;
67+
68+
if ((sign_bit_set && top_bits != 0x7e)
69+
|| (!sign_bit_set && top_bits != 0))
70+
return BH_LEB_READ_OVERFLOW;
71+
}
72+
}
73+
74+
*p_offset = offset;
75+
*p_result = result;
76+
return BH_LEB_READ_SUCCESS;
77+
}

core/shared/utils/bh_leb128.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#ifndef _BH_LEB128_H
7+
#define _BH_LEB128_H
8+
9+
#include "bh_platform.h"
10+
11+
typedef enum {
12+
BH_LEB_READ_SUCCESS,
13+
BH_LEB_READ_TOO_LONG,
14+
BH_LEB_READ_OVERFLOW,
15+
BH_LEB_READ_UNEXPECTED_END,
16+
} bh_leb_read_status_t;
17+
18+
#ifdef __cplusplus
19+
extern "C" {
20+
#endif
21+
22+
bh_leb_read_status_t
23+
bh_leb_read(const uint8 *buf, const uint8 *buf_end, uint32 maxbits, bool sign,
24+
uint64 *p_result, size_t *p_offset);
25+
26+
#ifdef __cplusplus
27+
}
28+
#endif
29+
30+
#endif

0 commit comments

Comments
 (0)