parse_fuzzer.cc 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by an MIT-style license that can be
  3. // found in the LICENSE file.
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include <string>
  7. #include "base/check.h"
  8. #include "base/check_op.h"
  9. #include "base/containers/span.h"
  10. #include "base/logging.h"
  11. #include "base/strings/strcat.h"
  12. #include "base/strings/string_util.h"
  13. #include "third_party/abseil-cpp/absl/status/statusor.h"
  14. #include "third_party/abseil-cpp/absl/strings/str_format.h"
  15. #include "third_party/abseil-cpp/absl/strings/string_view.h"
  16. #include "third_party/abseil-cpp/absl/types/optional.h"
  17. #include "third_party/liburlpattern/parse.h"
  18. #include "third_party/liburlpattern/pattern.h"
  19. namespace liburlpattern {
  20. namespace {
  21. absl::StatusOr<std::string> PassThrough(absl::string_view input) {
  22. return std::string(input);
  23. }
  24. absl::optional<std::string> ParseAndCanonicalize(absl::string_view s) {
  25. absl::StatusOr<Pattern> pattern = Parse(s, &PassThrough);
  26. if (!pattern.ok()) {
  27. LOG(INFO) << "Parse failed with status: " << pattern.status();
  28. return absl::nullopt;
  29. }
  30. return pattern->GeneratePatternString();
  31. }
  32. std::string FancyHexDump(base::StringPiece label, base::StringPiece data) {
  33. std::string char_line, hex_line;
  34. for (char c : data) {
  35. if (!base::IsAsciiPrintable(c))
  36. char_line.append(" [?]");
  37. else
  38. char_line.append(absl::StrFormat("%4c", c));
  39. hex_line.append(absl::StrFormat(" %02x", c));
  40. }
  41. return base::StrCat({label, "\n", char_line, "\n", hex_line});
  42. }
  43. struct Environment {
  44. Environment() { logging::SetMinLogLevel(logging::LOG_INFO); }
  45. };
  46. } // namespace
  47. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  48. static Environment env;
  49. // Make a copy of `data` on the heap to enable ASAN to catch OOB accesses.
  50. std::string pattern_string(reinterpret_cast<const char*>(data), size);
  51. absl::optional<std::string> canonical = ParseAndCanonicalize(pattern_string);
  52. if (!canonical)
  53. return 0;
  54. // If `Pattern::GeneratePatternString()` generates canonical strings,
  55. // recanonicalizing one of its outputs should always be a no-op. To test that
  56. // property, let's check that `ParseAndCanonicalize()` is idempotent, i.e.
  57. // that `canonical` is a fixed point of the function.
  58. absl::optional<std::string> canonical2 = ParseAndCanonicalize(*canonical);
  59. CHECK(canonical2)
  60. << "Failed to parse canonical pattern from original input.\n"
  61. << FancyHexDump("original : ", pattern_string) << "\n"
  62. << FancyHexDump("canonical: ", *canonical);
  63. CHECK_EQ(*canonical, *canonical2)
  64. << "Canonical pattern and its recanonicalization are not equal.\n"
  65. << FancyHexDump("canonical : ", *canonical) << "\n"
  66. << FancyHexDump("canonical2: ", *canonical2);
  67. return 0;
  68. }
  69. } // namespace liburlpattern