Skip to content

Commit b35b675

Browse files
committed
Do not reverse bytes for nullvm
- moved the condition to htowasm()/wasmtoh() parameter - added isWasmByteOrder() function to WasmVm interface - added ByteOrder test into null_vm_test Signed-off-by: Konstantin Maksimov <konstantin.maksimov@ibm.com>
1 parent 174c6be commit b35b675

File tree

15 files changed

+80
-38
lines changed

15 files changed

+80
-38
lines changed

include/proxy-wasm/null_vm.h

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ struct NullVm : public WasmVm {
6161
#undef _REGISTER_CALLBACK
6262

6363
void terminate() override {}
64+
bool isWasmByteOrder() override { return false; }
6465

6566
std::string plugin_name_;
6667
std::unique_ptr<NullVmPlugin> plugin_;

include/proxy-wasm/pairs_util.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,20 @@ class PairsUtil {
4545
* @param size size of the output buffer.
4646
* @return indicates whether serialization succeeded or not.
4747
*/
48-
static bool marshalPairs(const Pairs &pairs, char *buffer, size_t size);
48+
static bool marshalPairs(const Pairs &pairs, char *buffer, size_t size, bool is_wasm_byte_order);
4949

50-
static bool marshalPairs(const StringPairs &stringpairs, char *buffer, size_t size) {
50+
static bool marshalPairs(const StringPairs &stringpairs, char *buffer, size_t size,
51+
bool is_wasm_byte_order) {
5152
Pairs views(stringpairs.begin(), stringpairs.end());
52-
return marshalPairs(views, buffer, size);
53+
return marshalPairs(views, buffer, size, is_wasm_byte_order);
5354
}
5455

5556
/**
5657
* toPairs deserializes input buffer to Pairs.
5758
* @param buffer serialized input buffer.
5859
* @return deserialized Pairs or an empty instance in case of deserialization failure.
5960
*/
60-
static Pairs toPairs(std::string_view buffer);
61+
static Pairs toPairs(std::string_view buffer, bool is_wasm_byte_order);
6162
};
6263

6364
} // namespace proxy_wasm

include/proxy-wasm/wasm_vm.h

+6
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ class WasmVm {
303303
*/
304304
virtual void terminate() = 0;
305305

306+
/**
307+
* Byte order flag (host or wasm).
308+
* @return 'false' for a null VM and 'true' for a wasm VM.
309+
*/
310+
virtual bool isWasmByteOrder() = 0;
311+
306312
bool isFailed() { return failed_ != FailState::Ok; }
307313
void fail(FailState fail_state, std::string_view message) {
308314
integration()->error(message);

include/proxy-wasm/word.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ namespace proxy_wasm {
2424
// Use byteswap functions only when compiling for big-endian platforms.
2525
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
2626
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
27-
#define htowasm(x) __builtin_bswap32(x)
28-
#define wasmtoh(x) __builtin_bswap32(x)
27+
#define htowasm1111(x, is_null) is_null ? (x) : __builtin_bswap32(x)
28+
#define htowasm(x, is_wasm_byte_order) is_wasm_byte_order ? __builtin_bswap32(x) : (x)
29+
#define wasmtoh(x, is_wasm_byte_order) is_wasm_byte_order ? __builtin_bswap32(x) : (x)
2930
#else
30-
#define htowasm(x) (x)
31-
#define wasmtoh(x) (x)
31+
#define htowasm(x, is_wasm_byte_order) (x)
32+
#define wasmtoh(x, is_wasm_byte_order) (x)
3233
#endif
3334

3435
// Represents a Wasm-native word-sized datum. On 32-bit VMs, the high bits are always zero.

src/exports.cc

+15-10
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ Word send_local_response(Word response_code, Word response_code_details_ptr,
152152
if (!details || !body || !additional_response_header_pairs) {
153153
return WasmResult::InvalidMemoryAccess;
154154
}
155-
auto additional_headers = PairsUtil::toPairs(additional_response_header_pairs.value());
155+
auto additional_headers = PairsUtil::toPairs(additional_response_header_pairs.value(),
156+
context->wasmVm()->isWasmByteOrder());
156157
context->sendLocalResponse(response_code, body.value(), std::move(additional_headers),
157158
grpc_status, details.value());
158159
context->wasm()->stopNextIteration(true);
@@ -399,7 +400,7 @@ Word get_header_map_pairs(Word type, Word ptr_ptr, Word size_ptr) {
399400
if (buffer == nullptr) {
400401
return WasmResult::InvalidMemoryAccess;
401402
}
402-
if (!PairsUtil::marshalPairs(pairs, buffer, size)) {
403+
if (!PairsUtil::marshalPairs(pairs, buffer, size, context->wasmVm()->isWasmByteOrder())) {
403404
return WasmResult::InvalidMemoryAccess;
404405
}
405406
if (!context->wasmVm()->setWord(ptr_ptr, Word(ptr))) {
@@ -420,8 +421,9 @@ Word set_header_map_pairs(Word type, Word ptr, Word size) {
420421
if (!data) {
421422
return WasmResult::InvalidMemoryAccess;
422423
}
423-
return context->setHeaderMapPairs(static_cast<WasmHeaderMapType>(type.u64_),
424-
PairsUtil::toPairs(data.value()));
424+
return context->setHeaderMapPairs(
425+
static_cast<WasmHeaderMapType>(type.u64_),
426+
PairsUtil::toPairs(data.value(), context->wasmVm()->isWasmByteOrder()));
425427
}
426428

427429
Word get_header_map_size(Word type, Word result_ptr) {
@@ -519,8 +521,8 @@ Word http_call(Word uri_ptr, Word uri_size, Word header_pairs_ptr, Word header_p
519521
if (!uri || !body || !header_pairs || !trailer_pairs) {
520522
return WasmResult::InvalidMemoryAccess;
521523
}
522-
auto headers = PairsUtil::toPairs(header_pairs.value());
523-
auto trailers = PairsUtil::toPairs(trailer_pairs.value());
524+
auto headers = PairsUtil::toPairs(header_pairs.value(), context->wasmVm()->isWasmByteOrder());
525+
auto trailers = PairsUtil::toPairs(trailer_pairs.value(), context->wasmVm()->isWasmByteOrder());
524526
uint32_t token = 0;
525527
// NB: try to write the token to verify the memory before starting the async
526528
// operation.
@@ -589,7 +591,8 @@ Word grpc_call(Word service_ptr, Word service_size, Word service_name_ptr, Word
589591
return WasmResult::InvalidMemoryAccess;
590592
}
591593
uint32_t token = 0;
592-
auto initial_metadata = PairsUtil::toPairs(initial_metadata_pairs.value());
594+
auto initial_metadata =
595+
PairsUtil::toPairs(initial_metadata_pairs.value(), context->wasmVm()->isWasmByteOrder());
593596
auto result = context->grpcCall(service.value(), service_name.value(), method_name.value(),
594597
initial_metadata, request.value(),
595598
std::chrono::milliseconds(timeout_milliseconds), &token);
@@ -615,7 +618,8 @@ Word grpc_stream(Word service_ptr, Word service_size, Word service_name_ptr, Wor
615618
return WasmResult::InvalidMemoryAccess;
616619
}
617620
uint32_t token = 0;
618-
auto initial_metadata = PairsUtil::toPairs(initial_metadata_pairs.value());
621+
auto initial_metadata =
622+
PairsUtil::toPairs(initial_metadata_pairs.value(), context->wasmVm()->isWasmByteOrder());
619623
auto result = context->grpcStream(service.value(), service_name.value(), method_name.value(),
620624
initial_metadata, &token);
621625
if (result != WasmResult::Ok) {
@@ -693,8 +697,9 @@ Word writevImpl(Word fd, Word iovs, Word iovs_len, Word *nwritten_ptr) {
693697
}
694698
const auto *iovec = reinterpret_cast<const uint32_t *>(memslice.value().data());
695699
if (iovec[1] != 0U /* buf_len */) {
696-
memslice = context->wasmVm()->getMemory(wasmtoh(iovec[0]) /* buf */,
697-
wasmtoh(iovec[1]) /* buf_len */);
700+
memslice = context->wasmVm()->getMemory(
701+
wasmtoh(iovec[0], context->wasmVm()->isWasmByteOrder()) /* buf */,
702+
wasmtoh(iovec[1], context->wasmVm()->isWasmByteOrder()) /* buf_len */);
698703
if (!memslice) {
699704
return 21; // __WASI_EFAULT
700705
}

src/pairs_util.cc

+9-8
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ size_t PairsUtil::pairsSize(const Pairs &pairs) {
3636
return size;
3737
}
3838

39-
bool PairsUtil::marshalPairs(const Pairs &pairs, char *buffer, size_t size) {
39+
bool PairsUtil::marshalPairs(const Pairs &pairs, char *buffer, size_t size,
40+
[[maybe_unused]] bool is_wasm_byte_order) {
4041
if (buffer == nullptr) {
4142
return false;
4243
}
@@ -45,7 +46,7 @@ bool PairsUtil::marshalPairs(const Pairs &pairs, char *buffer, size_t size) {
4546
const char *end = buffer + size;
4647

4748
// Write number of pairs.
48-
uint32_t num_pairs = htowasm(pairs.size());
49+
uint32_t num_pairs = htowasm(pairs.size(), is_wasm_byte_order);
4950
if (pos + sizeof(uint32_t) > end) {
5051
return false;
5152
}
@@ -54,15 +55,15 @@ bool PairsUtil::marshalPairs(const Pairs &pairs, char *buffer, size_t size) {
5455

5556
for (const auto &p : pairs) {
5657
// Write name length.
57-
uint32_t name_len = htowasm(p.first.size());
58+
uint32_t name_len = htowasm(p.first.size(), is_wasm_byte_order);
5859
if (pos + sizeof(uint32_t) > end) {
5960
return false;
6061
}
6162
::memcpy(pos, &name_len, sizeof(uint32_t));
6263
pos += sizeof(uint32_t);
6364

6465
// Write value length.
65-
uint32_t value_len = htowasm(p.second.size());
66+
uint32_t value_len = htowasm(p.second.size(), is_wasm_byte_order);
6667
if (pos + sizeof(uint32_t) > end) {
6768
return false;
6869
}
@@ -91,7 +92,7 @@ bool PairsUtil::marshalPairs(const Pairs &pairs, char *buffer, size_t size) {
9192
return pos == end;
9293
}
9394

94-
Pairs PairsUtil::toPairs(std::string_view buffer) {
95+
Pairs PairsUtil::toPairs(std::string_view buffer, [[maybe_unused]] bool is_wasm_byte_order) {
9596
if (buffer.data() == nullptr || buffer.size() > PROXY_WASM_HOST_PAIRS_MAX_BYTES) {
9697
return {};
9798
}
@@ -103,7 +104,7 @@ Pairs PairsUtil::toPairs(std::string_view buffer) {
103104
if (pos + sizeof(uint32_t) > end) {
104105
return {};
105106
}
106-
uint32_t num_pairs = wasmtoh(*reinterpret_cast<const uint32_t *>(pos));
107+
uint32_t num_pairs = wasmtoh(*reinterpret_cast<const uint32_t *>(pos), is_wasm_byte_order);
107108
pos += sizeof(uint32_t);
108109

109110
// Check if we're not going to exceed the limit.
@@ -122,14 +123,14 @@ Pairs PairsUtil::toPairs(std::string_view buffer) {
122123
if (pos + sizeof(uint32_t) > end) {
123124
return {};
124125
}
125-
s.first = wasmtoh(*reinterpret_cast<const uint32_t *>(pos));
126+
s.first = wasmtoh(*reinterpret_cast<const uint32_t *>(pos), is_wasm_byte_order);
126127
pos += sizeof(uint32_t);
127128

128129
// Read value length.
129130
if (pos + sizeof(uint32_t) > end) {
130131
return {};
131132
}
132-
s.second = wasmtoh(*reinterpret_cast<const uint32_t *>(pos));
133+
s.second = wasmtoh(*reinterpret_cast<const uint32_t *>(pos), is_wasm_byte_order);
133134
pos += sizeof(uint32_t);
134135
}
135136

src/signature_util.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
8686

8787
uint32_t alg_id;
8888
std::memcpy(&alg_id, payload.data(), sizeof(uint32_t));
89-
alg_id = wasmtoh(alg_id);
89+
alg_id = wasmtoh(alg_id, true);
9090

9191
if (alg_id != 2) {
9292
message = "Signature has a wrong alg_id (want: 2, is: " + std::to_string(alg_id) + ")";

src/v8/v8.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class V8 : public WasmVm {
105105
#undef _GET_MODULE_FUNCTION
106106

107107
void terminate() override;
108+
bool isWasmByteOrder() override { return true; }
108109

109110
private:
110111
wasm::own<wasm::Trap> trap(std::string message);
@@ -503,7 +504,7 @@ bool V8::getWord(uint64_t pointer, Word *word) {
503504
}
504505
uint32_t word32;
505506
::memcpy(&word32, memory_->data() + pointer, size);
506-
word->u64_ = wasmtoh(word32);
507+
word->u64_ = wasmtoh(word32, isWasmByteOrder());
507508
return true;
508509
}
509510

@@ -516,7 +517,7 @@ bool V8::setWord(uint64_t pointer, Word word) {
516517
if (pointer + size > memory_->data_size()) {
517518
return false;
518519
}
519-
uint32_t word32 = htowasm(word.u32());
520+
uint32_t word32 = htowasm(word.u32(), isWasmByteOrder());
520521
::memcpy(memory_->data() + pointer, &word32, size);
521522
return true;
522523
}

src/wamr/wamr.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class Wamr : public WasmVm {
8787
#undef _GET_MODULE_FUNCTION
8888

8989
void terminate() override {}
90+
bool isWasmByteOrder() override { return true; }
9091

9192
private:
9293
template <typename... Args>
@@ -368,7 +369,7 @@ bool Wamr::getWord(uint64_t pointer, Word *word) {
368369

369370
uint32_t word32;
370371
::memcpy(&word32, wasm_memory_data(memory_.get()) + pointer, size);
371-
word->u64_ = wasmtoh(word32);
372+
word->u64_ = wasmtoh(word32, isWasmByteOrder());
372373
return true;
373374
}
374375

@@ -377,7 +378,7 @@ bool Wamr::setWord(uint64_t pointer, Word word) {
377378
if (pointer + size > wasm_memory_data_size(memory_.get())) {
378379
return false;
379380
}
380-
uint32_t word32 = htowasm(word.u32());
381+
uint32_t word32 = htowasm(word.u32(), isWasmByteOrder());
381382
::memcpy(wasm_memory_data(memory_.get()) + pointer, &word32, size);
382383
return true;
383384
}

src/wasmedge/wasmedge.cc

+1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ class WasmEdge : public WasmVm {
281281
std::function<R(ContextBase *, Args...)> *function);
282282

283283
void terminate() override {}
284+
bool isWasmByteOrder() override { return true; }
284285

285286
WasmEdgeLoaderPtr loader_;
286287
WasmEdgeValidatorPtr validator_;

src/wasmtime/wasmtime.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class Wasmtime : public WasmVm {
9898
std::function<R(ContextBase *, Args...)> *function);
9999

100100
void terminate() override {}
101+
bool isWasmByteOrder() override { return true; }
101102

102103
WasmStorePtr store_;
103104
WasmModulePtr module_;
@@ -394,7 +395,7 @@ bool Wasmtime::getWord(uint64_t pointer, Word *word) {
394395

395396
uint32_t word32;
396397
::memcpy(&word32, wasm_memory_data(memory_.get()) + pointer, size);
397-
word->u64_ = wasmtoh(word32);
398+
word->u64_ = wasmtoh(word32, isWasmByteOrder());
398399
return true;
399400
}
400401

@@ -403,7 +404,7 @@ bool Wasmtime::setWord(uint64_t pointer, Word word) {
403404
if (pointer + size > wasm_memory_data_size(memory_.get())) {
404405
return false;
405406
}
406-
uint32_t word32 = htowasm(word.u32());
407+
uint32_t word32 = htowasm(word.u32(), isWasmByteOrder());
407408
::memcpy(wasm_memory_data(memory_.get()) + pointer, &word32, size);
408409
return true;
409410
}

src/wavm/wavm.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ struct Wavm : public WasmVm {
230230
#undef _REGISTER_CALLBACK
231231

232232
void terminate() override {}
233+
bool isWasmByteOrder() override { return true; }
233234

234235
IR::Module ir_module_;
235236
WAVM::Runtime::ModuleRef module_ = nullptr;
@@ -389,12 +390,12 @@ bool Wavm::getWord(uint64_t pointer, Word *data) {
389390
auto *p = reinterpret_cast<char *>(memory_base_ + pointer);
390391
uint32_t data32;
391392
memcpy(&data32, p, sizeof(uint32_t));
392-
data->u64_ = wasmtoh(data32);
393+
data->u64_ = wasmtoh(data32, isWasmByteOrder());
393394
return true;
394395
}
395396

396397
bool Wavm::setWord(uint64_t pointer, Word data) {
397-
uint32_t data32 = htowasm(data.u32());
398+
uint32_t data32 = htowasm(data.u32(), isWasmByteOrder());
398399
return setMemory(pointer, sizeof(uint32_t), &data32);
399400
}
400401

test/fuzz/pairs_util_fuzzer.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace {
2222
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
2323
auto input = std::string_view(reinterpret_cast<const char *>(data), size);
2424

25-
auto pairs = PairsUtil::toPairs(input);
25+
auto pairs = PairsUtil::toPairs(input, true);
2626

2727
if (!pairs.empty()) {
2828
// Verify that non-empty Pairs serializes back to the same bytes.
@@ -31,7 +31,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
3131
__builtin_trap();
3232
}
3333
std::vector<char> new_data(new_size);
34-
if (!PairsUtil::marshalPairs(pairs, new_data.data(), new_data.size())) {
34+
if (!PairsUtil::marshalPairs(pairs, new_data.data(), new_data.size(), true)) {
3535
__builtin_trap();
3636
}
3737
if (::memcmp(new_data.data(), data, size) != 0) {

test/null_vm_test.cc

+21
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "include/proxy-wasm/null.h"
1818
#include "include/proxy-wasm/null_vm_plugin.h"
19+
#include "include/proxy-wasm/pairs_util.h"
1920

2021
#include "gtest/gtest.h"
2122

@@ -73,4 +74,24 @@ TEST_F(BaseVmTest, NullVmStartup) {
7374
EXPECT_NE(test_null_vm_plugin, nullptr);
7475
}
7576

77+
TEST_F(BaseVmTest, ByteOrder) {
78+
auto wasm_vm = createNullVm();
79+
EXPECT_TRUE(wasm_vm->load("test_null_vm_plugin", {}, {}));
80+
EXPECT_FALSE(wasm_vm->isWasmByteOrder());
81+
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
82+
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
83+
proxy_wasm::Pairs pairs1;
84+
std::string data1("some_data");
85+
pairs1.push_back({data1.data(), std::to_string(data1.size())});
86+
std::vector<char> buffer(PairsUtil::pairsSize(pairs1));
87+
// encode using null_vm byte order
88+
EXPECT_TRUE(
89+
PairsUtil::marshalPairs(pairs1, buffer.data(), buffer.size(), wasm_vm->isWasmByteOrder()));
90+
// decode using host byte order
91+
auto pairs2 = PairsUtil::toPairs(std::string_view(buffer.data(), buffer.size()), false);
92+
EXPECT_EQ(pairs2.size(), pairs1.size());
93+
EXPECT_EQ(pairs2[0].second, pairs1[0].second);
94+
#endif
95+
}
96+
7697
} // namespace proxy_wasm

test/wasm_vm_test.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ TEST_P(TestVm, Memory) {
5353
ASSERT_TRUE(vm_->getWord(0x2000, &word));
5454
ASSERT_EQ(100, word.u64_);
5555

56-
uint32_t data[2] = {htowasm(static_cast<uint32_t>(-1)), htowasm(200)};
56+
uint32_t data[2] = {htowasm(static_cast<uint32_t>(-1), vm_->isWasmByteOrder()),
57+
htowasm(200, vm_->isWasmByteOrder())};
5758
ASSERT_TRUE(vm_->setMemory(0x200, sizeof(int32_t) * 2, static_cast<void *>(data)));
5859
ASSERT_TRUE(vm_->getWord(0x200, &word));
5960
ASSERT_EQ(-1, static_cast<int32_t>(word.u64_));

0 commit comments

Comments
 (0)