Skip to content

Commit 13a3f34

Browse files
committed
Generate Struct RMW operations in the fuzzer
And allow fuzzing of initial contents that contain these operations.
1 parent df5c0e0 commit 13a3f34

3 files changed

Lines changed: 74 additions & 18 deletions

File tree

scripts/test/fuzzing.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,6 @@
7070
# the fuzzer does not support imported memories
7171
'multi-memory-lowering-import.wast',
7272
'multi-memory-lowering-import-error.wast',
73-
# the fuzzer does not support struct RMW ops
74-
'gc-atomics.wast',
75-
'gc-atomics-null-refs.wast',
76-
'shared-structs.wast',
77-
'heap2local-rmw.wast',
78-
'optimize-instructions-struct-rmw.wast',
79-
'gto-removals-rmw.wast',
80-
'type-refining-rmw.wast',
81-
'type-ssa-exact-rmw.wast',
82-
'cfp-rmw.wast',
83-
'unsubtyping-cmpxchg.wast',
84-
'struct-atomic-threads.wast',
85-
'type-refining-gufa-rmw.wast',
86-
'struct-cmpxchg-shared-expected.wast',
87-
'precompute-gc-atomics-rmw.wast',
8873
# contains too many segments to run in a wasm VM
8974
'limit-segments_disable-bulk-memory.wast',
9075
# https://github.com/WebAssembly/binaryen/issues/7176

src/tools/fuzzing.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,8 @@ class TranslateToFuzzReader {
540540
bool maybeSignedGet(const Field& field);
541541

542542
Expression* makeStructGet(Type type);
543+
Expression* makeStructRMW(Type type);
544+
Expression* makeStructCmpxchg(Type type);
543545
Expression* makeStructSet(Type type);
544546
Expression* makeArrayGet(Type type);
545547
Expression* makeArraySet(Type type);

src/tools/fuzzing/fuzzing.cpp

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,6 +2598,12 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
25982598
if (typeStructFields.find(type) != typeStructFields.end()) {
25992599
options.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
26002600
&Self::makeStructGet);
2601+
options.add(FeatureSet::ReferenceTypes | FeatureSet::GC |
2602+
FeatureSet::Atomics | FeatureSet::SharedEverything,
2603+
&Self::makeStructRMW);
2604+
options.add(FeatureSet::ReferenceTypes | FeatureSet::GC |
2605+
FeatureSet::Atomics | FeatureSet::SharedEverything,
2606+
&Self::makeStructCmpxchg);
26012607
}
26022608
if (typeArrays.find(type) != typeArrays.end()) {
26032609
options.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
@@ -5583,8 +5589,66 @@ Expression* TranslateToFuzzReader::makeStructGet(Type type) {
55835589
auto [structType, fieldIndex] = pick(structFields);
55845590
auto* ref = makeTrappingRefUse(structType);
55855591
auto signed_ = maybeSignedGet(structType.getStruct().fields[fieldIndex]);
5586-
return builder.makeStructGet(
5587-
fieldIndex, ref, MemoryOrder::Unordered, type, signed_);
5592+
auto order = MemoryOrder::Unordered;
5593+
if (wasm.features.hasAtomics() && wasm.features.hasSharedEverything() &&
5594+
oneIn(2)) {
5595+
order = oneIn(2) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5596+
}
5597+
return builder.makeStructGet(fieldIndex, ref, order, type, signed_);
5598+
}
5599+
5600+
Expression* TranslateToFuzzReader::makeStructRMW(Type type) {
5601+
bool isAny =
5602+
type.isRef() &&
5603+
Type::isSubType(
5604+
type,
5605+
Type(HeapTypes::any.getBasic(type.getHeapType().getShared()), Nullable));
5606+
if (type != Type::i32 && type != Type::i64 && !isAny) {
5607+
// Not a valid field type for an RMW operation.
5608+
return makeStructGet(type);
5609+
}
5610+
auto& structFields = typeStructFields[type];
5611+
assert(!structFields.empty());
5612+
auto [structType, fieldIndex] = pick(structFields);
5613+
const auto& field = structType.getStruct().fields[fieldIndex];
5614+
if (field.isPacked() || field.mutable_ == Immutable) {
5615+
// Cannot RMW a packed or immutable field.
5616+
return makeStructGet(type);
5617+
}
5618+
AtomicRMWOp op = RMWXchg;
5619+
if (type == Type::i32 || type == Type::i64) {
5620+
op = pick(RMWAdd, RMWSub, RMWAnd, RMWOr, RMWXor, RMWXchg);
5621+
}
5622+
auto* ref = makeTrappingRefUse(structType);
5623+
auto* value = make(type);
5624+
auto order = oneIn(2) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5625+
return builder.makeStructRMW(op, fieldIndex, ref, value, order);
5626+
}
5627+
5628+
Expression* TranslateToFuzzReader::makeStructCmpxchg(Type type) {
5629+
bool isEq =
5630+
type.isRef() &&
5631+
Type::isSubType(
5632+
type,
5633+
Type(HeapTypes::eq.getBasic(type.getHeapType().getShared()), Nullable));
5634+
if (type != Type::i32 && type != Type::i64 && !isEq) {
5635+
// Not a valid field type for a cmpxchg operation.
5636+
return makeStructGet(type);
5637+
}
5638+
auto& structFields = typeStructFields[type];
5639+
assert(!structFields.empty());
5640+
auto [structType, fieldIndex] = pick(structFields);
5641+
const auto& field = structType.getStruct().fields[fieldIndex];
5642+
if (field.isPacked() || field.mutable_ == Immutable) {
5643+
// Cannot RMW a packed or immutable field.
5644+
return makeStructGet(type);
5645+
}
5646+
auto* ref = makeTrappingRefUse(structType);
5647+
auto* expected = make(type);
5648+
auto* replacement = make(type);
5649+
auto order = oneIn(2) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5650+
return builder.makeStructCmpxchg(
5651+
fieldIndex, ref, expected, replacement, order);
55885652
}
55895653

55905654
Expression* TranslateToFuzzReader::makeStructSet(Type type) {
@@ -5596,7 +5660,12 @@ Expression* TranslateToFuzzReader::makeStructSet(Type type) {
55965660
auto fieldType = structType.getStruct().fields[fieldIndex].type;
55975661
auto* ref = makeTrappingRefUse(structType);
55985662
auto* value = make(fieldType);
5599-
return builder.makeStructSet(fieldIndex, ref, value, MemoryOrder::Unordered);
5663+
auto order = MemoryOrder::Unordered;
5664+
if (wasm.features.hasAtomics() && wasm.features.hasSharedEverything() &&
5665+
oneIn(2)) {
5666+
order = oneIn(2) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5667+
}
5668+
return builder.makeStructSet(fieldIndex, ref, value, order);
56005669
}
56015670

56025671
// Make a bounds check for an array operation, given a ref + index. An optional

0 commit comments

Comments
 (0)