diff --git a/fuzzers/tint_regex_fuzzer/fuzzer.cc b/fuzzers/tint_regex_fuzzer/fuzzer.cc index cc87cf590f..57eecffbc2 100644 --- a/fuzzers/tint_regex_fuzzer/fuzzer.cc +++ b/fuzzers/tint_regex_fuzzer/fuzzer.cc @@ -35,6 +35,8 @@ enum class MutationKind { kSwapIntervals, kDeleteInterval, kDuplicateInterval, + kReplaceIdentifier, + kReplaceLiteral, kNumMutationKinds }; @@ -78,6 +80,18 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, } break; + case MutationKind::kReplaceIdentifier: + if (!ReplaceRandomIdentifier(wgsl_code, generator)) { + return 0; + } + break; + + case MutationKind::kReplaceLiteral: + if (!ReplaceRandomIntLiteral(wgsl_code, generator)) { + return 0; + } + break; + default: assert(false && "Unreachable"); return 0; diff --git a/fuzzers/tint_regex_fuzzer/regex_fuzzer_tests.cc b/fuzzers/tint_regex_fuzzer/regex_fuzzer_tests.cc index 252958cbbb..94fe68fb56 100644 --- a/fuzzers/tint_regex_fuzzer/regex_fuzzer_tests.cc +++ b/fuzzers/tint_regex_fuzzer/regex_fuzzer_tests.cc @@ -226,6 +226,40 @@ TEST(GetIdentifierTest, GetIdentifierTest1) { ASSERT_EQ(ground_truth, identifiers_pos); } +TEST(TestGetLiteralsValues, TestGetLiteralsValues1) { + std::string wgsl_code = + "fn clamp_0acf8f() {" + "var res: vec2 = clamp(vec2(), vec2(), vec2());}" + "[[stage(vertex)]]" + "fn vertex_main() -> [[builtin(position)]] vec4 {" + " clamp_0acf8f();" + "var foo_1: i32 = 3;" + " return vec4();}" + "[[stage(fragment)]]" + "fn fragment_main() {" + " clamp_0acf8f();}" + "[[stage(compute), workgroup_size(1)]]" + "fn compute_main() {" + "var foo: f32 = 0.0;" + "var foo_2: i32 = 10;" + " clamp_0acf8f();}" + "foo_1 = 5 + 7;" + "var foo_3 : i32 = -20;"; + + std::vector> literals_pos = + GetIntLiterals(wgsl_code); + + std::vector ground_truth = {"3", "10", "5", "7", "-20"}; + + std::vector result; + + for (auto pos : literals_pos) { + result.push_back(wgsl_code.substr(pos.first, pos.second)); + } + + ASSERT_EQ(ground_truth, result); +} + } // namespace } // namespace regex_fuzzer } // namespace fuzzers diff --git a/fuzzers/tint_regex_fuzzer/wgsl_mutator.cc b/fuzzers/tint_regex_fuzzer/wgsl_mutator.cc index cb1f85019a..2745001eeb 100644 --- a/fuzzers/tint_regex_fuzzer/wgsl_mutator.cc +++ b/fuzzers/tint_regex_fuzzer/wgsl_mutator.cc @@ -67,6 +67,29 @@ std::vector> GetIdentifiers( return result; } +std::vector> GetIntLiterals(const std::string& s) { + std::vector> result; + + // Looks for integer literals in decimal or hexadecimal form. + // Regex obtained here: https://www.w3.org/TR/WGSL/#literals + std::regex int_literal_regex("-?0x[0-9a-fA-F]+ | 0 | -?[1-9][0-9]*"); + std::regex uint_literal_regex("0x[0-9a-fA-F]+u | 0u | [1-9][0-9]*u"); + std::smatch match; + + std::string::const_iterator search_start(s.cbegin()); + std::string prefix = ""; + + while (regex_search(search_start, s.cend(), match, int_literal_regex) || + regex_search(search_start, s.cend(), match, uint_literal_regex)) { + prefix += match.prefix(); + result.push_back( + std::make_pair(prefix.size() + 1, match.str(0).size() - 1)); + prefix += match.str(0); + search_start = match.suffix().first; + } + return result; +} + void SwapIntervals(size_t idx1, size_t reg1_len, size_t idx2, @@ -76,7 +99,7 @@ void SwapIntervals(size_t idx1, std::string region_2 = wgsl_code.substr(idx2 + 1, reg2_len - 1); - // The second transformation is done first as it doesn't affect ind1 and ind2 + // The second transformation is done first as it doesn't affect idx2. wgsl_code.replace(idx2 + 1, region_2.size(), region_1); wgsl_code.replace(idx1 + 1, region_1.size(), region_2); @@ -104,6 +127,14 @@ void ReplaceRegion(size_t idx1, wgsl_code.replace(idx2, region_2.size(), region_1); } +void ReplaceInterval(size_t start_index, + size_t length, + std::string replacement_text, + std::string& wgsl_code) { + std::string region_1 = wgsl_code.substr(start_index, length); + wgsl_code.replace(start_index, length, replacement_text); +} + bool SwapRandomIntervals(const std::string& delimiter, std::string& wgsl_code, std::mt19937& generator) { @@ -211,6 +242,29 @@ bool ReplaceRandomIdentifier(std::string& wgsl_code, std::mt19937& generator) { return true; } +bool ReplaceRandomIntLiteral(std::string& wgsl_code, std::mt19937& generator) { + std::vector> literals = GetIntLiterals(wgsl_code); + + // Need at least one integer literal + if (literals.size() < 1) { + return false; + } + + size_t id1_index = GetRandomIntFromRange(0, literals.size() - 1U, generator); + + // INT_MAX = 2147483647, INT_MIN = -2147483648 + std::vector boundary_values = { + "2147483647", "-2147483648", "1", "-1", "0", "4294967295"}; + + size_t boundary_index = + GetRandomIntFromRange(0, boundary_values.size() - 1U, generator); + + ReplaceInterval(literals[id1_index].first, literals[id1_index].second, + boundary_values[boundary_index], wgsl_code); + + return true; +} + } // namespace regex_fuzzer } // namespace fuzzers } // namespace tint diff --git a/fuzzers/tint_regex_fuzzer/wgsl_mutator.h b/fuzzers/tint_regex_fuzzer/wgsl_mutator.h index bd7975bfc3..1af6b025ce 100644 --- a/fuzzers/tint_regex_fuzzer/wgsl_mutator.h +++ b/fuzzers/tint_regex_fuzzer/wgsl_mutator.h @@ -39,6 +39,15 @@ std::vector FindDelimiterIndices(const std::string& delimiter, std::vector> 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> GetIntLiterals( + const std::string& wgsl_code); + /// Given 4 indices, idx1, idx2, idx3 and idx4 it swaps the regions /// in the interval (idx1, idx2] with the region in the interval (idx3, idx4] /// in wgsl_text. @@ -74,16 +83,28 @@ void DuplicateInterval(size_t idx1, /// 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 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 idx2, size_t id2_len, std::string& wgsl_code); +/// Replaces an interval of length interval1_len starting at start_index +/// with the interval interval2. +/// @param start_index - starting position of the interval to be replaced. +/// @param interval1_len - 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, + std::string replacement_text, + std::string& wgsl_code); + /// A function that, given WGSL-like string and a delimiter, /// generates another WGSL-like string by picking two random regions /// enclosed by the delimiter and swapping them. @@ -117,13 +138,19 @@ bool DuplicateRandomInterval(const std::string& delimiter, std::string& wgsl_code, std::mt19937& generator); -/// Replaces a random identifier in wgsl_code. +/// 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, std::mt19937& 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, std::mt19937& generator); + } // namespace regex_fuzzer } // namespace fuzzers } // namespace tint