Skip to content

Commit 5898877

Browse files
authored
Fuzzer: Add cross-module global usage (#7970)
* Export some globals. * Import some globals. * Move some code around to enable this.
1 parent 0ccf280 commit 5898877

File tree

5 files changed

+181
-122
lines changed

5 files changed

+181
-122
lines changed

src/tools/fuzzing.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,7 @@ class TranslateToFuzzReader {
132132
void setPreserveImportsAndExports(bool preserveImportsAndExports_) {
133133
preserveImportsAndExports = preserveImportsAndExports_;
134134
}
135-
void setImportedModule(std::string importedModule_) {
136-
importedModule = importedModule_;
137-
}
135+
void setImportedModule(std::string importedModuleName);
138136

139137
void build();
140138

@@ -161,7 +159,7 @@ class TranslateToFuzzReader {
161159
bool preserveImportsAndExports = false;
162160

163161
// An optional module to import from.
164-
std::optional<std::string> importedModule;
162+
std::optional<Module> importedModule;
165163

166164
// Whether we allow the fuzzer to add unreachable code when generating changes
167165
// to existing code. This is randomized during startup, but could be an option
@@ -371,7 +369,8 @@ class TranslateToFuzzReader {
371369

372370
void addHangLimitChecks(Function* func);
373371

374-
void useImportedModule();
372+
void useImportedFunctions();
373+
void useImportedGlobals();
375374

376375
// Recombination and mutation
377376

@@ -396,6 +395,9 @@ class TranslateToFuzzReader {
396395
void fixAfterChanges(Function* func);
397396
void modifyInitialFunctions();
398397

398+
// Note a global for use during code generation.
399+
void useGlobalLater(Global* global);
400+
399401
// Initial wasm contents may have come from a test that uses the drop pattern:
400402
//
401403
// (drop ..something interesting..)

src/tools/fuzzing/fuzzing.cpp

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ void TranslateToFuzzReader::build() {
352352
setupHeapTypes();
353353
setupTables();
354354
setupGlobals();
355+
useImportedGlobals();
355356
if (wasm.features.hasExceptionHandling()) {
356357
setupTags();
357358
addImportThrowingSupport();
@@ -366,7 +367,7 @@ void TranslateToFuzzReader::build() {
366367
// First, modify initial functions. That includes removing imports. Then,
367368
// use the imported module, which are function imports that we allow.
368369
modifyInitialFunctions();
369-
useImportedModule();
370+
useImportedFunctions();
370371

371372
processFunctions();
372373
if (fuzzParams->HANG_LIMIT > 0) {
@@ -625,6 +626,20 @@ void TranslateToFuzzReader::setupTables() {
625626
}
626627
}
627628

629+
void TranslateToFuzzReader::useGlobalLater(Global* global) {
630+
auto type = global->type;
631+
auto name = global->name;
632+
globalsByType[type].push_back(name);
633+
if (global->mutable_) {
634+
mutableGlobalsByType[type].push_back(name);
635+
} else {
636+
immutableGlobalsByType[type].push_back(name);
637+
if (global->imported()) {
638+
importedImmutableGlobalsByType[type].push_back(name);
639+
}
640+
}
641+
}
642+
628643
void TranslateToFuzzReader::setupGlobals() {
629644
// If there were initial wasm contents, there may be imported globals. That
630645
// would be a problem in the fuzzer harness as we'd error if we do not
@@ -651,20 +666,6 @@ void TranslateToFuzzReader::setupGlobals() {
651666
}
652667
}
653668

654-
auto useGlobalLater = [&](Global* global) {
655-
auto type = global->type;
656-
auto name = global->name;
657-
globalsByType[type].push_back(name);
658-
if (global->mutable_) {
659-
mutableGlobalsByType[type].push_back(name);
660-
} else {
661-
immutableGlobalsByType[type].push_back(name);
662-
if (global->imported()) {
663-
importedImmutableGlobalsByType[type].push_back(name);
664-
}
665-
}
666-
};
667-
668669
// Randomly assign some globals from initial content to be ignored for the
669670
// fuzzer to use. Such globals will only be used from initial content. This is
670671
// important to preserve some real-world patterns, like the "once" pattern in
@@ -712,9 +713,23 @@ void TranslateToFuzzReader::setupGlobals() {
712713
type = getMVPType();
713714
init = makeConst(type);
714715
}
715-
auto global = builder.makeGlobal(
716-
Names::getValidGlobalName(wasm, "global$"), type, init, mutability);
716+
auto name = Names::getValidGlobalName(wasm, "global$");
717+
auto global = builder.makeGlobal(name, type, init, mutability);
717718
useGlobalLater(wasm.addGlobal(std::move(global)));
719+
720+
// Export some globals, where we can.
721+
if (preserveImportsAndExports || type.isTuple() ||
722+
!isValidPublicType(type)) {
723+
continue;
724+
}
725+
if (mutability == Builder::Mutable && !wasm.features.hasMutableGlobals()) {
726+
continue;
727+
}
728+
if (oneIn(2)) {
729+
auto exportName = Names::getValidExportName(wasm, name);
730+
wasm.addExport(
731+
Builder::makeExport(exportName, name, ExternalKind::Global));
732+
}
718733
}
719734
}
720735

@@ -1185,23 +1200,26 @@ void TranslateToFuzzReader::addHashMemorySupport() {
11851200
}
11861201
}
11871202

1188-
void TranslateToFuzzReader::useImportedModule() {
1203+
void TranslateToFuzzReader::setImportedModule(std::string importedModuleName) {
1204+
importedModule.emplace();
1205+
1206+
importedModule->features = FeatureSet::All;
1207+
ModuleReader().read(importedModuleName, *importedModule);
1208+
}
1209+
1210+
void TranslateToFuzzReader::useImportedFunctions() {
11891211
if (!importedModule) {
11901212
return;
11911213
}
11921214

1193-
Module imported;
1194-
imported.features = FeatureSet::All;
1195-
ModuleReader().read(*importedModule, imported);
1196-
11971215
// Add some of the module's exported functions as imports, at a random rate.
11981216
auto rate = upTo(100);
1199-
for (auto& exp : imported.exports) {
1217+
for (auto& exp : importedModule->exports) {
12001218
if (exp->kind != ExternalKind::Function || upTo(100) > rate) {
12011219
continue;
12021220
}
12031221

1204-
auto* func = imported.getFunction(*exp->getInternalName());
1222+
auto* func = importedModule->getFunction(*exp->getInternalName());
12051223
auto name =
12061224
Names::getValidFunctionName(wasm, "primary_" + exp->name.toString());
12071225
// We can import it as its own type, or any (declared) supertype.
@@ -1213,12 +1231,45 @@ void TranslateToFuzzReader::useImportedModule() {
12131231
wasm.addFunction(std::move(import));
12141232
}
12151233

1216-
// TODO: All other imports: globals, memories, tables, etc. We must, as we do
1234+
// TODO: All other imports: memories, tables, etc. We must, as we do
12171235
// with functions, take care to run this *after* the removal of those
12181236
// imports (as normally we remove them all, as the fuzzer harness will
12191237
// not provide them, but an imported module is the exception).
12201238
}
12211239

1240+
void TranslateToFuzzReader::useImportedGlobals() {
1241+
if (!importedModule) {
1242+
return;
1243+
}
1244+
1245+
// Add some of the module's exported globals as imports, at a random rate.
1246+
auto rate = upTo(100);
1247+
for (auto& exp : importedModule->exports) {
1248+
if (exp->kind != ExternalKind::Global || upTo(100) > rate) {
1249+
continue;
1250+
}
1251+
1252+
auto* global = importedModule->getGlobal(*exp->getInternalName());
1253+
auto name =
1254+
Names::getValidGlobalName(wasm, "primary_" + exp->name.toString());
1255+
// We can import it as its own type, or if immutable, any (declared)
1256+
// supertype.
1257+
Type type;
1258+
Builder::Mutability mutability;
1259+
if (global->mutable_) {
1260+
mutability = Builder::Mutable;
1261+
type = global->type;
1262+
} else {
1263+
mutability = Builder::Immutable;
1264+
type = getSuperType(global->type);
1265+
}
1266+
auto import = builder.makeGlobal(name, type, nullptr, mutability);
1267+
import->module = "primary";
1268+
import->base = exp->name;
1269+
useGlobalLater(wasm.addGlobal(std::move(import)));
1270+
}
1271+
}
1272+
12221273
TranslateToFuzzReader::FunctionCreationContext::FunctionCreationContext(
12231274
TranslateToFuzzReader& parent, Function* func)
12241275
: parent(parent), func(func) {
@@ -5846,6 +5897,9 @@ HeapType TranslateToFuzzReader::getSuperType(HeapType type) {
58465897
}
58475898

58485899
Type TranslateToFuzzReader::getSuperType(Type type) {
5900+
if (!type.isRef()) {
5901+
return type;
5902+
}
58495903
auto heapType = getSuperType(type.getHeapType());
58505904
auto nullability = getSuperType(type.getNullability());
58515905
auto superType = Type(heapType, nullability);
Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,35 @@
11
Metrics
22
total
3-
[exports] : 32
4-
[funcs] : 42
3+
[exports] : 139
4+
[funcs] : 217
55
[globals] : 7
6-
[imports] : 4
6+
[imports] : 6
77
[memories] : 1
88
[memory-data] : 23
9-
[table-data] : 9
9+
[table-data] : 71
1010
[tables] : 1
1111
[tags] : 0
12-
[total] : 7716
13-
[vars] : 107
14-
Binary : 512
15-
Block : 1312
16-
Break : 299
17-
Call : 245
18-
CallIndirect : 49
19-
Const : 1197
20-
Drop : 95
21-
GlobalGet : 659
22-
GlobalSet : 465
23-
If : 416
24-
Load : 140
25-
LocalGet : 625
26-
LocalSet : 450
27-
Loop : 188
28-
Nop : 87
29-
RefFunc : 9
30-
Return : 75
31-
Select : 67
32-
Store : 45
33-
Unary : 547
34-
Unreachable : 234
12+
[total] : 15952
13+
[vars] : 628
14+
Binary : 1172
15+
Block : 2734
16+
Break : 525
17+
Call : 628
18+
CallIndirect : 146
19+
Const : 2648
20+
Drop : 185
21+
GlobalGet : 1418
22+
GlobalSet : 1052
23+
If : 866
24+
Load : 259
25+
LocalGet : 1011
26+
LocalSet : 708
27+
Loop : 309
28+
Nop : 227
29+
RefFunc : 71
30+
Return : 159
31+
Select : 83
32+
Store : 105
33+
Switch : 1
34+
Unary : 1112
35+
Unreachable : 533
Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
11
Metrics
22
total
3-
[exports] : 17
4-
[funcs] : 25
3+
[exports] : 33
4+
[funcs] : 57
55
[globals] : 4
6-
[imports] : 6
6+
[imports] : 4
77
[memories] : 1
88
[memory-data] : 20
9-
[table-data] : 9
9+
[table-data] : 14
1010
[tables] : 1
1111
[tags] : 0
12-
[total] : 3774
13-
[vars] : 91
14-
Binary : 238
15-
Block : 655
16-
Break : 105
17-
Call : 135
18-
CallIndirect : 23
19-
Const : 703
20-
Drop : 103
21-
GlobalGet : 258
22-
GlobalSet : 230
23-
If : 211
24-
Load : 44
25-
LocalGet : 285
26-
LocalSet : 163
27-
Loop : 90
28-
Nop : 64
29-
RefFunc : 9
30-
Return : 41
31-
Select : 24
32-
Store : 19
12+
[total] : 8611
13+
[vars] : 182
14+
Binary : 562
15+
Block : 1467
16+
Break : 279
17+
Call : 266
18+
CallIndirect : 51
19+
Const : 1345
20+
Drop : 118
21+
GlobalGet : 715
22+
GlobalSet : 508
23+
If : 493
24+
Load : 138
25+
LocalGet : 635
26+
LocalSet : 564
27+
Loop : 197
28+
Nop : 115
29+
RefFunc : 14
30+
Return : 98
31+
Select : 87
32+
Store : 67
3333
Switch : 2
34-
Unary : 256
35-
Unreachable : 116
34+
Unary : 634
35+
Unreachable : 256

0 commit comments

Comments
 (0)