Skip to content

Commit 8f8bcc8

Browse files
authored
Extract common code from runtime implementations. (#152)
Signed-off-by: Takeshi Yoneda <[email protected]>
1 parent c81a554 commit 8f8bcc8

File tree

15 files changed

+556
-398
lines changed

15 files changed

+556
-398
lines changed

include/proxy-wasm/null_vm.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ struct NullVm : public WasmVm {
4444
bool setWord(uint64_t pointer, Word data) override;
4545
bool getWord(uint64_t pointer, Word *data) override;
4646
size_t getWordSize() override;
47-
std::string_view getCustomSection(std::string_view name) override;
4847
std::string_view getPrecompiledSectionName() override;
4948

5049
#define _FORWARD_GET_FUNCTION(_T) \

include/proxy-wasm/wasm_vm.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,6 @@ class WasmVm {
248248
*/
249249
virtual size_t getWordSize() = 0;
250250

251-
/**
252-
* Get the contents of the custom section with the given name or "" if it does not exist.
253-
* @param name the name of the custom section to get.
254-
* @return the contents of the custom section (if any). The result will be empty if there
255-
* is no such section.
256-
*/
257-
virtual std::string_view getCustomSection(std::string_view name) = 0;
258-
259251
/**
260252
* Get the name of the custom section that contains precompiled module.
261253
* @return the name of the custom section that contains precompiled module.

src/common/bytecode_util.cc

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "src/common/bytecode_util.h"
16+
#include <cstring>
17+
18+
namespace proxy_wasm {
19+
namespace common {
20+
21+
bool BytecodeUtil::checkWasmHeader(std::string_view bytecode) {
22+
// Wasm file header is 8 bytes (magic number + version).
23+
static const uint8_t wasm_magic_number[4] = {0x00, 0x61, 0x73, 0x6d};
24+
return bytecode.size() < 8 || !::memcmp(bytecode.data(), wasm_magic_number, 4);
25+
}
26+
27+
bool BytecodeUtil::getAbiVersion(std::string_view bytecode, proxy_wasm::AbiVersion &ret) {
28+
ret = proxy_wasm::AbiVersion::Unknown;
29+
// Check Wasm header.
30+
if (!checkWasmHeader(bytecode)) {
31+
return false;
32+
}
33+
34+
// Skip the Wasm header.
35+
const char *pos = bytecode.data() + 8;
36+
const char *end = bytecode.data() + bytecode.size();
37+
while (pos < end) {
38+
if (pos + 1 > end) {
39+
return false;
40+
}
41+
const auto section_type = *pos++;
42+
uint32_t section_len = 0;
43+
if (!parseVarint(pos, end, section_len) || pos + section_len > end) {
44+
return false;
45+
}
46+
if (section_type == 7 /* export section */) {
47+
uint32_t export_vector_size = 0;
48+
if (!parseVarint(pos, end, export_vector_size) || pos + export_vector_size > end) {
49+
return false;
50+
}
51+
// Search thourgh exports.
52+
for (uint32_t i = 0; i < export_vector_size; i++) {
53+
// Parse name of the export.
54+
uint32_t export_name_size = 0;
55+
if (!parseVarint(pos, end, export_name_size) || pos + export_name_size > end) {
56+
return false;
57+
}
58+
const auto name_begin = pos;
59+
pos += export_name_size;
60+
if (pos + 1 > end) {
61+
return false;
62+
}
63+
// Check if it is a function type export
64+
if (*pos++ == 0x00) {
65+
const std::string export_name = {name_begin, export_name_size};
66+
// Check the name of the function.
67+
if (export_name == "proxy_abi_version_0_1_0") {
68+
ret = AbiVersion::ProxyWasm_0_1_0;
69+
return true;
70+
} else if (export_name == "proxy_abi_version_0_2_0") {
71+
ret = AbiVersion::ProxyWasm_0_2_0;
72+
return true;
73+
} else if (export_name == "proxy_abi_version_0_2_1") {
74+
ret = AbiVersion::ProxyWasm_0_2_1;
75+
return true;
76+
}
77+
}
78+
// Skip export's index.
79+
if (!parseVarint(pos, end, export_name_size)) {
80+
return false;
81+
}
82+
}
83+
return true;
84+
} else {
85+
pos += section_len;
86+
}
87+
}
88+
return true;
89+
}
90+
91+
bool BytecodeUtil::getCustomSection(std::string_view bytecode, std::string_view name,
92+
std::string_view &ret) {
93+
// Check Wasm header.
94+
if (!checkWasmHeader(bytecode)) {
95+
return false;
96+
}
97+
98+
// Skip the Wasm header.
99+
const char *pos = bytecode.data() + 8;
100+
const char *end = bytecode.data() + bytecode.size();
101+
while (pos < end) {
102+
if (pos + 1 > end) {
103+
return false;
104+
}
105+
const auto section_type = *pos++;
106+
uint32_t section_len = 0;
107+
if (!parseVarint(pos, end, section_len) || pos + section_len > end) {
108+
return false;
109+
}
110+
if (section_type == 0) {
111+
// Custom section.
112+
const auto section_data_start = pos;
113+
uint32_t section_name_len = 0;
114+
if (!BytecodeUtil::parseVarint(pos, end, section_name_len) || pos + section_name_len > end) {
115+
return false;
116+
}
117+
if (section_name_len == name.size() && ::memcmp(pos, name.data(), section_name_len) == 0) {
118+
pos += section_name_len;
119+
ret = {pos, static_cast<size_t>(section_data_start + section_len - pos)};
120+
return true;
121+
}
122+
pos = section_data_start + section_len;
123+
} else {
124+
// Skip other sections.
125+
pos += section_len;
126+
}
127+
}
128+
return true;
129+
};
130+
131+
bool BytecodeUtil::getFunctionNameIndex(std::string_view bytecode,
132+
std::unordered_map<uint32_t, std::string> &ret) {
133+
std::string_view name_section = {};
134+
if (!BytecodeUtil::getCustomSection(bytecode, "name", name_section)) {
135+
return false;
136+
};
137+
if (!name_section.empty()) {
138+
const char *pos = name_section.data();
139+
const char *end = name_section.data() + name_section.size();
140+
while (pos < end) {
141+
const auto subsection_id = *pos++;
142+
uint32_t subsection_size = 0;
143+
if (!parseVarint(pos, end, subsection_size) || pos + subsection_size > end) {
144+
return false;
145+
}
146+
147+
if (subsection_id != 1) {
148+
// Skip other subsctions.
149+
pos += subsection_size;
150+
} else {
151+
// Enters function name subsection.
152+
const auto start = pos;
153+
uint32_t namemap_vector_size = 0;
154+
if (!parseVarint(pos, end, namemap_vector_size) || pos + namemap_vector_size > end) {
155+
return false;
156+
}
157+
for (uint32_t i = 0; i < namemap_vector_size; i++) {
158+
uint32_t func_index = 0;
159+
if (!parseVarint(pos, end, func_index)) {
160+
return false;
161+
}
162+
163+
uint32_t func_name_size = 0;
164+
if (!parseVarint(pos, end, func_name_size) || pos + func_name_size > end) {
165+
return false;
166+
}
167+
ret.insert({func_index, std::string(pos, func_name_size)});
168+
pos += func_name_size;
169+
}
170+
if (start + subsection_size != pos) {
171+
return false;
172+
}
173+
}
174+
}
175+
}
176+
return true;
177+
}
178+
179+
bool BytecodeUtil::getStrippedSource(std::string_view bytecode, std::string &ret) {
180+
// Check Wasm header.
181+
if (!checkWasmHeader(bytecode)) {
182+
return false;
183+
}
184+
185+
// Skip the Wasm header.
186+
const char *pos = bytecode.data() + 8;
187+
const char *end = bytecode.data() + bytecode.size();
188+
while (pos < end) {
189+
const auto section_start = pos;
190+
if (pos + 1 > end) {
191+
return false;
192+
}
193+
const auto section_type = *pos++;
194+
uint32_t section_len = 0;
195+
if (!parseVarint(pos, end, section_len) || pos + section_len > end) {
196+
return false;
197+
}
198+
if (section_type == 0 /* custom section */) {
199+
const auto section_data_start = pos;
200+
uint32_t section_name_len = 0;
201+
if (!parseVarint(pos, end, section_name_len) || pos + section_name_len > end) {
202+
return false;
203+
}
204+
auto section_name = std::string_view(pos, section_name_len);
205+
if (section_name.find("precompiled_") != std::string::npos) {
206+
// If this is the first "precompiled_" section, then save everything
207+
// before it, otherwise skip it.
208+
if (ret.empty()) {
209+
const char *start = bytecode.data();
210+
ret.append(start, section_start);
211+
}
212+
}
213+
pos = section_data_start + section_len;
214+
} else {
215+
pos += section_len;
216+
// Save this section if we already saw a custom "precompiled_" section.
217+
if (!ret.empty()) {
218+
ret.append(section_start, pos);
219+
}
220+
}
221+
}
222+
if (ret.empty()) {
223+
// Copy the original source code if it is empty.
224+
ret = std::string(bytecode);
225+
}
226+
return true;
227+
}
228+
229+
bool BytecodeUtil::parseVarint(const char *&pos, const char *end, uint32_t &ret) {
230+
uint32_t shift = 0;
231+
char b;
232+
do {
233+
if (pos + 1 > end) {
234+
return false;
235+
}
236+
b = *pos++;
237+
ret += (b & 0x7f) << shift;
238+
shift += 7;
239+
} while ((b & 0x80) != 0);
240+
return ret != static_cast<uint32_t>(-1);
241+
}
242+
243+
} // namespace common
244+
} // namespace proxy_wasm

src/common/bytecode_util.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
#pragma once
15+
16+
#include <string_view>
17+
#include <vector>
18+
#include <unordered_map>
19+
20+
#include "include/proxy-wasm/wasm_vm.h"
21+
22+
namespace proxy_wasm {
23+
namespace common {
24+
25+
// Utilitiy functions which directly operate on Wasm bytecodes.
26+
class BytecodeUtil {
27+
public:
28+
/**
29+
* checkWasmHeader validates Wasm header.
30+
* @param bytecode is the target bytecode.
31+
* @return indicates whether the bytecode has valid Wasm header.
32+
*/
33+
static bool checkWasmHeader(std::string_view bytecode);
34+
35+
/**
36+
* getAbiVersion extracts ABI version from the bytecode.
37+
* @param bytecode is the target bytecode.
38+
* @param ret is the reference to store the extracted ABI version or UnKnown if it doesn't exist.
39+
* @return indicates whether parsing succeeded or not.
40+
*/
41+
static bool getAbiVersion(std::string_view bytecode, proxy_wasm::AbiVersion &ret);
42+
43+
/**
44+
* getCustomSection extract the view of the custom section for a given name.
45+
* @param bytecode is the target bytecode.
46+
* @param name is the name of the custom section.
47+
* @param ret is the reference to store the resulting view to the custom section.
48+
* @return indicates whether parsing succeeded or not.
49+
*/
50+
static bool getCustomSection(std::string_view bytecode, std::string_view name,
51+
std::string_view &ret);
52+
53+
/**
54+
* getFunctionNameIndex constructs the map from function indexes to function names stored in
55+
* the function name subsection in "name" custom section.
56+
* See https://webassembly.github.io/spec/core/appendix/custom.html#binary-funcnamesec for detail.
57+
* @param bytecode is the target bytecode.
58+
* @param ret is the reference to store map from function indexes to function names.
59+
* @return indicates whether parsing succeeded or not.
60+
*/
61+
static bool getFunctionNameIndex(std::string_view bytecode,
62+
std::unordered_map<uint32_t, std::string> &ret);
63+
64+
/**
65+
* getStrippedSource gets Wasm module without Custom Sections to save some memory in workers.
66+
* @param bytecode is the original bytecode.
67+
* @param ret is the reference to the stripped bytecode or a copy of the original bytecode.
68+
* @return indicates whether parsing succeeded or not.
69+
*/
70+
static bool getStrippedSource(std::string_view bytecode, std::string &ret);
71+
72+
private:
73+
static bool parseVarint(const char *&begin, const char *end, uint32_t &ret);
74+
};
75+
76+
} // namespace common
77+
} // namespace proxy_wasm

src/null/null_vm.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,6 @@ bool NullVm::getWord(uint64_t pointer, Word *data) {
104104

105105
size_t NullVm::getWordSize() { return sizeof(uint64_t); }
106106

107-
std::string_view NullVm::getCustomSection(std::string_view /* name */) {
108-
// Return nothing: there is no WASM file.
109-
return {};
110-
}
111-
112107
std::string_view NullVm::getPrecompiledSectionName() {
113108
// Return nothing: there is no WASM file.
114109
return {};

0 commit comments

Comments
 (0)