@@ -332,6 +332,7 @@ void TranslateToFuzzReader::build() {
332332 addHashMemorySupport ();
333333 }
334334 finalizeTable ();
335+ shuffleExports ();
335336}
336337
337338void TranslateToFuzzReader::setupMemory () {
@@ -746,6 +747,37 @@ void TranslateToFuzzReader::finalizeTable() {
746747 }
747748}
748749
750+ void TranslateToFuzzReader::shuffleExports () {
751+ // Randomly ordering the exports is useful for a few reasons. First, initial
752+ // content may have a natural order in which to execute things (an "init"
753+ // export first, for example), and changing that order may lead to very
754+ // different execution. Second, even in the fuzzer's own random content there
755+ // is a "direction", since we generate as we go (e.g. no function calls a
756+ // later function that does not exist yet / will be created later), and also
757+ // we emit invokes for a function right after it (so we end up calling the
758+ // same code several times in succession, but interleaving it with others may
759+ // find more things). But we also keep a good chance for the natural order
760+ // here, as it may help some initial content.
761+ if (wasm.exports .empty () || oneIn (2 )) {
762+ return ;
763+ }
764+
765+ // Sort the exports in the simple Fisher-Yates manner.
766+ // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
767+ for (Index i = 0 ; i < wasm.exports .size () - 1 ; i++) {
768+ // Pick the index of the item to place at index |i|. The number of items to
769+ // pick from begins at the full length, then decreases with i.
770+ auto j = i + upTo (wasm.exports .size () - i);
771+
772+ // Swap the item over here.
773+ if (j != i) {
774+ std::swap (wasm.exports [i], wasm.exports [j]);
775+ }
776+ }
777+
778+ wasm.updateMaps ();
779+ }
780+
749781void TranslateToFuzzReader::prepareHangLimitSupport () {
750782 HANG_LIMIT_GLOBAL = Names::getValidGlobalName (wasm, " hangLimit" );
751783}
0 commit comments