driver_fuzzer.cpp 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include <cstdint>
  5. #include <cstring>
  6. #include <numeric>
  7. #include <string>
  8. #include "driver/driver.h"
  9. #include "llvm/ADT/SmallVector.h"
  10. #include "llvm/ADT/StringRef.h"
  11. #include "llvm/Support/raw_ostream.h"
  12. namespace Carbon {
  13. static auto Read(const unsigned char*& data, size_t& size, int& output)
  14. -> bool {
  15. if (size < sizeof(output)) {
  16. return false;
  17. }
  18. std::memcpy(&output, data, sizeof(output));
  19. size -= sizeof(output);
  20. data += sizeof(output);
  21. return true;
  22. }
  23. extern "C" auto LLVMFuzzerTestOneInput(const unsigned char* data, size_t size)
  24. -> int {
  25. // First use the data to compute the number of arguments. Note that for
  26. // scaling reasons we don't allow 2^31 arguments, even empty ones. Simply
  27. // creating the vector of those won't work. We limit this to 2^20 arguments
  28. // total.
  29. int num_args;
  30. if (!Read(data, size, num_args) || num_args < 0 || num_args > (1 << 20)) {
  31. return 0;
  32. }
  33. // Now use the data to compute the length of each argument. We don't want to
  34. // exhaust all memory, so bound the search space to using 2^17 bytes of
  35. // memory for the argument text itself.
  36. size_t arg_length_sum = 0;
  37. llvm::SmallVector<int, 16> arg_lengths(num_args);
  38. for (int& arg_length : arg_lengths) {
  39. if (!Read(data, size, arg_length) || arg_length < 0) {
  40. return 0;
  41. }
  42. arg_length_sum += arg_length;
  43. if (arg_length_sum > (1 << 17)) {
  44. return 0;
  45. }
  46. }
  47. // Ensure we have enough data for all the arguments.
  48. if (size < arg_length_sum) {
  49. return 0;
  50. }
  51. // Lastly, read the contents of each argument out of the data.
  52. llvm::SmallVector<llvm::StringRef, 16> args;
  53. args.reserve(num_args);
  54. for (int arg_length : arg_lengths) {
  55. args.push_back(
  56. llvm::StringRef(reinterpret_cast<const char*>(data), arg_length));
  57. data += arg_length;
  58. size -= arg_length;
  59. }
  60. std::string error_text;
  61. llvm::raw_string_ostream error_stream(error_text);
  62. llvm::raw_null_ostream output_stream;
  63. Driver d(output_stream, error_stream);
  64. if (!d.RunFullCommand(args)) {
  65. error_stream.flush();
  66. if (error_text.find("ERROR:") == std::string::npos) {
  67. llvm::errs() << "No error message on a failure!\n";
  68. return 1;
  69. }
  70. }
  71. return 0;
  72. }
  73. } // namespace Carbon