-
Notifications
You must be signed in to change notification settings - Fork 830
Fuzzer mutation: Use GLB to find the type to replace with #8100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| /* | ||
| * Copyright 2025 WebAssembly Community Group participants | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #ifndef wasm_ir_glbs_h | ||
| #define wasm_ir_glbs_h | ||
|
|
||
| #include "ir/module-utils.h" | ||
| #include "wasm.h" | ||
|
|
||
| namespace wasm { | ||
|
|
||
| // | ||
| // Similar to LUBFinder, but for GLBs. | ||
| // | ||
| struct GLBFinder { | ||
| GLBFinder() {} | ||
|
|
||
| GLBFinder(Type initialType) { note(initialType); } | ||
|
|
||
| // Note another type to take into account in the GLB. | ||
| void note(Type type) { | ||
| // We only compute GLBs of concrete types in our IR. | ||
| assert(type != Type::none); | ||
|
|
||
| if (type != Type::unreachable) { | ||
| if (glb == Type::unreachable) { | ||
| // This is the first thing we see. | ||
| glb = type; | ||
| } else { | ||
| glb = Type::getGreatestLowerBound(glb, type); | ||
| // If the result is unreachable, when neither of the inputs was, then we | ||
| // have combined things from different hierarchies, which we do not | ||
| // allow here: We focus on computing GLBs for concrete places in our IR. | ||
| assert(glb != Type::unreachable); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Returns whether we noted any (reachable) value. | ||
| bool noted() { return glb != Type::unreachable; } | ||
|
|
||
| // Returns the GLB. | ||
| Type getGLB() { return glb; } | ||
|
|
||
| // Combines the information in another GLBFinder into this one, and returns | ||
| // whether we changed anything. | ||
| bool combine(const GLBFinder& other) { | ||
| // Check if the GLB was changed. | ||
| auto old = glb; | ||
| note(other.glb); | ||
| return old != glb; | ||
| } | ||
|
|
||
| private: | ||
| // The greatest lower bound. As we go this always contains the latest value | ||
| // based on everything we've seen so far. | ||
| Type glb = Type::unreachable; | ||
| }; | ||
|
|
||
| } // namespace wasm | ||
|
|
||
| #endif // wasm_ir_glbs_h | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| /* | ||
| * Copyright 2025 WebAssembly Community Group participants | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #include "ir/glbs.h" | ||
| #include "wasm-type.h" | ||
| #include "wasm.h" | ||
| #include "gtest/gtest.h" | ||
|
|
||
| using namespace wasm; | ||
|
|
||
| TEST(GLBsTest, Basics) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be good to test the edge cases around
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added testing for one corner case, and assertions for others that it seems better to just disallow as invalid. |
||
| GLBFinder finder; | ||
|
|
||
| // Nothing noted yet. | ||
| EXPECT_FALSE(finder.noted()); | ||
| EXPECT_EQ(finder.getGLB(), Type::unreachable); | ||
|
|
||
| // Note a type. | ||
| Type anyref = Type(HeapType::any, Nullable); | ||
| finder.note(anyref); | ||
| EXPECT_TRUE(finder.noted()); | ||
| EXPECT_EQ(finder.getGLB(), anyref); | ||
|
|
||
| // Note another, leaving the more-refined GLB. | ||
| Type refAny = Type(HeapType::any, NonNullable); | ||
| finder.note(refAny); | ||
| EXPECT_TRUE(finder.noted()); | ||
| EXPECT_EQ(finder.getGLB(), refAny); | ||
|
|
||
| // Note unreachable, which changes nothing (we ignore unreachable inputs). | ||
| finder.note(Type::unreachable); | ||
| EXPECT_EQ(finder.getGLB(), refAny); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use
Type::noneas the initial value, since it behaves very similarly to a top type whereasType::unreachableis the bottom type. (This still requires some special casing, sinceType::getGLBdoes not treatType::noneas top; we should consider fixing that to makeType::getLUBandType::getGLBmore consistent with each other.)Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unreachable happens to be the bottom type in the lattice, but in this API, unreachable is the "uninitialized / we have seen no reachable data yet" marker. We ignore inputs of unreachable, and we start in that state.
That is, we want to ignore unreachable data - it does not constrain us - so
GLBFinder.note(unreachable)should do nothing, not turn us into the bottom.Avoiding that is consistent with LUBFinder and seems like the most intuitive API here to me.
(For similar reasons, using ValType's meet would be more work here, I found as I tried that now.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the GLB/meet of any type t with bottom (i.e. unreachable) is t, so you should get the "ignore unreachable" behavior for free, right? All you have to do is use
noneas the "uninitialized / we have seen no reachable data yet" marker.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, isn't it the opposite? Meet refines, towards the bottom, using the GLB. So the GLB/meet of any type t with bottom (i.e unreachable) is bottom (unreachable).
Here is that in the code:
binaryen/src/wasm/wasm-type.cpp
Lines 808 to 810 in 8e5f757
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, I was confused.