Print and compare prototypes in fuzzer interpreter#8457
Print and compare prototypes in fuzzer interpreter#8457
Conversation
GTO already handled keeping the prototype configuration fields on descriptors of types that flowed out to JS via @binaryen.js.called functions, but it did not handle propagating the information that a type flows out to JS to that type's subtypes. It also did not consider that types may flow out to JS via imports and exports. Fix these issues.
When a struct flows out to JS, if it has a descriptor and that desriptor's first field is an externref, that field's value becomes the JS prototype of the struct. There is a class of bugs where we misoptimize something in this setup so that the JS-observable prototype changes. To catch those bugs in the fuzzer, update the fuzzer interpreter and fuzz_shell.js to print the prototypes of objects. This lets the fuzzer make sure that engines like V8 and interpreter agree on whether there is a prototype. Also update the fuzzer interpreter to compare configured prototypes when comparing two execution traces. This lets --fuzz-exec detect when optimizations have changed a prototype.
| } | ||
| // The environment always sees externalized references and is able to | ||
| // observe the difference between external references and externalized | ||
| // internal references. Make sure this is accounted for below by unrapping |
There was a problem hiding this comment.
| // internal references. Make sure this is accounted for below by unrapping | |
| // internal references. Make sure this is accounted for below by unwrapping |
| std::ostream& operator<<(std::ostream& o, const WasmException& exn) { | ||
| auto exnData = exn.exn.getExnData(); | ||
| return o << exnData->tag->name << " " << exnData->payload; | ||
| } |
There was a problem hiding this comment.
This was only used in two places: wasm-ctor-eval and execution-results. The latter was updated to use its own printValue function to print exception payloads, so I just inlined this original method into the single remaining use site in wasm-ctor-eval.
| ;; CHECK-NEXT: [exception thrown: A [ref (type $array.0 (array (mut i32))) (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0[..])]] | ||
| ;; CHECK-NEXT: [exception thrown: A object(null)] | ||
| (func $array (export "array") (result (ref $A)) | ||
| ;; Throw a very large array. We should not print all 12K items in it, as that |
There was a problem hiding this comment.
Comment needs updating. But why is the new output better?
There was a problem hiding this comment.
The new output matches what will be printed by fuzz_shell.js. I figure that the less they differ, the simpler.
There was a problem hiding this comment.
It is simpler, yeah. We are losing something though, when the fuzzer compares its logging to itself after opts. See in fuzz_opt.py where we simplify the output for comparison reasons, e.g.
# funcref(0) has the index of the function in it, and optimizations can
# change that index, so ignore it
out = re.sub(r'funcref\([\d\w$+-_:]+\)', 'funcref()', out)I think we could do a similar thing for this?
There was a problem hiding this comment.
Yes, we could do something similar, but I think it's better not to. The input "fixing" is somewhat complex in the fuzzer, and bugs there can mean missing real bugs. I think it would be better to try to reduce the amount of fixing that happens in fuzz_opt.py. Also, I contend that if we ignore some difference in the fuzzer (and when comparing interpreter executions), then it's clearer if that difference doesn't show up in the textual log, either.
When a struct flows out to JS, if it has a descriptor and that desriptor's first field is an externref, that field's value becomes the JS prototype of the struct. There is a class of bugs where we misoptimize something in this setup so that the JS-observable prototype changes. To catch those bugs in the fuzzer, update the fuzzer interpreter and fuzz_shell.js to print the prototypes of objects. This lets the fuzzer make sure that engines like V8 and interpreter agree on whether there is a prototype. Also update the fuzzer interpreter to compare configured prototypes when comparing two execution traces. This lets --fuzz-exec detect when optimizations have changed a prototype.