Coverage Report

Created: 2026-04-12 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre_deep_fuzz.cpp
Line
Count
Source
1
/* Copyright 2026 Google LLC
2
Licensed under the Apache License, Version 2.0 (the "License");
3
you may not use this file except in compliance with the License.
4
You may obtain a copy of the License at
5
      http://www.apache.org/licenses/LICENSE-2.0
6
Unless required by applicable law or agreed to in writing, software
7
distributed under the License is distributed on an "AS IS" BASIS,
8
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
See the License for the specific language governing permissions and
10
limitations under the License.
11
*/
12
13
/*
14
 * Multi-target fuzzer for Ogre3D covering:
15
 * 1. Mesh binary format deserialization (7 format versions)
16
 * 2. Skeleton binary format deserialization
17
 * 3. Script lexer and parser pipeline
18
 * 4. ConfigFile parsing
19
 * 5. StreamSerialiser chunk reading (extended)
20
 *
21
 * Uses FuzzedDataProvider to select which target to exercise per input,
22
 * maximizing code coverage across the Ogre codebase.
23
 */
24
25
#include <stdint.h>
26
#include <stdlib.h>
27
#include <string.h>
28
29
#include <fuzzer/FuzzedDataProvider.h>
30
#include <string>
31
32
#include "OgreConfigFile.h"
33
#include "OgreDataStream.h"
34
#include "OgreDefaultHardwareBufferManager.h"
35
#include "OgreException.h"
36
#include "OgreLodStrategyManager.h"
37
#include "OgreLogManager.h"
38
#include "OgreMaterialManager.h"
39
#include "OgreMesh.h"
40
#include "OgreMeshManager.h"
41
#include "OgreMeshSerializer.h"
42
#include "OgreSkeleton.h"
43
#include "OgreSkeletonManager.h"
44
#include "OgreSkeletonSerializer.h"
45
#include "OgreStreamSerialiser.h"
46
47
enum FuzzTarget {
48
  FUZZ_MESH = 0,
49
  FUZZ_SKELETON,
50
  FUZZ_CONFIG,
51
  FUZZ_STREAM_SERIALISER,
52
  FUZZ_TARGET_COUNT
53
};
54
55
static bool g_initialized = false;
56
57
3.62k
static void global_init() {
58
3.62k
  if (g_initialized)
59
3.62k
    return;
60
61
  /* Suppress all log output */
62
1
  auto *logMgr = new Ogre::LogManager();
63
1
  logMgr->createLog("fuzz.log", true, false, true); /* suppressFileOutput */
64
1
  logMgr->setMinLogLevel(Ogre::LML_CRITICAL);
65
66
  /* Create singletons needed for Mesh/Skeleton operations */
67
1
  new Ogre::ResourceGroupManager();
68
1
  new Ogre::LodStrategyManager();
69
1
  new Ogre::DefaultHardwareBufferManager();
70
1
  new Ogre::MeshManager();
71
1
  new Ogre::SkeletonManager();
72
1
  auto *matMgr = new Ogre::MaterialManager();
73
1
  matMgr->initialise();
74
75
1
  g_initialized = true;
76
1
}
77
78
1.82k
static void fuzz_mesh(const uint8_t *data, size_t size) {
79
1.82k
  Ogre::MeshPtr mesh =
80
1.82k
      Ogre::MeshManager::getSingleton().create("fuzz.mesh", "General");
81
82
1.82k
  Ogre::DataStreamPtr stream(
83
1.82k
      new Ogre::MemoryDataStream(const_cast<uint8_t *>(data), size, false, true));
84
85
1.82k
  Ogre::MeshSerializer serializer;
86
1.82k
  try {
87
1.82k
    serializer.importMesh(stream, mesh.get());
88
1.82k
  } catch (Ogre::Exception &) {
89
533
  } catch (std::exception &) {
90
8
  }
91
92
1.82k
  Ogre::MeshManager::getSingleton().remove(mesh);
93
1.82k
}
94
95
734
static void fuzz_skeleton(const uint8_t *data, size_t size) {
96
734
  Ogre::SkeletonPtr skeleton =
97
734
      Ogre::SkeletonManager::getSingleton().create("fuzz.skeleton", "General");
98
99
734
  Ogre::DataStreamPtr stream(
100
734
      new Ogre::MemoryDataStream(const_cast<uint8_t *>(data), size, false, true));
101
102
734
  Ogre::SkeletonSerializer serializer;
103
734
  try {
104
734
    serializer.importSkeleton(stream, skeleton.get());
105
734
  } catch (Ogre::Exception &) {
106
163
  } catch (std::exception &) {
107
0
  }
108
109
734
  Ogre::SkeletonManager::getSingleton().remove(skeleton);
110
734
}
111
112
936
static void fuzz_config(const uint8_t *data, size_t size) {
113
936
  Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(
114
936
      "fuzz.cfg", const_cast<uint8_t *>(data), size, false, true));
115
116
936
  Ogre::ConfigFile cf;
117
936
  try {
118
936
    cf.load(stream);
119
120
    /* Exercise iteration over parsed sections and settings */
121
3.29k
    for (auto &sec : cf.getSettingsBySection()) {
122
17.0k
      for (auto &kv : sec.second) {
123
17.0k
        volatile const char *k = kv.first.c_str();
124
17.0k
        volatile const char *v = kv.second.c_str();
125
17.0k
        (void)k;
126
17.0k
        (void)v;
127
17.0k
      }
128
3.29k
    }
129
936
  } catch (Ogre::Exception &) {
130
0
  } catch (std::exception &) {
131
0
  }
132
936
}
133
134
137
static void fuzz_stream_serialiser(const uint8_t *data, size_t size) {
135
137
  Ogre::DataStreamPtr stream(
136
137
      new Ogre::MemoryDataStream(const_cast<uint8_t *>(data), size, false, true));
137
138
137
  try {
139
137
    Ogre::StreamSerialiser serialiser(stream);
140
141
    /* Try to read multiple chunks, exercising the chunk state machine */
142
137
    for (int i = 0; i < 32; i++) {
143
137
      const Ogre::StreamSerialiser::Chunk *c = serialiser.readChunkBegin();
144
137
      if (!c)
145
0
        break;
146
147
      /* Try reading various data types from the chunk */
148
137
      Ogre::String str;
149
137
      try { serialiser.read(&str); } catch (...) {}
150
151
137
      Ogre::Real r;
152
0
      try { serialiser.read(&r); } catch (...) {}
153
154
0
      Ogre::Vector3 v3;
155
0
      try { serialiser.read(&v3); } catch (...) {}
156
157
0
      Ogre::Vector4 v4;
158
0
      try { serialiser.read(&v4); } catch (...) {}
159
160
0
      serialiser.readChunkEnd(c->id);
161
0
    }
162
137
  } catch (Ogre::Exception &) {
163
137
  } catch (std::exception &) {
164
0
  }
165
137
}
166
167
3.63k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
168
3.63k
  if (size < 2)
169
1
    return 0;
170
171
3.62k
  global_init();
172
173
3.62k
  FuzzedDataProvider provider(data, size);
174
3.62k
  uint8_t target = provider.ConsumeIntegral<uint8_t>() % FUZZ_TARGET_COUNT;
175
3.62k
  auto remaining = provider.ConsumeRemainingBytes<uint8_t>();
176
177
3.62k
  if (remaining.empty())
178
0
    return 0;
179
180
3.62k
  switch (target) {
181
1.82k
  case FUZZ_MESH:
182
1.82k
    fuzz_mesh(remaining.data(), remaining.size());
183
1.82k
    break;
184
734
  case FUZZ_SKELETON:
185
734
    fuzz_skeleton(remaining.data(), remaining.size());
186
734
    break;
187
936
  case FUZZ_CONFIG:
188
936
    fuzz_config(remaining.data(), remaining.size());
189
936
    break;
190
137
  case FUZZ_STREAM_SERIALISER:
191
137
    fuzz_stream_serialiser(remaining.data(), remaining.size());
192
137
    break;
193
3.62k
  }
194
195
3.62k
  return 0;
196
3.62k
}