Coverage Report

Created: 2026-02-26 06:31

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