chromium/components/url_formatter/url_fixer_fuzzer.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdint.h>

#include <string>
#include <tuple>

#include <fuzzer/FuzzedDataProvider.h>

#include "base/at_exit.h"
#include "base/check.h"
#include "base/files/file_path.h"
#include "base/i18n/icu_util.h"
#include "base/logging.h"
#include "base/strings/escape.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/url_formatter/url_fixer.h"
#include "components/url_formatter/url_formatter.h"
#include "url/third_party/mozilla/url_parse.h"

namespace {

// Performs initialization and holds state that's shared across all runs.
class Environment {
 public:
  Environment() {
    CHECK(base::i18n::InitializeICU());
    logging::SetMinLogLevel(logging::LOGGING_FATAL);
  }

 private:
  base::AtExitManager at_exit_manager_;
};

base::FilePath GenerateFuzzedFilePath(FuzzedDataProvider& provider) {
  const std::string raw_string = provider.ConsumeRandomLengthString();
#if BUILDFLAG(IS_WIN)
  return base::FilePath(base::UTF8ToWide(raw_string));
#else
  return base::FilePath(raw_string);
#endif
}

const size_t kMaxFuzzerInputBytes = 100 * 1024;

}  // namespace

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  if (size > kMaxFuzzerInputBytes) {
    return 0;
  }

  static Environment env;
  FuzzedDataProvider provider(data, size);

  switch (provider.ConsumeIntegralInRange<int>(0, 4)) {
    case 0: {
      std::string text = provider.ConsumeRandomLengthString();
      url::Parsed parts;
      std::ignore = url_formatter::SegmentURL(text, &parts);
      break;
    }
    case 1: {
      std::u16string text =
          base::UTF8ToUTF16(provider.ConsumeRandomLengthString());
      url::Parsed parts;
      std::ignore = url_formatter::SegmentURL(text, &parts);
      break;
    }
    case 2: {
      std::ignore =
          url_formatter::FixupURL(provider.ConsumeRandomLengthString(),
                                  provider.ConsumeRandomLengthString());
      break;
    }
    case 3: {
      std::ignore = url_formatter::FixupRelativeFile(
          GenerateFuzzedFilePath(provider), GenerateFuzzedFilePath(provider));
      break;
    }
    case 4: {
      url::Parsed parsed;
      GURL unparsed(provider.ConsumeRandomLengthString());
      // Get any valid bitmask of the FormatUrlType options
      const uint32_t kCurrentMaxFormatUrlType =
          url_formatter::kFormatUrlOmitMobilePrefix;
      url_formatter::FormatUrlType format_url_type =
          provider.ConsumeIntegralInRange(
              0U, ((kCurrentMaxFormatUrlType << 1) - 1));
      // Get any valid bitmask of the UnescapeRule types
      const uint32_t kCurrentMaxUnescapeRuleType =
          base::UnescapeRule::REPLACE_PLUS_WITH_SPACE;
      base::UnescapeRule::Type unescape_rule_type =
          provider.ConsumeIntegralInRange(
              0U, ((kCurrentMaxUnescapeRuleType << 1) - 1));
      url_formatter::FormatUrl(unparsed, format_url_type, unescape_rule_type,
                               &parsed, nullptr, nullptr);
      break;
    }
  }

  return 0;
}