driver_fuzzer.cpp 2.4 KB

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