-
Notifications
You must be signed in to change notification settings - Fork 747
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
Fuzzer: Log locals and values referred to from locals #6913
base: main
Are you sure you want to change the base?
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 |
---|---|---|
|
@@ -693,9 +693,77 @@ Expression* TranslateToFuzzReader::makeHangLimitCheck() { | |
} | ||
|
||
Expression* TranslateToFuzzReader::makeLogging() { | ||
auto type = getLoggableType(); | ||
return builder.makeCall( | ||
std::string("log-") + type.toString(), {make(type)}, Type::none); | ||
auto makeLoggingCall = [&](Expression* value) { | ||
assert(isLoggableType(value->type)); | ||
return builder.makeCall( | ||
std::string("log-") + value->type.toString(), {value}, Type::none); | ||
}; | ||
|
||
// We may choose to log a local, if there are any. | ||
auto* func = funcContext->func; | ||
auto numLocals = func->getNumLocals(); | ||
|
||
auto choice = upTo(4); | ||
if (choice < 2 || numLocals == 0) { | ||
// 50% of the time, pick a loggable type and make something of that type | ||
// to log. Also do so when there are no locals to log. | ||
return makeLoggingCall(make(getLoggableType())); | ||
} | ||
|
||
// 50% of the time, pick a local and log it, either shallowly or deeply. | ||
auto index = upTo(numLocals); | ||
auto type = func->getLocalType(index); | ||
if (isLoggableType(type)) { | ||
// We can log this directly. Get it and log that. | ||
return makeLoggingCall(builder.makeLocalGet(index, type)); | ||
} | ||
|
||
if (type.isRef()) { | ||
// This is a reference, which cannot be directly logged. We can at least | ||
// "shallowly" log it by seeing if it is null (if it is nullable - if not, | ||
// then there is no point to such a check). | ||
auto* get = builder.makeLocalGet(index, type); | ||
auto* isNullCheck = | ||
type.isNullable() ? builder.makeRefIsNull(get) : nullptr; | ||
if (choice & 1) { | ||
// Try to also "deeply" log it, by reading a value from it, if we can. | ||
auto heapType = type.getHeapType(); | ||
if (heapType.isStruct()) { | ||
auto& fields = heapType.getStruct().fields; | ||
if (!fields.empty()) { | ||
auto fieldIndex = upTo(fields.size()); | ||
auto fieldType = fields[fieldIndex].type; | ||
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. Do you think it's worth linearly searching from this random starting index looking for the first loggable field? We could also do a breadth-first search on the type graph looking for a loggable type. |
||
if (isLoggableType(fieldType)) { | ||
// Do a deep logging after a null check. Or, if non-nullable, | ||
// without the null check. | ||
auto* get2 = builder.makeLocalGet(index, type); | ||
auto* structGet = | ||
builder.makeStructGet(fieldIndex, get2, fieldType); | ||
auto* whenNonNull = makeLoggingCall(structGet); | ||
if (!isNullCheck) { | ||
assert(type.isNonNullable()); | ||
return whenNonNull; | ||
} | ||
|
||
// If the ref is null, log a random integer. The randomness is to | ||
// avoid the risk of colliding with the value logged in the other | ||
// arm. | ||
auto* whenNull = makeLoggingCall(makeConst(Type::i32)); | ||
return builder.makeIf(isNullCheck, whenNull, whenNonNull); | ||
Comment on lines
+748
to
+752
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. We could also unconditionally log the result of the null check, followed by a conditional log of the field without an else arm in the if. |
||
} | ||
} | ||
} | ||
} | ||
|
||
// All we can do is log the nullability as an i32 (if it is nullable; if | ||
// not then we'd be logging 1 all the time). | ||
if (isNullCheck) { | ||
return makeLoggingCall(isNullCheck); | ||
} | ||
} | ||
|
||
// For anything else, log something loggable from scratch. | ||
return makeLoggingCall(make(getLoggableType())); | ||
} | ||
|
||
Expression* TranslateToFuzzReader::makeMemoryHashLogging() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,35 @@ | ||
Metrics | ||
total | ||
[exports] : 23 | ||
[funcs] : 34 | ||
[exports] : 58 | ||
[funcs] : 81 | ||
[globals] : 9 | ||
[imports] : 4 | ||
[memories] : 1 | ||
[memory-data] : 2 | ||
[table-data] : 6 | ||
[table-data] : 33 | ||
[tables] : 1 | ||
[tags] : 0 | ||
[total] : 4303 | ||
[vars] : 100 | ||
Binary : 355 | ||
Block : 684 | ||
Break : 149 | ||
Call : 219 | ||
CallIndirect : 23 | ||
Const : 643 | ||
Drop : 50 | ||
GlobalGet : 367 | ||
GlobalSet : 258 | ||
If : 206 | ||
Load : 78 | ||
LocalGet : 339 | ||
LocalSet : 236 | ||
Loop : 93 | ||
Nop : 41 | ||
RefFunc : 6 | ||
Return : 45 | ||
Select : 41 | ||
Store : 36 | ||
Switch : 1 | ||
Unary : 304 | ||
Unreachable : 129 | ||
[total] : 9015 | ||
[vars] : 210 | ||
Binary : 668 | ||
Block : 1543 | ||
Break : 293 | ||
Call : 256 | ||
CallIndirect : 64 | ||
Const : 1436 | ||
Drop : 92 | ||
GlobalGet : 779 | ||
GlobalSet : 585 | ||
If : 485 | ||
Load : 161 | ||
LocalGet : 592 | ||
LocalSet : 478 | ||
Loop : 207 | ||
Nop : 138 | ||
RefFunc : 33 | ||
Return : 89 | ||
Select : 63 | ||
Store : 85 | ||
Switch : 7 | ||
Unary : 667 | ||
Unreachable : 294 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,48 @@ | ||
Metrics | ||
total | ||
[exports] : 5 | ||
[funcs] : 9 | ||
[funcs] : 12 | ||
[globals] : 26 | ||
[imports] : 5 | ||
[memories] : 1 | ||
[memory-data] : 20 | ||
[table-data] : 3 | ||
[table-data] : 6 | ||
[tables] : 1 | ||
[tags] : 2 | ||
[total] : 669 | ||
[vars] : 27 | ||
[total] : 534 | ||
[vars] : 22 | ||
ArrayNew : 16 | ||
ArrayNewFixed : 3 | ||
AtomicCmpxchg : 1 | ||
AtomicFence : 1 | ||
Binary : 75 | ||
Block : 70 | ||
Break : 7 | ||
Call : 26 | ||
Binary : 66 | ||
Block : 53 | ||
Break : 3 | ||
Call : 8 | ||
CallRef : 1 | ||
Const : 143 | ||
Drop : 3 | ||
GlobalGet : 37 | ||
GlobalSet : 27 | ||
Const : 130 | ||
Drop : 2 | ||
GlobalGet : 38 | ||
GlobalSet : 26 | ||
I31Get : 1 | ||
If : 20 | ||
Load : 21 | ||
LocalGet : 55 | ||
LocalSet : 40 | ||
Loop : 6 | ||
Nop : 5 | ||
Pop : 5 | ||
RefAs : 2 | ||
RefEq : 2 | ||
RefFunc : 5 | ||
RefI31 : 2 | ||
RefNull : 11 | ||
RefTest : 2 | ||
Return : 6 | ||
Select : 2 | ||
If : 15 | ||
Load : 17 | ||
LocalGet : 35 | ||
LocalSet : 21 | ||
Loop : 3 | ||
Nop : 3 | ||
RefAs : 1 | ||
RefCast : 1 | ||
RefFunc : 9 | ||
RefI31 : 1 | ||
RefNull : 10 | ||
Return : 4 | ||
Select : 5 | ||
StringConst : 6 | ||
StringEq : 1 | ||
StringMeasure : 1 | ||
StringWTF16Get : 1 | ||
StructNew : 17 | ||
StringMeasure : 2 | ||
StructNew : 15 | ||
StructSet : 1 | ||
Try : 4 | ||
TupleExtract : 3 | ||
Try : 1 | ||
TupleExtract : 1 | ||
TupleMake : 5 | ||
Unary : 20 | ||
Unary : 15 | ||
Unreachable : 15 |
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.
How about inverting this condition to save a level of nesting on most of the following code?