Clean regex fuzzer API
Introduces a class to clearly identify the interface of the mutation functions used during regex-based fuzzing. Bug: None Change-Id: Ia6d125227cffc1c0b8944764c4e21825fd31d5cd Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96360 Reviewed-by: Ryan Harrison <rharrison@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Alastair Donaldson <allydonaldson@googlemail.com>
This commit is contained in:
parent
1cfe319290
commit
853cbadc8f
|
@ -64,39 +64,40 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
|
||||||
MutationKind mutation_kind = static_cast<MutationKind>(
|
MutationKind mutation_kind = static_cast<MutationKind>(
|
||||||
generator.GetUInt32(static_cast<uint32_t>(MutationKind::kNumMutationKinds)));
|
generator.GetUInt32(static_cast<uint32_t>(MutationKind::kNumMutationKinds)));
|
||||||
|
|
||||||
|
WgslMutator mutator(generator);
|
||||||
switch (mutation_kind) {
|
switch (mutation_kind) {
|
||||||
case MutationKind::kSwapIntervals:
|
case MutationKind::kSwapIntervals:
|
||||||
if (!SwapRandomIntervals(delimiter, wgsl_code, generator)) {
|
if (!mutator.SwapRandomIntervals(delimiter, wgsl_code)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MutationKind::kDeleteInterval:
|
case MutationKind::kDeleteInterval:
|
||||||
if (!DeleteRandomInterval(delimiter, wgsl_code, generator)) {
|
if (!mutator.DeleteRandomInterval(delimiter, wgsl_code)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MutationKind::kDuplicateInterval:
|
case MutationKind::kDuplicateInterval:
|
||||||
if (!DuplicateRandomInterval(delimiter, wgsl_code, generator)) {
|
if (!mutator.DuplicateRandomInterval(delimiter, wgsl_code)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MutationKind::kReplaceIdentifier:
|
case MutationKind::kReplaceIdentifier:
|
||||||
if (!ReplaceRandomIdentifier(wgsl_code, generator)) {
|
if (!mutator.ReplaceRandomIdentifier(wgsl_code)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MutationKind::kReplaceLiteral:
|
case MutationKind::kReplaceLiteral:
|
||||||
if (!ReplaceRandomIntLiteral(wgsl_code, generator)) {
|
if (!mutator.ReplaceRandomIntLiteral(wgsl_code)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MutationKind::kInsertReturnStatement:
|
case MutationKind::kInsertReturnStatement:
|
||||||
if (!InsertReturnStatement(wgsl_code, generator)) {
|
if (!mutator.InsertReturnStatement(wgsl_code)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,26 +21,44 @@
|
||||||
namespace tint::fuzzers::regex_fuzzer {
|
namespace tint::fuzzers::regex_fuzzer {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class WgslMutatorTest : public WgslMutator {
|
||||||
|
public:
|
||||||
|
explicit WgslMutatorTest(RandomGenerator& generator) : WgslMutator(generator) {}
|
||||||
|
|
||||||
|
using WgslMutator::DeleteInterval;
|
||||||
|
using WgslMutator::DuplicateInterval;
|
||||||
|
using WgslMutator::FindClosingBrace;
|
||||||
|
using WgslMutator::GetFunctionBodyPositions;
|
||||||
|
using WgslMutator::GetIdentifiers;
|
||||||
|
using WgslMutator::GetIntLiterals;
|
||||||
|
using WgslMutator::ReplaceRegion;
|
||||||
|
using WgslMutator::SwapIntervals;
|
||||||
|
};
|
||||||
|
|
||||||
// Swaps two non-consecutive regions in the edge
|
// Swaps two non-consecutive regions in the edge
|
||||||
TEST(SwapRegionsTest, SwapIntervalsEdgeNonConsecutive) {
|
TEST(SwapRegionsTest, SwapIntervalsEdgeNonConsecutive) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;";
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;";
|
||||||
std::string all_regions = R1 + R2 + R3;
|
std::string all_regions = R1 + R2 + R3;
|
||||||
|
|
||||||
// this call should swap R1 with R3.
|
// this call should swap R1 with R3.
|
||||||
SwapIntervals(0, R1.length(), R1.length() + R2.length(), R3.length(), all_regions);
|
mutator.SwapIntervals(0, R1.length(), R1.length() + R2.length(), R3.length(), all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R3 + R2 + R1, all_regions);
|
ASSERT_EQ(R3 + R2 + R1, all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swaps two non-consecutive regions not in the edge
|
// Swaps two non-consecutive regions not in the edge
|
||||||
TEST(SwapRegionsTest, SwapIntervalsNonConsecutiveNonEdge) {
|
TEST(SwapRegionsTest, SwapIntervalsNonConsecutiveNonEdge) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// this call should swap R2 with R4.
|
// this call should swap R2 with R4.
|
||||||
SwapIntervals(R1.length(), R2.length(), R1.length() + R2.length() + R3.length(), R4.length(),
|
mutator.SwapIntervals(R1.length(), R2.length(), R1.length() + R2.length() + R3.length(),
|
||||||
all_regions);
|
R4.length(), all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R4 + R3 + R2 + R5, all_regions);
|
ASSERT_EQ(R1 + R4 + R3 + R2 + R5, all_regions);
|
||||||
}
|
}
|
||||||
|
@ -48,12 +66,15 @@ TEST(SwapRegionsTest, SwapIntervalsNonConsecutiveNonEdge) {
|
||||||
// Swaps two consecutive regions not in the edge (sorrounded by other
|
// Swaps two consecutive regions not in the edge (sorrounded by other
|
||||||
// regions)
|
// regions)
|
||||||
TEST(SwapRegionsTest, SwapIntervalsConsecutiveEdge) {
|
TEST(SwapRegionsTest, SwapIntervalsConsecutiveEdge) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4;
|
std::string all_regions = R1 + R2 + R3 + R4;
|
||||||
|
|
||||||
// this call should swap R2 with R3.
|
// this call should swap R2 with R3.
|
||||||
SwapIntervals(R1.length(), R2.length(), R1.length() + R2.length(), R3.length(), all_regions);
|
mutator.SwapIntervals(R1.length(), R2.length(), R1.length() + R2.length(), R3.length(),
|
||||||
|
all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R3 + R2 + R4, all_regions);
|
ASSERT_EQ(R1 + R3 + R2 + R4, all_regions);
|
||||||
}
|
}
|
||||||
|
@ -61,113 +82,137 @@ TEST(SwapRegionsTest, SwapIntervalsConsecutiveEdge) {
|
||||||
// Swaps two consecutive regions not in the edge (not sorrounded by other
|
// Swaps two consecutive regions not in the edge (not sorrounded by other
|
||||||
// regions)
|
// regions)
|
||||||
TEST(SwapRegionsTest, SwapIntervalsConsecutiveNonEdge) {
|
TEST(SwapRegionsTest, SwapIntervalsConsecutiveNonEdge) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// this call should swap R4 with R5.
|
// this call should swap R4 with R5.
|
||||||
SwapIntervals(R1.length() + R2.length() + R3.length(), R4.length(),
|
mutator.SwapIntervals(R1.length() + R2.length() + R3.length(), R4.length(),
|
||||||
R1.length() + R2.length() + R3.length() + R4.length(), R5.length(), all_regions);
|
R1.length() + R2.length() + R3.length() + R4.length(), R5.length(),
|
||||||
|
all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R2 + R3 + R5 + R4, all_regions);
|
ASSERT_EQ(R1 + R2 + R3 + R5 + R4, all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes the first region.
|
// Deletes the first region.
|
||||||
TEST(DeleteRegionTest, DeleteFirstRegion) {
|
TEST(DeleteRegionTest, DeleteFirstRegion) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// This call should delete R1.
|
// This call should delete R1.
|
||||||
DeleteInterval(0, R1.length(), all_regions);
|
mutator.DeleteInterval(0, R1.length(), all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(";" + R2 + R3 + R4 + R5, all_regions);
|
ASSERT_EQ(";" + R2 + R3 + R4 + R5, all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes the last region.
|
// Deletes the last region.
|
||||||
TEST(DeleteRegionTest, DeleteLastRegion) {
|
TEST(DeleteRegionTest, DeleteLastRegion) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// This call should delete R5.
|
// This call should delete R5.
|
||||||
DeleteInterval(R1.length() + R2.length() + R3.length() + R4.length(), R5.length(), all_regions);
|
mutator.DeleteInterval(R1.length() + R2.length() + R3.length() + R4.length(), R5.length(),
|
||||||
|
all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R2 + R3 + R4 + ";", all_regions);
|
ASSERT_EQ(R1 + R2 + R3 + R4 + ";", all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes the middle region.
|
// Deletes the middle region.
|
||||||
TEST(DeleteRegionTest, DeleteMiddleRegion) {
|
TEST(DeleteRegionTest, DeleteMiddleRegion) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// This call should delete R3.
|
// This call should delete R3.
|
||||||
DeleteInterval(R1.length() + R2.length(), R3.length(), all_regions);
|
mutator.DeleteInterval(R1.length() + R2.length(), R3.length(), all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R2 + ";" + R4 + R5, all_regions);
|
ASSERT_EQ(R1 + R2 + ";" + R4 + R5, all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(InsertRegionTest, InsertRegionTest1) {
|
TEST(InsertRegionTest, InsertRegionTest1) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// This call should insert R2 after R4.
|
// This call should insert R2 after R4.
|
||||||
DuplicateInterval(R1.length(), R2.length(),
|
mutator.DuplicateInterval(R1.length(), R2.length(),
|
||||||
R1.length() + R2.length() + R3.length() + R4.length() - 1, all_regions);
|
R1.length() + R2.length() + R3.length() + R4.length() - 1,
|
||||||
|
all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R2 + R3 + R4 + R2.substr(1, R2.size() - 1) + R5, all_regions);
|
ASSERT_EQ(R1 + R2 + R3 + R4 + R2.substr(1, R2.size() - 1) + R5, all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(InsertRegionTest, InsertRegionTest2) {
|
TEST(InsertRegionTest, InsertRegionTest2) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
|
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// This call should insert R3 after R1.
|
// This call should insert R3 after R1.
|
||||||
DuplicateInterval(R1.length() + R2.length(), R3.length(), R1.length() - 1, all_regions);
|
mutator.DuplicateInterval(R1.length() + R2.length(), R3.length(), R1.length() - 1, all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R3.substr(1, R3.length() - 1) + R2 + R3 + R4 + R5, all_regions);
|
ASSERT_EQ(R1 + R3.substr(1, R3.length() - 1) + R2 + R3 + R4 + R5, all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(InsertRegionTest, InsertRegionTest3) {
|
TEST(InsertRegionTest, InsertRegionTest3) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
|
||||||
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
|
||||||
|
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// This call should insert R2 after R5.
|
// This call should insert R2 after R5.
|
||||||
DuplicateInterval(R1.length(), R2.length(), all_regions.length() - 1, all_regions);
|
mutator.DuplicateInterval(R1.length(), R2.length(), all_regions.length() - 1, all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R2 + R3 + R4 + R5 + R2.substr(1, R2.length() - 1), all_regions);
|
ASSERT_EQ(R1 + R2 + R3 + R4 + R5 + R2.substr(1, R2.length() - 1), all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ReplaceIdentifierTest, ReplaceIdentifierTest1) {
|
TEST(ReplaceIdentifierTest, ReplaceIdentifierTest1) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = "|region1|", R2 = "; region2;", R3 = "---------region3---------",
|
std::string R1 = "|region1|", R2 = "; region2;", R3 = "---------region3---------",
|
||||||
R4 = "++region4++", R5 = "***region5***";
|
R4 = "++region4++", R5 = "***region5***";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// Replaces R3 with R1.
|
// Replaces R3 with R1.
|
||||||
ReplaceRegion(0, R1.length(), R1.length() + R2.length(), R3.length(), all_regions);
|
mutator.ReplaceRegion(0, R1.length(), R1.length() + R2.length(), R3.length(), all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R2 + R1 + R4 + R5, all_regions);
|
ASSERT_EQ(R1 + R2 + R1 + R4 + R5, all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ReplaceIdentifierTest, ReplaceIdentifierTest2) {
|
TEST(ReplaceIdentifierTest, ReplaceIdentifierTest2) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string R1 = "|region1|", R2 = "; region2;", R3 = "---------region3---------",
|
std::string R1 = "|region1|", R2 = "; region2;", R3 = "---------region3---------",
|
||||||
R4 = "++region4++", R5 = "***region5***";
|
R4 = "++region4++", R5 = "***region5***";
|
||||||
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
std::string all_regions = R1 + R2 + R3 + R4 + R5;
|
||||||
|
|
||||||
// Replaces R5 with R3.
|
// Replaces R5 with R3.
|
||||||
ReplaceRegion(R1.length() + R2.length(), R3.length(),
|
mutator.ReplaceRegion(R1.length() + R2.length(), R3.length(),
|
||||||
R1.length() + R2.length() + R3.length() + R4.length(), R5.length(), all_regions);
|
R1.length() + R2.length() + R3.length() + R4.length(), R5.length(),
|
||||||
|
all_regions);
|
||||||
|
|
||||||
ASSERT_EQ(R1 + R2 + R3 + R4 + R3, all_regions);
|
ASSERT_EQ(R1 + R2 + R3 + R4 + R3, all_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GetIdentifierTest, GetIdentifierTest1) {
|
TEST(GetIdentifierTest, GetIdentifierTest1) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string wgsl_code =
|
std::string wgsl_code =
|
||||||
R"(fn clamp_0acf8f() {
|
R"(fn clamp_0acf8f() {
|
||||||
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
|
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
|
||||||
|
@ -187,7 +232,7 @@ TEST(GetIdentifierTest, GetIdentifierTest1) {
|
||||||
clamp_0acf8f();
|
clamp_0acf8f();
|
||||||
})";
|
})";
|
||||||
|
|
||||||
std::vector<std::pair<size_t, size_t>> identifiers_pos = GetIdentifiers(wgsl_code);
|
std::vector<std::pair<size_t, size_t>> identifiers_pos = mutator.GetIdentifiers(wgsl_code);
|
||||||
|
|
||||||
std::vector<std::pair<size_t, size_t>> ground_truth = {
|
std::vector<std::pair<size_t, size_t>> ground_truth = {
|
||||||
std::make_pair(3, 12), std::make_pair(28, 3), std::make_pair(37, 4),
|
std::make_pair(3, 12), std::make_pair(28, 3), std::make_pair(37, 4),
|
||||||
|
@ -204,6 +249,8 @@ TEST(GetIdentifierTest, GetIdentifierTest1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestGetLiteralsValues, TestGetLiteralsValues1) {
|
TEST(TestGetLiteralsValues, TestGetLiteralsValues1) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string wgsl_code =
|
std::string wgsl_code =
|
||||||
R"(fn clamp_0acf8f() {
|
R"(fn clamp_0acf8f() {
|
||||||
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
|
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
|
||||||
|
@ -227,7 +274,7 @@ TEST(TestGetLiteralsValues, TestGetLiteralsValues1) {
|
||||||
foo_1 = 5 + 7;
|
foo_1 = 5 + 7;
|
||||||
var foo_3 : i32 = -20;)";
|
var foo_3 : i32 = -20;)";
|
||||||
|
|
||||||
std::vector<std::pair<size_t, size_t>> literals_pos = GetIntLiterals(wgsl_code);
|
std::vector<std::pair<size_t, size_t>> literals_pos = mutator.GetIntLiterals(wgsl_code);
|
||||||
|
|
||||||
std::vector<std::string> ground_truth = {"3", "10", "5", "7", "-20"};
|
std::vector<std::string> ground_truth = {"3", "10", "5", "7", "-20"};
|
||||||
|
|
||||||
|
@ -241,6 +288,8 @@ TEST(TestGetLiteralsValues, TestGetLiteralsValues1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(InsertReturnTest, FindClosingBrace) {
|
TEST(InsertReturnTest, FindClosingBrace) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string wgsl_code =
|
std::string wgsl_code =
|
||||||
R"(fn clamp_0acf8f() {
|
R"(fn clamp_0acf8f() {
|
||||||
if(false){
|
if(false){
|
||||||
|
@ -269,7 +318,7 @@ TEST(InsertReturnTest, FindClosingBrace) {
|
||||||
var foo_3 : i32 = -20;
|
var foo_3 : i32 = -20;
|
||||||
)";
|
)";
|
||||||
size_t opening_bracket_pos = 18;
|
size_t opening_bracket_pos = 18;
|
||||||
size_t closing_bracket_pos = FindClosingBrace(opening_bracket_pos, wgsl_code);
|
size_t closing_bracket_pos = mutator.FindClosingBrace(opening_bracket_pos, wgsl_code);
|
||||||
|
|
||||||
// The -1 is needed since the function body starts after the left bracket.
|
// The -1 is needed since the function body starts after the left bracket.
|
||||||
std::string function_body =
|
std::string function_body =
|
||||||
|
@ -286,6 +335,8 @@ TEST(InsertReturnTest, FindClosingBrace) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(InsertReturnTest, FindClosingBraceFailing) {
|
TEST(InsertReturnTest, FindClosingBraceFailing) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string wgsl_code =
|
std::string wgsl_code =
|
||||||
R"(fn clamp_0acf8f() {
|
R"(fn clamp_0acf8f() {
|
||||||
// This comment } causes the test to fail.
|
// This comment } causes the test to fail.
|
||||||
|
@ -314,7 +365,7 @@ TEST(InsertReturnTest, FindClosingBraceFailing) {
|
||||||
foo_1 = 5 + 7;
|
foo_1 = 5 + 7;
|
||||||
var foo_3 : i32 = -20;)";
|
var foo_3 : i32 = -20;)";
|
||||||
size_t opening_bracket_pos = 18;
|
size_t opening_bracket_pos = 18;
|
||||||
size_t closing_bracket_pos = FindClosingBrace(opening_bracket_pos, wgsl_code);
|
size_t closing_bracket_pos = mutator.FindClosingBrace(opening_bracket_pos, wgsl_code);
|
||||||
|
|
||||||
// The -1 is needed since the function body starts after the left bracket.
|
// The -1 is needed since the function body starts after the left bracket.
|
||||||
std::string function_body =
|
std::string function_body =
|
||||||
|
@ -330,6 +381,8 @@ TEST(InsertReturnTest, FindClosingBraceFailing) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestInsertReturn, TestInsertReturn1) {
|
TEST(TestInsertReturn, TestInsertReturn1) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string wgsl_code =
|
std::string wgsl_code =
|
||||||
R"(fn clamp_0acf8f() {
|
R"(fn clamp_0acf8f() {
|
||||||
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
|
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
|
||||||
|
@ -390,6 +443,8 @@ TEST(TestInsertReturn, TestInsertReturn1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestInsertReturn, TestFunctionPositions) {
|
TEST(TestInsertReturn, TestFunctionPositions) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string wgsl_code =
|
std::string wgsl_code =
|
||||||
R"(fn clamp_0acf8f() {
|
R"(fn clamp_0acf8f() {
|
||||||
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
|
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
|
||||||
|
@ -418,12 +473,14 @@ TEST(TestInsertReturn, TestFunctionPositions) {
|
||||||
foo_1 = 5 + 7;
|
foo_1 = 5 + 7;
|
||||||
var foo_3 : i32 = -20;)";
|
var foo_3 : i32 = -20;)";
|
||||||
|
|
||||||
std::vector<size_t> function_positions = GetFunctionBodyPositions(wgsl_code);
|
std::vector<size_t> function_positions = mutator.GetFunctionBodyPositions(wgsl_code);
|
||||||
std::vector<size_t> expected_positions = {180, 586};
|
std::vector<size_t> expected_positions = {180, 586};
|
||||||
ASSERT_EQ(expected_positions, function_positions);
|
ASSERT_EQ(expected_positions, function_positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestInsertReturn, TestMissingSemicolon) {
|
TEST(TestInsertReturn, TestMissingSemicolon) {
|
||||||
|
RandomGenerator generator(0);
|
||||||
|
WgslMutatorTest mutator(generator);
|
||||||
std::string wgsl_code =
|
std::string wgsl_code =
|
||||||
R"(fn clamp_0acf8f() {
|
R"(fn clamp_0acf8f() {
|
||||||
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>())
|
var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>())
|
||||||
|
@ -452,8 +509,7 @@ TEST(TestInsertReturn, TestMissingSemicolon) {
|
||||||
foo_1 = 5 + 7;
|
foo_1 = 5 + 7;
|
||||||
var foo_3 : i32 = -20;)";
|
var foo_3 : i32 = -20;)";
|
||||||
|
|
||||||
RandomGenerator generator(0);
|
mutator.InsertReturnStatement(wgsl_code);
|
||||||
InsertReturnStatement(wgsl_code, generator);
|
|
||||||
|
|
||||||
// No semicolons found in the function's body, so wgsl_code
|
// No semicolons found in the function's body, so wgsl_code
|
||||||
// should remain unchanged.
|
// should remain unchanged.
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
|
|
||||||
namespace tint::fuzzers::regex_fuzzer {
|
namespace tint::fuzzers::regex_fuzzer {
|
||||||
|
|
||||||
std::vector<size_t> FindDelimiterIndices(const std::string& delimiter,
|
WgslMutator::WgslMutator(RandomGenerator& generator) : generator_(generator) {}
|
||||||
|
|
||||||
|
std::vector<size_t> WgslMutator::FindDelimiterIndices(const std::string& delimiter,
|
||||||
const std::string& wgsl_code) {
|
const std::string& wgsl_code) {
|
||||||
std::vector<size_t> result;
|
std::vector<size_t> result;
|
||||||
for (size_t pos = wgsl_code.find(delimiter, 0); pos != std::string::npos;
|
for (size_t pos = wgsl_code.find(delimiter, 0); pos != std::string::npos;
|
||||||
|
@ -37,7 +39,7 @@ std::vector<size_t> FindDelimiterIndices(const std::string& delimiter,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<size_t, size_t>> GetIdentifiers(const std::string& wgsl_code) {
|
std::vector<std::pair<size_t, size_t>> WgslMutator::GetIdentifiers(const std::string& wgsl_code) {
|
||||||
std::vector<std::pair<size_t, size_t>> result;
|
std::vector<std::pair<size_t, size_t>> result;
|
||||||
|
|
||||||
// This regular expression works by looking for a character that
|
// This regular expression works by looking for a character that
|
||||||
|
@ -61,7 +63,7 @@ std::vector<std::pair<size_t, size_t>> GetIdentifiers(const std::string& wgsl_co
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<size_t, size_t>> GetIntLiterals(const std::string& s) {
|
std::vector<std::pair<size_t, size_t>> WgslMutator::GetIntLiterals(const std::string& s) {
|
||||||
std::vector<std::pair<size_t, size_t>> result;
|
std::vector<std::pair<size_t, size_t>> result;
|
||||||
|
|
||||||
// Looks for integer literals in decimal or hexadecimal form.
|
// Looks for integer literals in decimal or hexadecimal form.
|
||||||
|
@ -83,7 +85,7 @@ std::vector<std::pair<size_t, size_t>> GetIntLiterals(const std::string& s) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FindClosingBrace(size_t opening_bracket_pos, const std::string& wgsl_code) {
|
size_t WgslMutator::FindClosingBrace(size_t opening_bracket_pos, const std::string& wgsl_code) {
|
||||||
size_t open_bracket_count = 1;
|
size_t open_bracket_count = 1;
|
||||||
size_t pos = opening_bracket_pos + 1;
|
size_t pos = opening_bracket_pos + 1;
|
||||||
while (open_bracket_count >= 1 && pos < wgsl_code.size()) {
|
while (open_bracket_count >= 1 && pos < wgsl_code.size()) {
|
||||||
|
@ -97,7 +99,7 @@ size_t FindClosingBrace(size_t opening_bracket_pos, const std::string& wgsl_code
|
||||||
return (pos == wgsl_code.size() && open_bracket_count >= 1) ? 0 : pos - 1;
|
return (pos == wgsl_code.size() && open_bracket_count >= 1) ? 0 : pos - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<size_t> GetFunctionBodyPositions(const std::string& wgsl_code) {
|
std::vector<size_t> WgslMutator::GetFunctionBodyPositions(const std::string& wgsl_code) {
|
||||||
// Finds all the functions with a non-void return value.
|
// Finds all the functions with a non-void return value.
|
||||||
std::regex function_regex("fn.*?->.*?\\{");
|
std::regex function_regex("fn.*?->.*?\\{");
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
|
@ -113,7 +115,7 @@ std::vector<size_t> GetFunctionBodyPositions(const std::string& wgsl_code) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InsertReturnStatement(std::string& wgsl_code, RandomGenerator& generator) {
|
bool WgslMutator::InsertReturnStatement(std::string& wgsl_code) {
|
||||||
std::vector<size_t> function_body_positions = GetFunctionBodyPositions(wgsl_code);
|
std::vector<size_t> function_body_positions = GetFunctionBodyPositions(wgsl_code);
|
||||||
|
|
||||||
// No function was found in wgsl_code.
|
// No function was found in wgsl_code.
|
||||||
|
@ -123,7 +125,7 @@ bool InsertReturnStatement(std::string& wgsl_code, RandomGenerator& generator) {
|
||||||
|
|
||||||
// Pick a random function's opening bracket, find the corresponding closing
|
// Pick a random function's opening bracket, find the corresponding closing
|
||||||
// bracket, and find a semi-colon within the function body.
|
// bracket, and find a semi-colon within the function body.
|
||||||
size_t left_bracket_pos = generator.GetRandomElement(function_body_positions);
|
size_t left_bracket_pos = generator_.GetRandomElement(function_body_positions);
|
||||||
|
|
||||||
size_t right_bracket_pos = FindClosingBrace(left_bracket_pos, wgsl_code);
|
size_t right_bracket_pos = FindClosingBrace(left_bracket_pos, wgsl_code);
|
||||||
|
|
||||||
|
@ -141,14 +143,14 @@ bool InsertReturnStatement(std::string& wgsl_code, RandomGenerator& generator) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t semicolon_position = generator.GetRandomElement(semicolon_positions);
|
size_t semicolon_position = generator_.GetRandomElement(semicolon_positions);
|
||||||
|
|
||||||
// Get all identifiers and integer literals to use as potential return values.
|
// Get all identifiers and integer literals to use as potential return values.
|
||||||
std::vector<std::pair<size_t, size_t>> identifiers = GetIdentifiers(wgsl_code);
|
std::vector<std::pair<size_t, size_t>> identifiers = GetIdentifiers(wgsl_code);
|
||||||
auto return_values = identifiers;
|
auto return_values = identifiers;
|
||||||
std::vector<std::pair<size_t, size_t>> int_literals = GetIntLiterals(wgsl_code);
|
std::vector<std::pair<size_t, size_t>> int_literals = GetIntLiterals(wgsl_code);
|
||||||
return_values.insert(return_values.end(), int_literals.begin(), int_literals.end());
|
return_values.insert(return_values.end(), int_literals.begin(), int_literals.end());
|
||||||
std::pair<size_t, size_t> return_value = generator.GetRandomElement(return_values);
|
std::pair<size_t, size_t> return_value = generator_.GetRandomElement(return_values);
|
||||||
std::string return_statement =
|
std::string return_statement =
|
||||||
"return " + wgsl_code.substr(return_value.first, return_value.second) + ";";
|
"return " + wgsl_code.substr(return_value.first, return_value.second) + ";";
|
||||||
|
|
||||||
|
@ -157,7 +159,7 @@ bool InsertReturnStatement(std::string& wgsl_code, RandomGenerator& generator) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapIntervals(size_t idx1,
|
void WgslMutator::SwapIntervals(size_t idx1,
|
||||||
size_t reg1_len,
|
size_t reg1_len,
|
||||||
size_t idx2,
|
size_t idx2,
|
||||||
size_t reg2_len,
|
size_t reg2_len,
|
||||||
|
@ -172,16 +174,19 @@ void SwapIntervals(size_t idx1,
|
||||||
wgsl_code.replace(idx1 + 1, region_1.size(), region_2);
|
wgsl_code.replace(idx1 + 1, region_1.size(), region_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteInterval(size_t idx1, size_t reg_len, std::string& wgsl_code) {
|
void WgslMutator::DeleteInterval(size_t idx1, size_t reg_len, std::string& wgsl_code) {
|
||||||
wgsl_code.erase(idx1 + 1, reg_len - 1);
|
wgsl_code.erase(idx1 + 1, reg_len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DuplicateInterval(size_t idx1, size_t reg1_len, size_t idx2, std::string& wgsl_code) {
|
void WgslMutator::DuplicateInterval(size_t idx1,
|
||||||
|
size_t reg1_len,
|
||||||
|
size_t idx2,
|
||||||
|
std::string& wgsl_code) {
|
||||||
std::string region = wgsl_code.substr(idx1 + 1, reg1_len - 1);
|
std::string region = wgsl_code.substr(idx1 + 1, reg1_len - 1);
|
||||||
wgsl_code.insert(idx2 + 1, region);
|
wgsl_code.insert(idx2 + 1, region);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplaceRegion(size_t idx1,
|
void WgslMutator::ReplaceRegion(size_t idx1,
|
||||||
size_t id1_len,
|
size_t id1_len,
|
||||||
size_t idx2,
|
size_t idx2,
|
||||||
size_t id2_len,
|
size_t id2_len,
|
||||||
|
@ -191,7 +196,7 @@ void ReplaceRegion(size_t idx1,
|
||||||
wgsl_code.replace(idx2, region_2.size(), region_1);
|
wgsl_code.replace(idx2, region_2.size(), region_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplaceInterval(size_t start_index,
|
void WgslMutator::ReplaceInterval(size_t start_index,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string replacement_text,
|
std::string replacement_text,
|
||||||
std::string& wgsl_code) {
|
std::string& wgsl_code) {
|
||||||
|
@ -199,9 +204,7 @@ void ReplaceInterval(size_t start_index,
|
||||||
wgsl_code.replace(start_index, length, replacement_text);
|
wgsl_code.replace(start_index, length, replacement_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SwapRandomIntervals(const std::string& delimiter,
|
bool WgslMutator::SwapRandomIntervals(const std::string& delimiter, std::string& wgsl_code) {
|
||||||
std::string& wgsl_code,
|
|
||||||
RandomGenerator& generator) {
|
|
||||||
std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
|
std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
|
||||||
|
|
||||||
// Need to have at least 3 indices.
|
// Need to have at least 3 indices.
|
||||||
|
@ -212,12 +215,12 @@ bool SwapRandomIntervals(const std::string& delimiter,
|
||||||
// Choose indices:
|
// Choose indices:
|
||||||
// interval_1_start < interval_1_end <= interval_2_start < interval_2_end
|
// interval_1_start < interval_1_end <= interval_2_start < interval_2_end
|
||||||
uint32_t interval_1_start =
|
uint32_t interval_1_start =
|
||||||
generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 2u);
|
generator_.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 2u);
|
||||||
uint32_t interval_1_end = generator.GetUInt32(
|
uint32_t interval_1_end = generator_.GetUInt32(
|
||||||
interval_1_start + 1u, static_cast<uint32_t>(delimiter_positions.size()) - 1u);
|
interval_1_start + 1u, static_cast<uint32_t>(delimiter_positions.size()) - 1u);
|
||||||
uint32_t interval_2_start =
|
uint32_t interval_2_start = generator_.GetUInt32(
|
||||||
generator.GetUInt32(interval_1_end, static_cast<uint32_t>(delimiter_positions.size()) - 1u);
|
interval_1_end, static_cast<uint32_t>(delimiter_positions.size()) - 1u);
|
||||||
uint32_t interval_2_end = generator.GetUInt32(
|
uint32_t interval_2_end = generator_.GetUInt32(
|
||||||
interval_2_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
|
interval_2_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
|
||||||
|
|
||||||
SwapIntervals(delimiter_positions[interval_1_start],
|
SwapIntervals(delimiter_positions[interval_1_start],
|
||||||
|
@ -229,9 +232,7 @@ bool SwapRandomIntervals(const std::string& delimiter,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeleteRandomInterval(const std::string& delimiter,
|
bool WgslMutator::DeleteRandomInterval(const std::string& delimiter, std::string& wgsl_code) {
|
||||||
std::string& wgsl_code,
|
|
||||||
RandomGenerator& generator) {
|
|
||||||
std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
|
std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
|
||||||
|
|
||||||
// Need to have at least 2 indices.
|
// Need to have at least 2 indices.
|
||||||
|
@ -240,9 +241,9 @@ bool DeleteRandomInterval(const std::string& delimiter,
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t interval_start =
|
uint32_t interval_start =
|
||||||
generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 1u);
|
generator_.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 1u);
|
||||||
uint32_t interval_end =
|
uint32_t interval_end = generator_.GetUInt32(interval_start + 1u,
|
||||||
generator.GetUInt32(interval_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
|
static_cast<uint32_t>(delimiter_positions.size()));
|
||||||
|
|
||||||
DeleteInterval(delimiter_positions[interval_start],
|
DeleteInterval(delimiter_positions[interval_start],
|
||||||
delimiter_positions[interval_end] - delimiter_positions[interval_start],
|
delimiter_positions[interval_end] - delimiter_positions[interval_start],
|
||||||
|
@ -251,9 +252,7 @@ bool DeleteRandomInterval(const std::string& delimiter,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DuplicateRandomInterval(const std::string& delimiter,
|
bool WgslMutator::DuplicateRandomInterval(const std::string& delimiter, std::string& wgsl_code) {
|
||||||
std::string& wgsl_code,
|
|
||||||
RandomGenerator& generator) {
|
|
||||||
std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
|
std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
|
||||||
|
|
||||||
// Need to have at least 2 indices
|
// Need to have at least 2 indices
|
||||||
|
@ -262,11 +261,11 @@ bool DuplicateRandomInterval(const std::string& delimiter,
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t interval_start =
|
uint32_t interval_start =
|
||||||
generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 1u);
|
generator_.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 1u);
|
||||||
uint32_t interval_end =
|
uint32_t interval_end = generator_.GetUInt32(interval_start + 1u,
|
||||||
generator.GetUInt32(interval_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
|
static_cast<uint32_t>(delimiter_positions.size()));
|
||||||
uint32_t duplication_point =
|
uint32_t duplication_point =
|
||||||
generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()));
|
generator_.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()));
|
||||||
|
|
||||||
DuplicateInterval(delimiter_positions[interval_start],
|
DuplicateInterval(delimiter_positions[interval_start],
|
||||||
delimiter_positions[interval_end] - delimiter_positions[interval_start],
|
delimiter_positions[interval_end] - delimiter_positions[interval_start],
|
||||||
|
@ -275,7 +274,7 @@ bool DuplicateRandomInterval(const std::string& delimiter,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReplaceRandomIdentifier(std::string& wgsl_code, RandomGenerator& generator) {
|
bool WgslMutator::ReplaceRandomIdentifier(std::string& wgsl_code) {
|
||||||
std::vector<std::pair<size_t, size_t>> identifiers = GetIdentifiers(wgsl_code);
|
std::vector<std::pair<size_t, size_t>> identifiers = GetIdentifiers(wgsl_code);
|
||||||
|
|
||||||
// Need at least 2 identifiers
|
// Need at least 2 identifiers
|
||||||
|
@ -283,12 +282,12 @@ bool ReplaceRandomIdentifier(std::string& wgsl_code, RandomGenerator& generator)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t id1_index = generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
|
uint32_t id1_index = generator_.GetUInt32(static_cast<uint32_t>(identifiers.size()));
|
||||||
uint32_t id2_index = generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
|
uint32_t id2_index = generator_.GetUInt32(static_cast<uint32_t>(identifiers.size()));
|
||||||
|
|
||||||
// The two identifiers must be different
|
// The two identifiers must be different
|
||||||
while (id1_index == id2_index) {
|
while (id1_index == id2_index) {
|
||||||
id2_index = generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
|
id2_index = generator_.GetUInt32(static_cast<uint32_t>(identifiers.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplaceRegion(identifiers[id1_index].first, identifiers[id1_index].second,
|
ReplaceRegion(identifiers[id1_index].first, identifiers[id1_index].second,
|
||||||
|
@ -297,7 +296,7 @@ bool ReplaceRandomIdentifier(std::string& wgsl_code, RandomGenerator& generator)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReplaceRandomIntLiteral(std::string& wgsl_code, RandomGenerator& generator) {
|
bool WgslMutator::ReplaceRandomIntLiteral(std::string& wgsl_code) {
|
||||||
std::vector<std::pair<size_t, size_t>> literals = GetIntLiterals(wgsl_code);
|
std::vector<std::pair<size_t, size_t>> literals = GetIntLiterals(wgsl_code);
|
||||||
|
|
||||||
// Need at least one integer literal
|
// Need at least one integer literal
|
||||||
|
@ -305,13 +304,13 @@ bool ReplaceRandomIntLiteral(std::string& wgsl_code, RandomGenerator& generator)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t literal_index = generator.GetUInt32(static_cast<uint32_t>(literals.size()));
|
uint32_t literal_index = generator_.GetUInt32(static_cast<uint32_t>(literals.size()));
|
||||||
|
|
||||||
// INT_MAX = 2147483647, INT_MIN = -2147483648
|
// INT_MAX = 2147483647, INT_MIN = -2147483648
|
||||||
std::vector<std::string> boundary_values = {"2147483647", "-2147483648", "1",
|
std::vector<std::string> boundary_values = {"2147483647", "-2147483648", "1",
|
||||||
"-1", "0", "4294967295"};
|
"-1", "0", "4294967295"};
|
||||||
|
|
||||||
uint32_t boundary_index = generator.GetUInt32(static_cast<uint32_t>(boundary_values.size()));
|
uint32_t boundary_index = generator_.GetUInt32(static_cast<uint32_t>(boundary_values.size()));
|
||||||
|
|
||||||
ReplaceInterval(literals[literal_index].first, literals[literal_index].second,
|
ReplaceInterval(literals[literal_index].first, literals[literal_index].second,
|
||||||
boundary_values[boundary_index], wgsl_code);
|
boundary_values[boundary_index], wgsl_code);
|
||||||
|
|
|
@ -23,152 +23,153 @@
|
||||||
|
|
||||||
namespace tint::fuzzers::regex_fuzzer {
|
namespace tint::fuzzers::regex_fuzzer {
|
||||||
|
|
||||||
/// A function that given a delimiter, returns a vector that contains
|
/// Class encapsulating code for regex-based mutation of WGSL shaders.
|
||||||
/// all the positions of the delimiter in the WGSL code.
|
class WgslMutator {
|
||||||
/// @param delimiter - the delimiter of the enclosed region.
|
public:
|
||||||
/// @param wgsl_code - the initial string (WGSL code) that will be mutated.
|
/// Constructor
|
||||||
/// @return a vector with the positions of the delimiter in the WGSL code.
|
/// @param generator - pseudo-random generator to use in mutator
|
||||||
std::vector<size_t> FindDelimiterIndices(const std::string& delimiter,
|
explicit WgslMutator(RandomGenerator& generator);
|
||||||
const std::string& wgsl_code);
|
|
||||||
|
|
||||||
/// A function that finds all the identifiers in a WGSL-like string.
|
/// A function that, given WGSL-like string and a delimiter,
|
||||||
/// @param wgsl_code - the WGSL-like string where the identifiers will be found.
|
/// generates another WGSL-like string by picking two random regions
|
||||||
/// @return a vector with the positions and the length of all the
|
/// enclosed by the delimiter and swapping them.
|
||||||
/// identifiers in wgsl_code.
|
/// @param delimiter - the delimiter that will be used to find enclosed regions.
|
||||||
std::vector<std::pair<size_t, size_t>> GetIdentifiers(const std::string& wgsl_code);
|
/// @param wgsl_code - the initial string (WGSL code) that will be mutated.
|
||||||
|
/// @return true if a swap happened or false otherwise.
|
||||||
|
bool SwapRandomIntervals(const std::string& delimiter, std::string& wgsl_code);
|
||||||
|
|
||||||
/// A function that returns returns the starting position
|
/// A function that, given a WGSL-like string and a delimiter,
|
||||||
/// and the length of all the integer literals in a WGSL-like string.
|
/// generates another WGSL-like string by deleting a random
|
||||||
/// @param wgsl_code - the WGSL-like string where the int literals
|
/// region enclosed by the delimiter.
|
||||||
/// will be found.
|
/// @param delimiter - the delimiter that will be used to find enclosed regions.
|
||||||
/// @return a vector with the starting positions and the length
|
/// @param wgsl_code - the initial string (WGSL code) that will be mutated.
|
||||||
/// of all the integer literals.
|
/// @return true if a deletion happened or false otherwise.
|
||||||
std::vector<std::pair<size_t, size_t>> GetIntLiterals(const std::string& wgsl_code);
|
bool DeleteRandomInterval(const std::string& delimiter, std::string& wgsl_code);
|
||||||
|
|
||||||
/// Finds a possible closing brace corresponding to the opening
|
/// A function that, given a WGSL-like string and a delimiter,
|
||||||
/// brace at position opening_bracket_pos.
|
/// generates another WGSL-like string by duplicating a random
|
||||||
/// @param opening_bracket_pos - the position of the opening brace.
|
/// region enclosed by the delimiter.
|
||||||
/// @param wgsl_code - the WGSL-like string where the closing brace.
|
/// @param delimiter - the delimiter that will be used to find enclosed regions.
|
||||||
/// @return the position of the closing bracket or 0 if there is no closing
|
/// @param wgsl_code - the initial string (WGSL code) that will be mutated.
|
||||||
/// brace.
|
/// @return true if a duplication happened or false otherwise.
|
||||||
size_t FindClosingBrace(size_t opening_bracket_pos, const std::string& wgsl_code);
|
bool DuplicateRandomInterval(const std::string& delimiter, std::string& wgsl_code);
|
||||||
|
|
||||||
/// Returns the starting_position of the bodies of the functions
|
/// Replaces a randomly-chosen identifier in wgsl_code.
|
||||||
/// that follow the regular expression: fn.*?->.*?\\{, which searches for the
|
/// @param wgsl_code - WGSL-like string where the replacement will occur.
|
||||||
/// keyword fn followed by the function name, its return type and opening brace.
|
/// @return true if a replacement happened or false otherwise.
|
||||||
/// @param wgsl_code - the WGSL-like string where the functions will be
|
bool ReplaceRandomIdentifier(std::string& wgsl_code);
|
||||||
/// searched.
|
|
||||||
/// @return a vector with the starting position of the function bodies in
|
|
||||||
/// wgsl_code.
|
|
||||||
std::vector<size_t> GetFunctionBodyPositions(const std::string& wgsl_code);
|
|
||||||
|
|
||||||
/// Given 4 indices, idx1, idx2, idx3 and idx4 it swaps the regions
|
/// Replaces the value of a randomly-chosen integer with one of
|
||||||
/// in the interval (idx1, idx2] with the region in the interval (idx3, idx4]
|
/// the values in the set {INT_MAX, INT_MIN, 0, -1}.
|
||||||
/// in wgsl_text.
|
/// @param wgsl_code - WGSL-like string where the replacement will occur.
|
||||||
/// @param idx1 - starting index of the first region.
|
/// @return true if a replacement happened or false otherwise.
|
||||||
/// @param reg1_len - length of the first region.
|
bool ReplaceRandomIntLiteral(std::string& wgsl_code);
|
||||||
/// @param idx2 - starting index of the second region.
|
|
||||||
/// @param reg2_len - length of the second region.
|
|
||||||
/// @param wgsl_code - the string where the swap will occur.
|
|
||||||
void SwapIntervals(size_t idx1,
|
|
||||||
size_t reg1_len,
|
|
||||||
size_t idx2,
|
|
||||||
size_t reg2_len,
|
|
||||||
std::string& wgsl_code);
|
|
||||||
|
|
||||||
/// Given index idx1 it delets the region of length interval_len
|
/// Inserts a return statement in a randomly chosen function of a
|
||||||
/// starting at index idx1;
|
/// WGSL-like string. The return value is a randomly-chosen identifier
|
||||||
/// @param idx1 - starting index of the first region.
|
/// or literal in the string.
|
||||||
/// @param reg_len - terminating index of the second region.
|
/// @param wgsl_code - WGSL-like string that will be mutated.
|
||||||
/// @param wgsl_code - the string where the swap will occur.
|
/// @return true if the mutation was succesful or false otherwise.
|
||||||
void DeleteInterval(size_t idx1, size_t reg_len, std::string& wgsl_code);
|
bool InsertReturnStatement(std::string& wgsl_code);
|
||||||
|
|
||||||
/// Given 2 indices, idx1, idx2, it inserts the region of length
|
protected:
|
||||||
/// reg1_len starting at idx1 after idx2.
|
/// Given index idx1 it delets the region of length interval_len
|
||||||
/// @param idx1 - starting index of region.
|
/// starting at index idx1;
|
||||||
/// @param reg1_len - length of the region.
|
/// @param idx1 - starting index of the first region.
|
||||||
/// @param idx2 - the position where the region will be inserted.
|
/// @param reg_len - terminating index of the second region.
|
||||||
/// @param wgsl_code - the string where the swap will occur.
|
/// @param wgsl_code - the string where the swap will occur.
|
||||||
void DuplicateInterval(size_t idx1, size_t reg1_len, size_t idx2, std::string& wgsl_code);
|
void DeleteInterval(size_t idx1, size_t reg_len, std::string& wgsl_code);
|
||||||
|
|
||||||
/// Replaces a region of a WGSL-like string of length id2_len starting
|
/// Given 2 indices, idx1, idx2, it inserts the region of length
|
||||||
/// at position idx2 with a region of length id1_len starting at
|
/// reg1_len starting at idx1 after idx2.
|
||||||
/// position idx1.
|
/// @param idx1 - starting index of region.
|
||||||
/// @param idx1 - starting position of the first region.
|
/// @param reg1_len - length of the region.
|
||||||
/// @param id1_len - length of the first region.
|
/// @param idx2 - the position where the region will be inserted.
|
||||||
/// @param idx2 - starting position of the second region.
|
/// @param wgsl_code - the string where the swap will occur.
|
||||||
/// @param id2_len - length of the second region.
|
void DuplicateInterval(size_t idx1, size_t reg1_len, size_t idx2, std::string& wgsl_code);
|
||||||
/// @param wgsl_code - the string where the replacement will occur.
|
|
||||||
void ReplaceRegion(size_t idx1,
|
/// Finds a possible closing brace corresponding to the opening
|
||||||
|
/// brace at position opening_bracket_pos.
|
||||||
|
/// @param opening_bracket_pos - the position of the opening brace.
|
||||||
|
/// @param wgsl_code - the WGSL-like string where the closing brace.
|
||||||
|
/// @return the position of the closing bracket or 0 if there is no closing
|
||||||
|
/// brace.
|
||||||
|
size_t FindClosingBrace(size_t opening_bracket_pos, const std::string& wgsl_code);
|
||||||
|
|
||||||
|
/// Returns the starting_position of the bodies of the functions
|
||||||
|
/// that follow the regular expression: fn.*?->.*?\\{, which searches for the
|
||||||
|
/// keyword fn followed by the function name, its return type and opening brace.
|
||||||
|
/// @param wgsl_code - the WGSL-like string where the functions will be
|
||||||
|
/// searched.
|
||||||
|
/// @return a vector with the starting position of the function bodies in
|
||||||
|
/// wgsl_code.
|
||||||
|
std::vector<size_t> GetFunctionBodyPositions(const std::string& wgsl_code);
|
||||||
|
|
||||||
|
/// A function that finds all the identifiers in a WGSL-like string.
|
||||||
|
/// @param wgsl_code - the WGSL-like string where the identifiers will be found.
|
||||||
|
/// @return a vector with the positions and the length of all the
|
||||||
|
/// identifiers in wgsl_code.
|
||||||
|
std::vector<std::pair<size_t, size_t>> GetIdentifiers(const std::string& wgsl_code);
|
||||||
|
|
||||||
|
/// A function that returns returns the starting position
|
||||||
|
/// and the length of all the integer literals in a WGSL-like string.
|
||||||
|
/// @param wgsl_code - the WGSL-like string where the int literals
|
||||||
|
/// will be found.
|
||||||
|
/// @return a vector with the starting positions and the length
|
||||||
|
/// of all the integer literals.
|
||||||
|
std::vector<std::pair<size_t, size_t>> GetIntLiterals(const std::string& wgsl_code);
|
||||||
|
|
||||||
|
/// Replaces a region of a WGSL-like string of length id2_len starting
|
||||||
|
/// at position idx2 with a region of length id1_len starting at
|
||||||
|
/// position idx1.
|
||||||
|
/// @param idx1 - starting position of the first region.
|
||||||
|
/// @param id1_len - length of the first region.
|
||||||
|
/// @param idx2 - starting position of the second region.
|
||||||
|
/// @param id2_len - length of the second region.
|
||||||
|
/// @param wgsl_code - the string where the replacement will occur.
|
||||||
|
void ReplaceRegion(size_t idx1,
|
||||||
size_t id1_len,
|
size_t id1_len,
|
||||||
size_t idx2,
|
size_t idx2,
|
||||||
size_t id2_len,
|
size_t id2_len,
|
||||||
std::string& wgsl_code);
|
std::string& wgsl_code);
|
||||||
|
|
||||||
/// Replaces an interval of length `length` starting at start_index
|
/// Given 4 indices, idx1, idx2, idx3 and idx4 it swaps the regions
|
||||||
/// with the `replacement_text`.
|
/// in the interval (idx1, idx2] with the region in the interval (idx3, idx4]
|
||||||
/// @param start_index - starting position of the interval to be replaced.
|
/// in wgsl_text.
|
||||||
/// @param length - length of the interval to be replaced.
|
/// @param idx1 - starting index of the first region.
|
||||||
/// @param replacement_text - the interval that will be used as a replacement.
|
/// @param reg1_len - length of the first region.
|
||||||
/// @param wgsl_code - the WGSL-like string where the replacement will occur.
|
/// @param idx2 - starting index of the second region.
|
||||||
void ReplaceInterval(size_t start_index,
|
/// @param reg2_len - length of the second region.
|
||||||
|
/// @param wgsl_code - the string where the swap will occur.
|
||||||
|
void SwapIntervals(size_t idx1,
|
||||||
|
size_t reg1_len,
|
||||||
|
size_t idx2,
|
||||||
|
size_t reg2_len,
|
||||||
|
std::string& wgsl_code);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// A function that given a delimiter, returns a vector that contains
|
||||||
|
/// all the positions of the delimiter in the WGSL code.
|
||||||
|
/// @param delimiter - the delimiter of the enclosed region.
|
||||||
|
/// @param wgsl_code - the initial string (WGSL code) that will be mutated.
|
||||||
|
/// @return a vector with the positions of the delimiter in the WGSL code.
|
||||||
|
std::vector<size_t> FindDelimiterIndices(const std::string& delimiter,
|
||||||
|
const std::string& wgsl_code);
|
||||||
|
|
||||||
|
/// Replaces an interval of length `length` starting at start_index
|
||||||
|
/// with the `replacement_text`.
|
||||||
|
/// @param start_index - starting position of the interval to be replaced.
|
||||||
|
/// @param length - length of the interval to be replaced.
|
||||||
|
/// @param replacement_text - the interval that will be used as a replacement.
|
||||||
|
/// @param wgsl_code - the WGSL-like string where the replacement will occur.
|
||||||
|
void ReplaceInterval(size_t start_index,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string replacement_text,
|
std::string replacement_text,
|
||||||
std::string& wgsl_code);
|
std::string& wgsl_code);
|
||||||
|
|
||||||
/// A function that, given WGSL-like string and a delimiter,
|
RandomGenerator& generator_;
|
||||||
/// generates another WGSL-like string by picking two random regions
|
};
|
||||||
/// enclosed by the delimiter and swapping them.
|
|
||||||
/// @param delimiter - the delimiter that will be used to find enclosed regions.
|
|
||||||
/// @param wgsl_code - the initial string (WGSL code) that will be mutated.
|
|
||||||
/// @param generator - the random number generator.
|
|
||||||
/// @return true if a swap happened or false otherwise.
|
|
||||||
bool SwapRandomIntervals(const std::string& delimiter,
|
|
||||||
std::string& wgsl_code,
|
|
||||||
RandomGenerator& generator);
|
|
||||||
|
|
||||||
/// A function that, given a WGSL-like string and a delimiter,
|
|
||||||
/// generates another WGSL-like string by deleting a random
|
|
||||||
/// region enclosed by the delimiter.
|
|
||||||
/// @param delimiter - the delimiter that will be used to find enclosed regions.
|
|
||||||
/// @param wgsl_code - the initial string (WGSL code) that will be mutated.
|
|
||||||
/// @param generator - the random number generator.
|
|
||||||
/// @return true if a deletion happened or false otherwise.
|
|
||||||
bool DeleteRandomInterval(const std::string& delimiter,
|
|
||||||
std::string& wgsl_code,
|
|
||||||
RandomGenerator& generator);
|
|
||||||
|
|
||||||
/// A function that, given a WGSL-like string and a delimiter,
|
|
||||||
/// generates another WGSL-like string by duplicating a random
|
|
||||||
/// region enclosed by the delimiter.
|
|
||||||
/// @param delimiter - the delimiter that will be used to find enclosed regions.
|
|
||||||
/// @param wgsl_code - the initial string (WGSL code) that will be mutated.
|
|
||||||
/// @param generator - the random number generator.
|
|
||||||
/// @return true if a duplication happened or false otherwise.
|
|
||||||
bool DuplicateRandomInterval(const std::string& delimiter,
|
|
||||||
std::string& wgsl_code,
|
|
||||||
RandomGenerator& generator);
|
|
||||||
|
|
||||||
/// Replaces a randomly-chosen identifier in wgsl_code.
|
|
||||||
/// @param wgsl_code - WGSL-like string where the replacement will occur.
|
|
||||||
/// @param generator - the random number generator.
|
|
||||||
/// @return true if a replacement happened or false otherwise.
|
|
||||||
bool ReplaceRandomIdentifier(std::string& wgsl_code, RandomGenerator& generator);
|
|
||||||
|
|
||||||
/// Replaces the value of a randomly-chosen integer with one of
|
|
||||||
/// the values in the set {INT_MAX, INT_MIN, 0, -1}.
|
|
||||||
/// @param wgsl_code - WGSL-like string where the replacement will occur.
|
|
||||||
/// @param generator - the random number generator.
|
|
||||||
/// @return true if a replacement happened or false otherwise.
|
|
||||||
bool ReplaceRandomIntLiteral(std::string& wgsl_code, RandomGenerator& generator);
|
|
||||||
|
|
||||||
/// Inserts a return statement in a randomly chosen function of a
|
|
||||||
/// WGSL-like string. The return value is a randomly-chosen identifier
|
|
||||||
/// or literal in the string.
|
|
||||||
/// @param wgsl_code - WGSL-like string that will be mutated.
|
|
||||||
/// @param generator - the random number generator.
|
|
||||||
/// @return true if the mutation was succesful or false otherwise.
|
|
||||||
bool InsertReturnStatement(std::string& wgsl_code, RandomGenerator& generator);
|
|
||||||
} // namespace tint::fuzzers::regex_fuzzer
|
} // namespace tint::fuzzers::regex_fuzzer
|
||||||
|
|
||||||
#endif // SRC_TINT_FUZZERS_TINT_REGEX_FUZZER_WGSL_MUTATOR_H_
|
#endif // SRC_TINT_FUZZERS_TINT_REGEX_FUZZER_WGSL_MUTATOR_H_
|
||||||
|
|
Loading…
Reference in New Issue