Coverage Report

Created: 2025-12-12 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/behaviortreecpp/fuzzing/bt_fuzzer.cpp
Line
Count
Source
1
#include <fuzzer/FuzzedDataProvider.h>
2
#include "behaviortree_cpp/bt_factory.h"
3
#include "behaviortree_cpp/xml_parsing.h"
4
#include <string>
5
6
// List of valid node types we can use to construct valid-ish XML
7
constexpr const char* NODE_TYPES[] = {
8
  "Sequence",         "Fallback",         "ParallelAll",
9
  "ReactiveSequence", "ReactiveFallback", "IfThenElse",
10
  "WhileDoElse",      "Inverter",         "RetryUntilSuccessful",
11
  "Repeat",           "Timeout",          "Delay",
12
  "ForceSuccess",     "ForceFailure",     "AlwaysSuccess",
13
  "AlwaysFailure",    "SetBlackboard",    "SubTree"
14
};
15
16
// Attributes that can be added to nodes
17
constexpr const char* NODE_ATTRIBUTES[] = { "name",      "ID",         "port_1",
18
                                            "port_2",    "timeout_ms", "delay_ms",
19
                                            "threshold", "max_repeats" };
20
21
std::string generateFuzzedNodeXML(FuzzedDataProvider& fdp, int depth = 0)
22
63.2k
{
23
  // Prevent stack overflow with max depth
24
63.2k
  if(depth > 6)
25
0
  {  // Reasonable limit for XML tree depth
26
0
    return "<AlwaysSuccess/>";
27
0
  }
28
29
63.2k
  std::string xml;
30
63.2k
  const std::string node_type = fdp.PickValueInArray(NODE_TYPES);
31
32
63.2k
  xml += "<" + node_type;
33
34
63.2k
  size_t num_attributes = fdp.ConsumeIntegralInRange<size_t>(0, 3);
35
152k
  for(size_t i = 0; i < num_attributes; i++)
36
89.5k
  {
37
89.5k
    const std::string attr = fdp.PickValueInArray(NODE_ATTRIBUTES);
38
89.5k
    std::string value = fdp.ConsumeRandomLengthString(10);
39
89.5k
    xml += " " + attr + "=\"" + value + "\"";
40
89.5k
  }
41
42
63.2k
  if(depth > 3 || fdp.ConsumeBool())
43
26.6k
  {
44
26.6k
    xml += "/>";
45
26.6k
  }
46
36.6k
  else
47
36.6k
  {
48
36.6k
    xml += ">";
49
    // Add some child nodes recursively with depth limit
50
36.6k
    size_t num_children = fdp.ConsumeIntegralInRange<size_t>(0, 2);
51
72.5k
    for(size_t i = 0; i < num_children; i++)
52
35.9k
    {
53
35.9k
      xml += generateFuzzedNodeXML(fdp, depth + 1);
54
35.9k
    }
55
36.6k
    xml += "</" + node_type + ">";
56
36.6k
  }
57
58
63.2k
  return xml;
59
63.2k
}
60
61
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
62
16.2k
{
63
16.2k
  if(size < 4)
64
2
  {
65
2
    return 0;
66
2
  }
67
68
16.2k
  FuzzedDataProvider fdp(data, size);
69
16.2k
  BT::BehaviorTreeFactory factory;
70
71
16.2k
  try
72
16.2k
  {
73
    // Strategy 1: Test with completely random data
74
16.2k
    if(fdp.ConsumeBool())
75
2.34k
    {
76
2.34k
      std::string random_xml = fdp.ConsumeRandomLengthString(size - 1);
77
2.34k
      try
78
2.34k
      {
79
2.34k
        factory.createTreeFromText(random_xml);
80
2.34k
      }
81
2.34k
      catch(const std::exception&)
82
2.34k
      {}
83
2.34k
    }
84
    // Strategy 2: Generate semi-valid XML
85
13.9k
    else
86
13.9k
    {
87
13.9k
      std::string xml = R"(
88
13.9k
                <root BTCPP_format="4">
89
13.9k
                    <BehaviorTree ID="MainTree">)";
90
91
13.9k
      size_t num_nodes = fdp.ConsumeIntegralInRange<size_t>(1, 5);
92
41.3k
      for(size_t i = 0; i < num_nodes; i++)
93
27.3k
      {
94
27.3k
        xml += generateFuzzedNodeXML(fdp);
95
27.3k
      }
96
97
13.9k
      xml += R"(
98
13.9k
                    </BehaviorTree>
99
13.9k
                </root>)";
100
101
13.9k
      auto blackboard = BT::Blackboard::create();
102
103
13.9k
      switch(fdp.ConsumeIntegralInRange<int>(0, 2))
104
13.9k
      {
105
13.8k
        case 0:
106
13.8k
          factory.createTreeFromText(xml, blackboard);
107
13.8k
          break;
108
48
        case 1:
109
48
          BT::VerifyXML(xml, {});
110
48
          break;
111
53
        case 2:
112
53
          factory.registerBehaviorTreeFromText(xml);
113
53
          if(!factory.registeredBehaviorTrees().empty())
114
31
          {
115
31
            factory.createTree(factory.registeredBehaviorTrees().front(), blackboard);
116
31
          }
117
53
          break;
118
13.9k
      }
119
13.9k
    }
120
16.2k
  }
121
16.2k
  catch(const std::exception&)
122
16.2k
  {}
123
124
16.2k
  return 0;
125
16.2k
}