Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 0 additions & 71 deletions scripts/fuzz_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1071,76 +1071,6 @@ def can_run_on_feature_opts(self, feature_opts):
return all_disallowed(['exception-handling', 'simd', 'threads', 'bulk-memory', 'nontrapping-float-to-int', 'tail-call', 'sign-ext', 'reference-types', 'multivalue', 'gc', 'multimemory'])


class Asyncify(TestCaseHandler):
frequency = 0.1

def handle_pair(self, input, before_wasm, after_wasm, opts):
# we must legalize in order to run in JS
async_before_wasm = abspath('async.' + os.path.basename(before_wasm))
async_after_wasm = abspath('async.' + os.path.basename(after_wasm))
run([in_bin('wasm-opt'), before_wasm, '--legalize-js-interface', '-o', async_before_wasm] + FEATURE_OPTS)
run([in_bin('wasm-opt'), after_wasm, '--legalize-js-interface', '-o', async_after_wasm] + FEATURE_OPTS)
before_wasm = async_before_wasm
after_wasm = async_after_wasm
before = fix_output(run_d8_wasm(before_wasm))
after = fix_output(run_d8_wasm(after_wasm))

if STACK_LIMIT in run_bynterp(before_wasm, ['--fuzz-exec-before']):
# Running out of stack in infinite recursion can be a problem here
# as we compare a wasm before and after asyncify, and asyncify can
# add a lot of locals, which could mean the host limit can be
# reached earlier, and alter the output (less logging before we
# reach the host limit and trap).
# TODO This is not quite enough, as if we are just under the limit
# then we may only hit the limit after running asyncify. But
# then we'd also need to detect differences in the limit in
# the JS VM's output (which can differ from Binaryen's). For
# now, this rules out infinite recursion at least.
print('ignoring due to stack limit being hit')
return

try:
compare(before, after, 'Asyncify (before/after)')
except Exception:
# if we failed to just compare the builds before asyncify even runs,
# then it may use NaNs or be sensitive to legalization; ignore it
print('ignoring due to pre-asyncify difference')
return

def do_asyncify(wasm):
cmd = [in_bin('wasm-opt'), wasm, '--asyncify', '-o', abspath('async.t.wasm')]
# if we allow NaNs, running binaryen optimizations and then
# executing in d8 may lead to different results due to NaN
# nondeterminism between VMs.
if not NANS:
if random.random() < 0.5:
cmd += ['--optimize-level=%d' % random.randint(1, 3)]
if random.random() < 0.5:
cmd += ['--shrink-level=%d' % random.randint(1, 2)]
cmd += FEATURE_OPTS
run(cmd)
out = run_d8_wasm(abspath('async.t.wasm'))
# ignore the output from the new asyncify API calls - the ones with asserts will trap, too
for ignore in ['[fuzz-exec] calling asyncify_start_unwind\nexception!\n',
'[fuzz-exec] calling asyncify_start_unwind\n',
'[fuzz-exec] calling asyncify_start_rewind\nexception!\n',
'[fuzz-exec] calling asyncify_start_rewind\n',
'[fuzz-exec] calling asyncify_stop_rewind\n',
'[fuzz-exec] calling asyncify_stop_unwind\n']:
out = out.replace(ignore, '')
out = '\n'.join([l for l in out.splitlines() if 'asyncify: ' not in l])
return fix_output(out)

before_asyncify = do_asyncify(before_wasm)
after_asyncify = do_asyncify(after_wasm)

compare(before, before_asyncify, 'Asyncify (before/before_asyncify)')
compare(before, after_asyncify, 'Asyncify (before/after_asyncify)')

def can_run_on_feature_opts(self, feature_opts):
return all_disallowed(['exception-handling', 'simd', 'tail-call', 'reference-types', 'multivalue', 'gc', 'multimemory'])


# given a wasm and a list of exports we want to keep, remove all other exports.
def filter_exports(wasm, output, keep):
# based on
Expand Down Expand Up @@ -1373,7 +1303,6 @@ def handle(self, wasm):
CompareVMs(),
CheckDeterminism(),
Wasm2JS(),
Asyncify(),
TrapsNeverHappen(),
CtorEval(),
Merge(),
Expand Down
123 changes: 0 additions & 123 deletions scripts/fuzz_shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,119 +38,6 @@ var detrand = (function() {
};
})();

// Asyncify integration.
var Asyncify = {
sleeping: false,
sleepingFunction: null,
sleeps: 0,
maxDepth: 0,
DATA_ADDR: 4,
// The fuzzer emits memories of size 16 (pages). Allow us to use almost all of
// that (we start from offset 4, so we can't use them all).
DATA_MAX: 15 * 65536,
savedMemory: null,
instrumentImports: function(imports) {
var ret = {};
for (var module in imports) {
ret[module] = {};
for (var i in imports[module]) {
if (typeof imports[module][i] === 'function') {
(function(module, i) {
ret[module][i] = function() {
refreshView();
if (!Asyncify.sleeping) {
// Sleep if asyncify support is present (which also requires
// that the memory be exported), and at a certain probability.
if (exports.asyncify_start_unwind &&
view &&
detrand() < 0.5) {
// We are called in order to start a sleep/unwind.
console.log('asyncify: sleep in ' + i + '...');
Asyncify.sleepingFunction = i;
Asyncify.sleeps++;
var depth = new Error().stack.split('\n').length - 6;
Asyncify.maxDepth = Math.max(Asyncify.maxDepth, depth);
// Save the memory we use for data, so after we restore it later, the
// sleep/resume appears to have had no change to memory.
Asyncify.savedMemory = new Int32Array(view.subarray(Asyncify.DATA_ADDR >> 2, Asyncify.DATA_MAX >> 2));
// Unwinding.
// Fill in the data structure. The first value has the stack location,
// which for simplicity we can start right after the data structure itself.
view[Asyncify.DATA_ADDR >> 2] = Asyncify.DATA_ADDR + 8;
// The end of the stack will not be reached here anyhow.
view[Asyncify.DATA_ADDR + 4 >> 2] = Asyncify.DATA_MAX;
exports.asyncify_start_unwind(Asyncify.DATA_ADDR);
Asyncify.sleeping = true;
} else {
// Don't sleep, normal execution.
return imports[module][i].apply(null, arguments);
}
} else {
// We are called as part of a resume/rewind. Stop sleeping.
console.log('asyncify: resume in ' + i + '...');
assert(Asyncify.sleepingFunction === i);
exports.asyncify_stop_rewind();
// The stack should have been all used up, and so returned to the original state.
assert(view[Asyncify.DATA_ADDR >> 2] == Asyncify.DATA_ADDR + 8);
assert(view[Asyncify.DATA_ADDR + 4 >> 2] == Asyncify.DATA_MAX);
Asyncify.sleeping = false;
// Restore the memory to the state from before we slept.
view.set(Asyncify.savedMemory, Asyncify.DATA_ADDR >> 2);
return imports[module][i].apply(null, arguments);
}
};
})(module, i);
} else {
ret[module][i] = imports[module][i];
}
}
}
// Add ignored.print, which is ignored by asyncify, and allows debugging of asyncified code.
ret['ignored'] = { 'print': function(x, y) { console.log(x, y) } };
return ret;
},
instrumentExports: function(exports) {
var ret = {};
for (var e in exports) {
if (typeof exports[e] === 'function' &&
!e.startsWith('asyncify_')) {
(function(e) {
ret[e] = function() {
while (1) {
var ret = exports[e].apply(null, arguments);
// If we are sleeping, then the stack was unwound; rewind it.
if (Asyncify.sleeping) {
console.log('asyncify: stop unwind; rewind');
assert(!ret, 'results during sleep are meaningless, just 0');
//console.log('asyncify: after unwind', view[Asyncify.DATA_ADDR >> 2], view[Asyncify.DATA_ADDR + 4 >> 2]);
try {
exports.asyncify_stop_unwind();
exports.asyncify_start_rewind(Asyncify.DATA_ADDR);
} catch (e) {
console.log('error in unwind/rewind switch', e);
}
continue;
}
return ret;
}
};
})(e);
} else {
ret[e] = exports[e];
}
}
return ret;
},
check: function() {
assert(!Asyncify.sleeping);
},
finish: function() {
if (Asyncify.sleeps > 0) {
print('asyncify:', 'sleeps:', Asyncify.sleeps, 'max depth:', Asyncify.maxDepth);
}
},
};

// Fuzz integration.
function logValue(x, y) {
if (typeof y !== 'undefined') {
Expand Down Expand Up @@ -183,8 +70,6 @@ if (typeof WebAssembly.Tag !== 'undefined') {
};
}

imports = Asyncify.instrumentImports(imports);

// Create the wasm.
var module = new WebAssembly.Module(binary);

Expand All @@ -198,7 +83,6 @@ try {

// Handle the exports.
var exports = instance.exports;
exports = Asyncify.instrumentExports(exports);

var view;

Expand All @@ -215,12 +99,7 @@ for (var e in exports) {
sortedExports.push(e);
}
sortedExports.sort();
sortedExports = sortedExports.filter(function(e) {
// Filter special intrinsic functions.
return !e.startsWith('asyncify_');
});
sortedExports.forEach(function(e) {
Asyncify.check();
if (typeof exports[e] !== 'function') return;
try {
console.log('[fuzz-exec] calling ' + e);
Expand All @@ -233,5 +112,3 @@ sortedExports.forEach(function(e) {
}
});

// Finish up
Asyncify.finish();