File size: 2,538 Bytes
a00553a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// libFuzzer harness for Program::load_method() -> Method::init()
// Targets the ExecutionPlan.delegates iteration in Method::init() specifically -
// this loop runs BEFORE any kernel/backend resolution, so no kernel or backend
// registration is required to reach it.
#include <cstddef>
#include <cstdint>
#include <memory>
#include <vector>

#include <executorch/extension/data_loader/buffer_data_loader.h>
#include <executorch/runtime/executor/method.h>
#include <executorch/runtime/executor/program.h>
#include <executorch/runtime/core/memory_allocator.h>
#include <executorch/runtime/core/hierarchical_allocator.h>
#include <executorch/runtime/executor/memory_manager.h>
#include <executorch/runtime/platform/runtime.h>

using executorch::extension::BufferDataLoader;
using executorch::runtime::Program;
using executorch::runtime::Method;
using executorch::runtime::MemoryAllocator;
using executorch::runtime::HierarchicalAllocator;
using executorch::runtime::MemoryManager;
using executorch::runtime::Span;

static bool g_initialized = false;

extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) {
  if (!g_initialized) {
    executorch::runtime::runtime_init();
    g_initialized = true;
  }

  constexpr std::size_t kMaxInput = 8U * 1024U * 1024U;
  if (data == nullptr || size == 0 || size > kMaxInput) {
    return 0;
  }

  BufferDataLoader loader(data, size);
  auto program = Program::load(&loader, Program::Verification::InternalConsistency);
  if (!program.ok()) {
    return 0;
  }

  // Minimal allocators - large enough for a tiny ExecutionPlan with no real
  // tensors/kernels; we only need to reach Method::init()'s delegates loop.
  static std::vector<uint8_t> method_pool(256 * 1024);
  static std::vector<uint8_t> planned_pool(64 * 1024);
  MemoryAllocator method_allocator(method_pool.size(), method_pool.data());
  static Span<uint8_t> planned_span(planned_pool.data(), planned_pool.size());
  HierarchicalAllocator planned_memory({&planned_span, 1});
  MemoryManager mm(&method_allocator, &planned_memory, nullptr);

  auto& p = program.get();
  auto n = p.num_methods();
  for (size_t i = 0; i < n; ++i) {
    auto name = p.get_method_name(i);
    if (name.ok()) {
      // load_method() calls Method::init() internally. We expect this to
      // fail gracefully for most fuzzer inputs (missing kernels, etc) -
      // we're specifically hunting for a crash, not a successful load.
      auto method = p.load_method(name.get(), &mm);
      (void)method;
    }
  }
  return 0;
}