Detect all overflows in rcBuildHeightfieldLayers (#214)
The function now fails if it fails to insert all layers because the array overflowed. Previously this would silently corrupt the heap.
This commit is contained in:
parent
ab0a679d8f
commit
9763478a9a
@ -27,7 +27,9 @@
|
|||||||
#include "RecastAssert.h"
|
#include "RecastAssert.h"
|
||||||
|
|
||||||
|
|
||||||
static const int RC_MAX_LAYERS = RC_NOT_CONNECTED;
|
// Must be 255 or smaller (not 256) because layer IDs are stored as
|
||||||
|
// a byte where 255 is a special value.
|
||||||
|
static const int RC_MAX_LAYERS = 63;
|
||||||
static const int RC_MAX_NEIS = 16;
|
static const int RC_MAX_NEIS = 16;
|
||||||
|
|
||||||
struct rcLayerRegion
|
struct rcLayerRegion
|
||||||
@ -42,25 +44,31 @@ struct rcLayerRegion
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void addUnique(unsigned char* a, unsigned char& an, unsigned char v)
|
|
||||||
{
|
|
||||||
const int n = (int)an;
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
if (a[i] == v)
|
|
||||||
return;
|
|
||||||
a[an] = v;
|
|
||||||
an++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool contains(const unsigned char* a, const unsigned char an, const unsigned char v)
|
static bool contains(const unsigned char* a, const unsigned char an, const unsigned char v)
|
||||||
{
|
{
|
||||||
const int n = (int)an;
|
const int n = (int)an;
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
if (a[i] == v)
|
if (a[i] == v)
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool addUnique(unsigned char* a, unsigned char& an, int anMax, unsigned char v)
|
||||||
|
{
|
||||||
|
if (contains(a, an, v))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ((int)an >= anMax)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
a[an] = v;
|
||||||
|
an++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool overlapRange(const unsigned short amin, const unsigned short amax,
|
inline bool overlapRange(const unsigned short amin, const unsigned short amax,
|
||||||
const unsigned short bmin, const unsigned short bmax)
|
const unsigned short bmin, const unsigned short bmax)
|
||||||
{
|
{
|
||||||
@ -258,8 +266,13 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
|||||||
const int ay = y + rcGetDirOffsetY(dir);
|
const int ay = y + rcGetDirOffsetY(dir);
|
||||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
||||||
const unsigned char rai = srcReg[ai];
|
const unsigned char rai = srcReg[ai];
|
||||||
if (rai != 0xff && rai != ri && regs[ri].nneis < RC_MAX_NEIS)
|
if (rai != 0xff && rai != ri)
|
||||||
addUnique(regs[ri].neis, regs[ri].nneis, rai);
|
{
|
||||||
|
// Don't check return value -- if we cannot add the neighbor
|
||||||
|
// it will just cause a few more regions to be created, which
|
||||||
|
// is fine.
|
||||||
|
addUnique(regs[ri].neis, regs[ri].nneis, RC_MAX_NEIS, rai);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,8 +287,13 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
|||||||
{
|
{
|
||||||
rcLayerRegion& ri = regs[lregs[i]];
|
rcLayerRegion& ri = regs[lregs[i]];
|
||||||
rcLayerRegion& rj = regs[lregs[j]];
|
rcLayerRegion& rj = regs[lregs[j]];
|
||||||
addUnique(ri.layers, ri.nlayers, lregs[j]);
|
|
||||||
addUnique(rj.layers, rj.nlayers, lregs[i]);
|
if (!addUnique(ri.layers, ri.nlayers, RC_MAX_LAYERS, lregs[j]) ||
|
||||||
|
!addUnique(rj.layers, rj.nlayers, RC_MAX_LAYERS, lregs[i]))
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: layer overflow (too many overlapping walkable platforms). Try increasing RC_MAX_LAYERS.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,7 +356,13 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
|||||||
regn.layerId = layerId;
|
regn.layerId = layerId;
|
||||||
// Merge current layers to root.
|
// Merge current layers to root.
|
||||||
for (int k = 0; k < regn.nlayers; ++k)
|
for (int k = 0; k < regn.nlayers; ++k)
|
||||||
addUnique(root.layers, root.nlayers, regn.layers[k]);
|
{
|
||||||
|
if (!addUnique(root.layers, root.nlayers, RC_MAX_LAYERS, regn.layers[k]))
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: layer overflow (too many overlapping walkable platforms). Try increasing RC_MAX_LAYERS.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
root.ymin = rcMin(root.ymin, regn.ymin);
|
root.ymin = rcMin(root.ymin, regn.ymin);
|
||||||
root.ymax = rcMax(root.ymax, regn.ymax);
|
root.ymax = rcMax(root.ymax, regn.ymax);
|
||||||
}
|
}
|
||||||
@ -416,7 +440,14 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
|||||||
rj.layerId = newId;
|
rj.layerId = newId;
|
||||||
// Add overlaid layers from 'rj' to 'ri'.
|
// Add overlaid layers from 'rj' to 'ri'.
|
||||||
for (int k = 0; k < rj.nlayers; ++k)
|
for (int k = 0; k < rj.nlayers; ++k)
|
||||||
addUnique(ri.layers, ri.nlayers, rj.layers[k]);
|
{
|
||||||
|
if (!addUnique(ri.layers, ri.nlayers, RC_MAX_LAYERS, rj.layers[k]))
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: layer overflow (too many overlapping walkable platforms). Try increasing RC_MAX_LAYERS.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update height bounds.
|
// Update height bounds.
|
||||||
ri.ymin = rcMin(ri.ymin, rj.ymin);
|
ri.ymin = rcMin(ri.ymin, rj.ymin);
|
||||||
ri.ymax = rcMax(ri.ymax, rj.ymax);
|
ri.ymax = rcMax(ri.ymax, rj.ymax);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user