summaryrefslogtreecommitdiff
path: root/src/ir/possible-contents.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-11-11 16:19:49 -0800
committerGitHub <noreply@github.com>2022-11-11 16:19:49 -0800
commit097e63a43b7681677ef54819b75d3c2bc756acce (patch)
treebe3acf44d6dfabce3b0e78ca6bdd596b2dfcd561 /src/ir/possible-contents.cpp
parentcf908c7976d02a9d3d4810a2b5a04e502e4efed2 (diff)
downloadbinaryen-097e63a43b7681677ef54819b75d3c2bc756acce.tar.gz
binaryen-097e63a43b7681677ef54819b75d3c2bc756acce.tar.bz2
binaryen-097e63a43b7681677ef54819b75d3c2bc756acce.zip
[Wasm GC] Fix nondeterminism in GUFA due to ordering (#5243)
We don't actually have the distributive property since our PossibleContents representation is an approximation, and the fuzzer found a case where that is noticeable. See more details in the new comment + testcase. I measured speed and memory usage and this actually causes almost no noticeable change.
Diffstat (limited to 'src/ir/possible-contents.cpp')
-rw-r--r--src/ir/possible-contents.cpp23
1 files changed, 13 insertions, 10 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index 35e87175a..d388d281c 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -22,13 +22,8 @@
#include "ir/local-graph.h"
#include "ir/module-utils.h"
#include "ir/possible-contents.h"
-#include "wasm.h"
-
-#ifdef POSSIBLE_CONTENTS_INSERT_ORDERED
-// Use an insert-ordered set for easier debugging with deterministic queue
-// ordering.
#include "support/insert_ordered.h"
-#endif
+#include "wasm.h"
namespace std {
@@ -1338,11 +1333,19 @@ private:
// possible is helpful as anything reading them meanwhile (before we get to
// their work item in the queue) will see the newer value, possibly avoiding
// flowing an old value that would later be overwritten.
-#ifdef POSSIBLE_CONTENTS_INSERT_ORDERED
+ //
+ // This must be ordered to avoid nondeterminism. The problem is that our
+ // operations are imprecise and so the transitive property does not hold:
+ // (AvB)vC may differ from Av(BvC). Likewise (AvB)^C may differ from
+ // (A^C)v(B^C). An example of the latter is if a location is sent a null func
+ // and an i31, and the location can only contain funcref. If the null func
+ // arrives first, then later we'd merge null func + i31 which ends up as Many,
+ // and then we filter that to funcref and get funcref. But if the i31 arrived
+ // first, we'd filter it into nothing, and then the null func that arrives
+ // later would be the final result. This would not happen if our operations
+ // were precise, but we only make approximations here to avoid unacceptable
+ // overhead, such as cone types but not arbitrary unions, etc.
InsertOrderedSet<LocationIndex> workQueue;
-#else
- std::unordered_set<LocationIndex> workQueue;
-#endif
// All existing links in the graph. We keep this to know when a link we want
// to add is new or not.