Skip to content

Commit 73b6b5c

Browse files
authored
Merge pull request #54 from ChrisHal/improvements
make loading more robust against malformed files
2 parents 0e7dbae + bc6d2f7 commit 73b6b5c

File tree

3 files changed

+26
-11
lines changed

3 files changed

+26
-11
lines changed

hekatoolslib/DatFile.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ void DatFile::InitFromStream(std::istream& infile)
7979
if (std::strcmp(item.Extension, ExtDat) == 0) {
8080
offsetDat = item.Start;
8181
lenDat = item.Length;
82+
if (offsetDat < 0 || lenDat <= 0) throw std::runtime_error("invalid data offset or length");
8283
}
8384
else if (std::strcmp(item.Extension, ExtPul) == 0) {
8485
// process pulse tree
@@ -97,6 +98,10 @@ void DatFile::InitFromStream(std::istream& infile)
9798
throw std::runtime_error("error processing tree");
9899
}
99100
}
101+
// make reasonably certain we succeded at loading and file is valid:
102+
if (lenDat == 0) throw std::runtime_error("no data in file");
103+
if (!PulTree.isValid()) throw std::runtime_error("no valid Pulse tree in file");
104+
if (!PgfTree.isValid())throw std::runtime_error("no valid Pgf in file");
100105
}
101106

102107
std::string DatFile::getFileDate() const

hekatoolslib/hkTree.cpp

+19-10
Original file line numberDiff line numberDiff line change
@@ -62,34 +62,35 @@ namespace hkLib {
6262
/// header of tree as stored in file
6363
/// </summary>
6464
struct TreeRoot {
65-
uint32_t Magic, //!< magic nummber MagicNumber or SwappedMagicNumber
65+
std::uint32_t Magic, //!< magic nummber MagicNumber or SwappedMagicNumber
6666
nLevels, //!< number of tree levels
6767
LevelSizes[1]; //!< variable length array (nLevels entries with size of level data in bytes)
6868
};
6969

70-
void hkTree::LoadToNode(hkTreeNode* parent, hkTreeNode& node, char** pdata, int level)
70+
void hkLib::hkTree::LoadToNode(hkTreeNode* parent, hkTreeNode& node, char** pdata, char* data_end, int level)
7171
{
7272
node.tree = this;
7373
auto size = static_cast<std::size_t>(LevelSizes.at(level));
7474
node.level = level;
75-
//node.len = size;
7675
node.isSwapped = isSwapped;
7776
node.Parent = parent;
78-
node.Data = std::span( *pdata, size );
77+
node.Data = std::span(*pdata, size);
7978
*pdata += size;
80-
uint32_t nchildren;
81-
std::memcpy(&nchildren, *pdata, sizeof(uint32_t));
79+
std::uint32_t nchildren;
80+
if (*pdata + sizeof(std::uint32_t) >= data_end) throw std::runtime_error("not enough data");
81+
std::memcpy(&nchildren, *pdata, sizeof(std::uint32_t));
8282
if (isSwapped) { swapInPlace(nchildren); }
83-
*pdata += sizeof(uint32_t);
83+
*pdata += sizeof(std::uint32_t);
8484
node.Children.resize(nchildren);
8585
for (auto& child : node.Children) {
86-
LoadToNode(&node, child, pdata, level + 1);
86+
LoadToNode(&node, child, pdata, data_end, level + 1);
8787
}
8888
}
8989

9090
bool hkTree::InitFromStream(const std::string_view& id, std::istream& infile, int offset, unsigned int len)
9191
{
9292
assert(!!infile);
93+
if (offset <= 0 || len == 0) throw std::runtime_error("invalid tree data offset or length");
9394
Data = std::make_unique<char[]>(len);
9495
infile.seekg(offset).read(Data.get(), len);
9596
if (!infile) {
@@ -102,6 +103,7 @@ namespace hkLib {
102103

103104
bool hkTree::InitFromBuffer(const std::string_view& id, char* buffer, std::size_t len)
104105
{
106+
if (len < sizeof(TreeRoot)) throw std::runtime_error("invalid TreeRoot (too few bytes in file)");
105107
ID = id;
106108
TreeRoot* root = reinterpret_cast<TreeRoot*>(buffer); // we assume buffer is correctly aligned
107109
isSwapped = false;
@@ -115,18 +117,25 @@ namespace hkLib {
115117
if (isSwapped) {
116118
swapInPlace(root->nLevels);
117119
}
120+
const auto root_bytes = offsetof(TreeRoot, LevelSizes) + sizeof(std::uint32_t) * root->nLevels;
121+
if (len < root_bytes) throw std::runtime_error("invalid TreeRoot (too few bytes in file)");
118122
for (std::size_t i = 0; i < root->nLevels; ++i) {
119123
if (isSwapped) { swapInPlace(root->LevelSizes[i]); }
120124
LevelSizes.push_back(root->LevelSizes[i]);
121125
}
122-
char* data = buffer + offsetof(TreeRoot, LevelSizes) + sizeof(uint32_t) * root->nLevels; // start of first tree node
123-
LoadToNode(nullptr, RootNode, &data, 0);
126+
char* data = buffer + root_bytes; // start of first tree node
127+
LoadToNode(nullptr, RootNode, &data, data + len, 0);
124128
if (data - buffer != static_cast<std::ptrdiff_t>(len)) {
125129
throw std::runtime_error("bytes read != bytes in buffer");
126130
}
127131
return true;
128132
}
129133

134+
bool hkTree::isValid()
135+
{
136+
return LevelSizes.size()!=0 && !RootNode.Data.empty();
137+
}
138+
130139
char hkTreeNode::getChar(std::size_t offset) const
131140
{
132141
if (Data.size() < offset + sizeof(char)) {

hekatoolslib/hkTree.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ namespace hkLib {
336336
std::unique_ptr<char[]> Data{};
337337
double time0{};
338338
bool isSwapped;
339-
void LoadToNode(hkTreeNode* parent, hkTreeNode& node, char** pdata, int level);
339+
void LoadToNode(hkTreeNode* parent, hkTreeNode& node, char** pdata, char* data_end, int level);
340340
public:
341341
hkTree() : LevelSizes{}, RootNode{}, isSwapped{ false } {};
342342
std::string getID() {
@@ -364,6 +364,7 @@ namespace hkLib {
364364
hkTreeNode& GetRootNode() { return RootNode; };
365365
std::size_t GetNumLevels() { return LevelSizes.size(); }; //!< return number of levels this tree has
366366
bool getIsSwapped() const { return isSwapped; };
367+
bool isValid();
367368
friend hkTreeNode;
368369
};
369370
}

0 commit comments

Comments
 (0)