Skip to content

Commit 1095ef9

Browse files
authored
Add a fuzzer option to not emit code with OOB loads/indirect calls (#2113)
This is useful for wasm2js, as we don't emit traps for OOB loads etc. like wasm (like we don't trap on bad float-to-int, as it's too hard in JS, and it's undefined behavior in C anyhow). It may also help general fuzzing, as those traps may make other interesting patterns less likely. Also add more wasm2js support in the fuzzer, which includes using this no-OOB option.
1 parent 1dd37de commit 1095ef9

3 files changed

Lines changed: 29 additions & 4 deletions

File tree

scripts/fuzz_opt.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848

4949
LOG_LIMIT = 125
5050

51+
WASM2JS = False
52+
5153

5254
# utilities
5355

@@ -145,7 +147,10 @@ def run_bynterp(wasm):
145147

146148
def run_wasm2js(wasm):
147149
wrapper = run([in_bin('wasm-opt'), wasm, '--emit-js-wrapper=/dev/stdout'] + FEATURE_OPTS)
148-
main = run([in_bin('wasm2js'), wasm, '--emscripten'] + FEATURE_OPTS)
150+
cmd = [in_bin('wasm2js'), wasm, '--emscripten']
151+
if random.random() < 0.5:
152+
cmd += ['-O']
153+
main = run(cmd + FEATURE_OPTS)
149154
with open(os.path.join(options.binaryen_root, 'scripts', 'wasm2js.js')) as f:
150155
glue = f.read()
151156
with open('js.js', 'w') as f:
@@ -164,7 +169,8 @@ def run_vms(prefix):
164169
results = []
165170
results.append(run_bynterp(wasm))
166171
results.append(fix_output(run_vm([os.path.expanduser('d8'), prefix + 'js'] + V8_OPTS + ['--', wasm])))
167-
# results.append(run_wasm2js(wasm))
172+
if WASM2JS:
173+
results.append(run_wasm2js(wasm))
168174

169175
# append to add results from VMs
170176
# results += [fix_output(run_vm([os.path.expanduser('d8'), prefix + 'js'] + V8_OPTS + ['--', prefix + 'wasm']))]
@@ -292,6 +298,12 @@ def get_multiple_opt_choices():
292298
if not NANS:
293299
FUZZ_OPTS += ['--no-fuzz-nans']
294300

301+
if WASM2JS:
302+
# wasm2js does not handle nans precisely, and does not
303+
# handle oob loads etc. with traps
304+
FUZZ_OPTS += ['--no-fuzz-nans']
305+
FUZZ_OPTS += ['--no-fuzz-oob']
306+
295307
if __name__ == '__main__':
296308
print('checking infinite random inputs')
297309
random.seed(time.time() * os.getpid())

src/tools/fuzzing.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ class TranslateToFuzzReader {
189189

190190
void setAllowMemory(bool allowMemory_) { allowMemory = allowMemory_; }
191191

192+
void setAllowOOB(bool allowOOB_) { allowOOB = allowOOB_; }
193+
192194
void build() {
193195
if (allowMemory) {
194196
setupMemory();
@@ -252,6 +254,10 @@ class TranslateToFuzzReader {
252254
// Whether to emit memory operations like loads and stores.
253255
bool allowMemory = true;
254256

257+
// Whether to emit loads, stores, and call_indirects that may be out
258+
// of bounds (which traps in wasm, and is undefined behavior in C).
259+
bool allowOOB = true;
260+
255261
// Whether to emit atomic waits (which in single-threaded mode, may hang...)
256262
static const bool ATOMIC_WAITS = false;
257263

@@ -1212,7 +1218,7 @@ class TranslateToFuzzReader {
12121218
// with high probability, make sure the type is valid otherwise, most are
12131219
// going to trap
12141220
Expression* target;
1215-
if (!oneIn(10)) {
1221+
if (!allowOOB || !oneIn(10)) {
12161222
target = builder.makeConst(Literal(int32_t(i)));
12171223
} else {
12181224
target = make(i32);
@@ -1277,7 +1283,7 @@ class TranslateToFuzzReader {
12771283
// with high probability, mask the pointer so it's in a reasonable
12781284
// range. otherwise, most pointers are going to be out of range and
12791285
// most memory ops will just trap
1280-
if (!oneIn(10)) {
1286+
if (!allowOOB || !oneIn(10)) {
12811287
ret = builder.makeBinary(
12821288
AndInt32, ret, builder.makeConst(Literal(int32_t(USABLE_MEMORY - 1))));
12831289
}

src/tools/wasm-opt.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ int main(int argc, const char* argv[]) {
7373
bool fuzzPasses = false;
7474
bool fuzzNaNs = true;
7575
bool fuzzMemory = true;
76+
bool fuzzOOB = true;
7677
std::string emitJSWrapper;
7778
std::string emitSpecWrapper;
7879
std::string inputSourceMapFilename;
@@ -157,6 +158,11 @@ int main(int argc, const char* argv[]) {
157158
"don't emit memory ops when fuzzing",
158159
Options::Arguments::Zero,
159160
[&](Options* o, const std::string& arguments) { fuzzMemory = false; })
161+
.add("--no-fuzz-oob",
162+
"",
163+
"don't emit out-of-bounds loads/stores/indirect calls when fuzzing",
164+
Options::Arguments::Zero,
165+
[&](Options* o, const std::string& arguments) { fuzzOOB = false; })
160166
.add("--emit-js-wrapper",
161167
"-ejw",
162168
"Emit a JavaScript wrapper file that can run the wasm with some test "
@@ -242,6 +248,7 @@ int main(int argc, const char* argv[]) {
242248
}
243249
reader.setAllowNaNs(fuzzNaNs);
244250
reader.setAllowMemory(fuzzMemory);
251+
reader.setAllowOOB(fuzzOOB);
245252
reader.build();
246253
if (options.passOptions.validate) {
247254
if (!WasmValidator().validate(wasm)) {

0 commit comments

Comments
 (0)