fix: sanitizer sweep across all generators; bound signed shifts/division/overflow at coordinate limits (L61); R31
New verify.py sanitize tier (Clang address,undefined,float-cast-overflow; GCC address,undefined; -fno-sanitize-recover) runs 19 cases per compiler at LOD0-8 across every generator, passages and the crossing: 0 runtime reports; a planted signed-overflow control is caught by both. A static scan fixed INT_MIN negation in floor division, unbounded signed LOD shifts and coordinate-times-extent overflow in VoxelClipmapDesiredTiles.h and VoxelTypes.h (plugin and standalone), and VoxelWorld.cpp, VoxelContentManager.cpp and VoxelDensityVolume.cpp (plugin only, uncompiled here). Supported-input output unchanged (version 211). fast/medium/full PASS. Research R31 (self-checked): far-LOD 4-8 cut plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
c0c204ba50
commit
135957831b
13 files changed
+760
-132
No files matched your search
@@ -4,6 +4,27 @@
|
||||
|
||||
namespace VoxelClipmapDesiredTiles
|
||||
{
|
||||
FORCEINLINE int64 FloorDivWide(int64 Value, int64 Divisor)
|
||||
{
|
||||
if (Divisor <= 0) { return 0; }
|
||||
const int64 Quotient = Value / Divisor;
|
||||
const int64 Remainder = Value % Divisor;
|
||||
return Remainder < 0 ? Quotient - 1 : Quotient;
|
||||
}
|
||||
|
||||
FORCEINLINE int64 CeilDivWide(int64 Value, int64 Divisor)
|
||||
{
|
||||
if (Divisor <= 0) { return 0; }
|
||||
const int64 Quotient = Value / Divisor;
|
||||
const int64 Remainder = Value % Divisor;
|
||||
return Remainder > 0 ? Quotient + 1 : Quotient;
|
||||
}
|
||||
|
||||
FORCEINLINE int32 ClampInt32(int64 Value)
|
||||
{
|
||||
return static_cast<int32>(FMath::Clamp<int64>(Value, MIN_int32, MAX_int32));
|
||||
}
|
||||
|
||||
struct FParameters
|
||||
{
|
||||
int32 ClipRadius = 3;
|
||||
@@ -13,7 +34,10 @@ namespace VoxelClipmapDesiredTiles
|
||||
|
||||
FORCEINLINE int32 FloorDiv(int32 Value, int32 Divisor)
|
||||
{
|
||||
return Value >= 0 ? (Value / Divisor) : -(((-Value) + Divisor - 1) / Divisor);
|
||||
if (Divisor <= 0) { return 0; }
|
||||
const int32 Quotient = Value / Divisor;
|
||||
const int32 Remainder = Value % Divisor;
|
||||
return Remainder < 0 ? Quotient - 1 : Quotient;
|
||||
}
|
||||
|
||||
FORCEINLINE FIntVector FloorDiv(const FIntVector& Value, int32 Divisor)
|
||||
@@ -24,7 +48,10 @@ namespace VoxelClipmapDesiredTiles
|
||||
|
||||
FORCEINLINE int32 CeilDiv(int32 Value, int32 Divisor)
|
||||
{
|
||||
return -FloorDiv(-Value, Divisor);
|
||||
if (Divisor <= 0) { return 0; }
|
||||
const int32 Quotient = Value / Divisor;
|
||||
const int32 Remainder = Value % Divisor;
|
||||
return Remainder > 0 ? Quotient + 1 : Quotient;
|
||||
}
|
||||
|
||||
FORCEINLINE void AlignedRingBounds(const FIntVector& Center, int32 Radius, int32 Alignment,
|
||||
@@ -33,10 +60,12 @@ namespace VoxelClipmapDesiredTiles
|
||||
const auto AlignAxis = [Radius, Alignment](int32 CenterAxis,
|
||||
int32& OutAxisMin, int32& OutAxisMax)
|
||||
{
|
||||
const int32 BaseMin = CenterAxis - Radius;
|
||||
const int32 BaseEnd = CenterAxis + Radius + 1;
|
||||
OutAxisMin = FloorDiv(BaseMin, Alignment) * Alignment;
|
||||
OutAxisMax = CeilDiv(BaseEnd, Alignment) * Alignment - 1;
|
||||
const int64 SafeRadius = FMath::Max<int64>(0, Radius);
|
||||
const int64 SafeAlignment = FMath::Max<int64>(1, Alignment);
|
||||
const int64 BaseMin = static_cast<int64>(CenterAxis) - SafeRadius;
|
||||
const int64 BaseEnd = static_cast<int64>(CenterAxis) + SafeRadius + 1;
|
||||
OutAxisMin = ClampInt32(FloorDivWide(BaseMin, SafeAlignment) * SafeAlignment);
|
||||
OutAxisMax = ClampInt32(CeilDivWide(BaseEnd, SafeAlignment) * SafeAlignment - 1);
|
||||
};
|
||||
AlignAxis(Center.X, OutMin.X, OutMax.X);
|
||||
AlignAxis(Center.Y, OutMin.Y, OutMax.Y);
|
||||
@@ -49,8 +78,13 @@ namespace VoxelClipmapDesiredTiles
|
||||
{
|
||||
return Radius;
|
||||
}
|
||||
return FMath::Max(Radius,
|
||||
(Parameters.RenderDistanceChunks + (1 << MaxLevel) - 1) >> MaxLevel);
|
||||
const int32 SafeLevel = FMath::Clamp(MaxLevel, 0, 8);
|
||||
const int64 Scale = static_cast<int64>(uint32{1} << static_cast<uint32>(SafeLevel));
|
||||
const int64 Numerator = static_cast<int64>(Parameters.RenderDistanceChunks)
|
||||
+ Scale - 1;
|
||||
const int64 DesiredRadius = Numerator / Scale;
|
||||
return static_cast<int32>(FMath::Clamp<int64>(
|
||||
FMath::Max<int64>(Radius, DesiredRadius), 0, MAX_int32));
|
||||
}
|
||||
|
||||
FORCEINLINE void OuterShell(const FParameters& Parameters, int32 Radius, int32 MaxLevel,
|
||||
@@ -73,12 +107,12 @@ namespace VoxelClipmapDesiredTiles
|
||||
return;
|
||||
}
|
||||
|
||||
OutMinChunkZ = CenterChunkZ - ViewDistanceDown;
|
||||
OutMaxChunkZ = CenterChunkZ + ViewDistanceUp;
|
||||
OutMinChunkZ = ClampInt32(static_cast<int64>(CenterChunkZ) - ViewDistanceDown);
|
||||
OutMaxChunkZ = ClampInt32(static_cast<int64>(CenterChunkZ) + ViewDistanceUp);
|
||||
if (bHasStrate)
|
||||
{
|
||||
OutMinChunkZ = StrateBottomChunkZ - StrateViewMarginChunks;
|
||||
OutMaxChunkZ = StrateTopChunkZ + StrateViewMarginChunks;
|
||||
OutMinChunkZ = ClampInt32(static_cast<int64>(StrateBottomChunkZ) - StrateViewMarginChunks);
|
||||
OutMaxChunkZ = ClampInt32(static_cast<int64>(StrateTopChunkZ) + StrateViewMarginChunks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +128,7 @@ namespace VoxelClipmapDesiredTiles
|
||||
|
||||
for (int32 Level = 0; Level <= MaxLevel; ++Level)
|
||||
{
|
||||
const int32 Pow = 1 << Level;
|
||||
const int32 Pow = static_cast<int32>(uint32{1} << static_cast<uint32>(Level));
|
||||
const FIntVector CenterLevel = FloorDiv(Center, Pow);
|
||||
const int32 LevelRadius = (Level == MaxLevel) ? OuterRadius : Radius;
|
||||
|
||||
@@ -105,24 +139,23 @@ namespace VoxelClipmapDesiredTiles
|
||||
FIntVector RingMin, RingMax;
|
||||
AlignedRingBounds(CenterLevel, LevelRadius, RingAlignment, RingMin, RingMax);
|
||||
|
||||
int32 DeltaZMin = RingMin.Z - CenterLevel.Z;
|
||||
int32 DeltaZMax = RingMax.Z - CenterLevel.Z;
|
||||
int64 TileMinZ = RingMin.Z;
|
||||
int64 TileMaxZ = RingMax.Z;
|
||||
if (LevelRadius > Radius && MinChunkZ != MIN_int32)
|
||||
{
|
||||
DeltaZMin = FMath::Max(DeltaZMin, FloorDiv(MinChunkZ, Pow) - CenterLevel.Z);
|
||||
DeltaZMax = FMath::Min(DeltaZMax, FloorDiv(MaxChunkZ, Pow) - CenterLevel.Z);
|
||||
TileMinZ = FMath::Max<int64>(TileMinZ, FloorDiv(MinChunkZ, Pow));
|
||||
TileMaxZ = FMath::Min<int64>(TileMaxZ, FloorDiv(MaxChunkZ, Pow));
|
||||
}
|
||||
|
||||
for (int32 DeltaZ = DeltaZMin; DeltaZ <= DeltaZMax; ++DeltaZ)
|
||||
for (int32 DeltaY = RingMin.Y - CenterLevel.Y;
|
||||
DeltaY <= RingMax.Y - CenterLevel.Y; ++DeltaY)
|
||||
for (int32 DeltaX = RingMin.X - CenterLevel.X;
|
||||
DeltaX <= RingMax.X - CenterLevel.X; ++DeltaX)
|
||||
for (int64 Z = TileMinZ; Z <= TileMaxZ; ++Z)
|
||||
for (int64 Y = RingMin.Y; Y <= RingMax.Y; ++Y)
|
||||
for (int64 X = RingMin.X; X <= RingMax.X; ++X)
|
||||
{
|
||||
const FIntVector Tile = CenterLevel + FIntVector(DeltaX, DeltaY, DeltaZ);
|
||||
const int32 TileMinZ = Tile.Z << Level;
|
||||
const int32 TileMaxZ = ((Tile.Z + 1) << Level) - 1;
|
||||
if (TileMaxZ < MinChunkZ || TileMinZ > MaxChunkZ)
|
||||
const FIntVector Tile(static_cast<int32>(X), static_cast<int32>(Y),
|
||||
static_cast<int32>(Z));
|
||||
const int64 TileBottomChunkZ = static_cast<int64>(Tile.Z) * Pow;
|
||||
const int64 TileTopChunkZ = (static_cast<int64>(Tile.Z) + 1) * Pow - 1;
|
||||
if (TileTopChunkZ < MinChunkZ || TileBottomChunkZ > MaxChunkZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -130,12 +163,12 @@ namespace VoxelClipmapDesiredTiles
|
||||
if (Level > 0)
|
||||
{
|
||||
const bool bCovered =
|
||||
(2 * Tile.X >= PreviousRingMin.X)
|
||||
&& (2 * Tile.X + 1 <= PreviousRingMax.X)
|
||||
&& (2 * Tile.Y >= PreviousRingMin.Y)
|
||||
&& (2 * Tile.Y + 1 <= PreviousRingMax.Y)
|
||||
&& (2 * Tile.Z >= PreviousRingMin.Z)
|
||||
&& (2 * Tile.Z + 1 <= PreviousRingMax.Z);
|
||||
(2 * static_cast<int64>(Tile.X) >= PreviousRingMin.X)
|
||||
&& (2 * static_cast<int64>(Tile.X) + 1 <= PreviousRingMax.X)
|
||||
&& (2 * static_cast<int64>(Tile.Y) >= PreviousRingMin.Y)
|
||||
&& (2 * static_cast<int64>(Tile.Y) + 1 <= PreviousRingMax.Y)
|
||||
&& (2 * static_cast<int64>(Tile.Z) >= PreviousRingMin.Z)
|
||||
&& (2 * static_cast<int64>(Tile.Z) + 1 <= PreviousRingMax.Z);
|
||||
if (bCovered)
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -332,16 +332,33 @@ struct FVoxelTileKey
|
||||
FVoxelTileKey(const FIntVector& InCoord, int32 InLevel) : Coord(InCoord), Level(InLevel) {}
|
||||
|
||||
// Cell size (sampling step) in voxels, and tile extent in voxels per axis.
|
||||
int32 StepVoxels() const { return 1 << Level; }
|
||||
int32 ExtentVoxels() const { return CHUNK_SIZE << Level; }
|
||||
int32 StepVoxels() const
|
||||
{
|
||||
const uint32 SafeLevel = static_cast<uint32>(FMath::Clamp(Level, 0, 8));
|
||||
return static_cast<int32>(uint32{1} << SafeLevel);
|
||||
}
|
||||
int32 ExtentVoxels() const
|
||||
{
|
||||
const uint32 SafeLevel = static_cast<uint32>(FMath::Clamp(Level, 0, 8));
|
||||
return static_cast<int32>(static_cast<uint32>(CHUNK_SIZE) * (uint32{1} << SafeLevel));
|
||||
}
|
||||
|
||||
// Min-corner of the tile in VOXEL coords (what the mesher takes).
|
||||
FIntVector OriginVoxels() const { return Coord * (CHUNK_SIZE << Level); }
|
||||
FIntVector OriginVoxels() const
|
||||
{
|
||||
const int64 Extent = ExtentVoxels();
|
||||
const auto ScaleAxis = [Extent](int32 Axis)
|
||||
{
|
||||
return static_cast<int32>(FMath::Clamp<int64>(
|
||||
static_cast<int64>(Axis) * Extent, MIN_int32, MAX_int32));
|
||||
};
|
||||
return FIntVector(ScaleAxis(Coord.X), ScaleAxis(Coord.Y), ScaleAxis(Coord.Z));
|
||||
}
|
||||
|
||||
// Tile centre in world cm (for distance sorting / LOD selection).
|
||||
FVector CenterCm() const
|
||||
{
|
||||
const double Ext = (double)(CHUNK_SIZE << Level) * (double)VOXEL_SIZE;
|
||||
const double Ext = static_cast<double>(ExtentVoxels()) * static_cast<double>(VOXEL_SIZE);
|
||||
return FVector((Coord.X + 0.5) * Ext, (Coord.Y + 0.5) * Ext, (Coord.Z + 0.5) * Ext);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user