Add safety checks to material constants binding code to prevent invalid memory access

This commit is contained in:
Wojtek Figat
2021-07-06 15:41:16 +02:00
parent 9f9d946d69
commit a165b4aa79
14 changed files with 85 additions and 55 deletions

View File

@@ -36,9 +36,10 @@ void DecalMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<DecalMaterialShaderData*>(cb);
cb += sizeof(DecalMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(DecalMaterialShaderData));
auto materialData = reinterpret_cast<DecalMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(DecalMaterialShaderData), cb.Length() - sizeof(DecalMaterialShaderData));
int32 srv = 0;
const bool isCameraInside = OrientedBoundingBox(Vector3::Half, params.FirstDrawCall->World).Contains(view.Position) == ContainmentType::Contains;

View File

@@ -60,9 +60,10 @@ void DeferredMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<DeferredMaterialShaderData*>(cb);
cb += sizeof(DeferredMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(DeferredMaterialShaderData));
auto materialData = reinterpret_cast<DeferredMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(DeferredMaterialShaderData), cb.Length() - sizeof(DeferredMaterialShaderData));
int32 srv = 2;
// Setup features

View File

@@ -47,9 +47,10 @@ void DeformableMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<DeformableMaterialShaderData*>(cb);
cb += sizeof(DeformableMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(DeformableMaterialShaderData));
auto materialData = reinterpret_cast<DeformableMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(DeformableMaterialShaderData), cb.Length() - sizeof(DeformableMaterialShaderData));
int32 srv = 1;
// Setup features

View File

@@ -57,9 +57,10 @@ void ForwardMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb);
cb += sizeof(ForwardMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(ForwardMaterialShaderData));
auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(ForwardMaterialShaderData), cb.Length() - sizeof(ForwardMaterialShaderData));
int32 srv = 2;
// Setup features

View File

@@ -26,9 +26,10 @@ void GUIMaterialShader::Bind(BindParameters& params)
{
// Prepare
auto context = params.GPUContext;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<GUIMaterialShaderData*>(cb);
cb += sizeof(GUIMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(GUIMaterialShaderData));
auto materialData = reinterpret_cast<GUIMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(GUIMaterialShaderData), cb.Length() - sizeof(GUIMaterialShaderData));
int32 srv = 0;
const auto ps = context->IsDepthBufferBinded() ? _cache.Depth : _cache.NoDepth;

View File

@@ -317,28 +317,36 @@ void MaterialParameter::Bind(BindMeta& meta) const
switch (_type)
{
case MaterialParameterType::Bool:
*((int32*)(meta.Constants + _offset)) = _asBool;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(bool));
*((int32*)(meta.Constants.Get() + _offset)) = _asBool;
break;
case MaterialParameterType::Integer:
*((int32*)(meta.Constants + _offset)) = _asInteger;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(int32));
*((int32*)(meta.Constants.Get() + _offset)) = _asInteger;
break;
case MaterialParameterType::Float:
*((float*)(meta.Constants + _offset)) = _asFloat;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(float));
*((float*)(meta.Constants.Get() + _offset)) = _asFloat;
break;
case MaterialParameterType::Vector2:
*((Vector2*)(meta.Constants + _offset)) = _asVector2;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector2));
*((Vector2*)(meta.Constants.Get() + _offset)) = _asVector2;
break;
case MaterialParameterType::Vector3:
*((Vector3*)(meta.Constants + _offset)) = _asVector3;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector3));
*((Vector3*)(meta.Constants.Get() + _offset)) = _asVector3;
break;
case MaterialParameterType::Vector4:
*((Vector4*)(meta.Constants + _offset)) = *(Vector4*)&AsData;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector4));
*((Vector4*)(meta.Constants.Get() + _offset)) = *(Vector4*)&AsData;
break;
case MaterialParameterType::Color:
*((Color*)(meta.Constants + _offset)) = _asColor;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector4));
*((Color*)(meta.Constants.Get() + _offset)) = _asColor;
break;
case MaterialParameterType::Matrix:
Matrix::Transpose(*(Matrix*)&AsData, *(Matrix*)(meta.Constants + _offset));
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Matrix));
Matrix::Transpose(*(Matrix*)&AsData, *(Matrix*)(meta.Constants.Get() + _offset));
break;
case MaterialParameterType::NormalMap:
{
@@ -415,7 +423,8 @@ void MaterialParameter::Bind(BindMeta& meta) const
break;
}
case MaterialParameterType::ChannelMask:
*((Vector4*)(meta.Constants + _offset)) = Vector4(_asInteger == 0, _asInteger == 1, _asInteger == 2, _asInteger == 3);
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(int32));
*((Vector4*)(meta.Constants.Get() + _offset)) = Vector4(_asInteger == 0, _asInteger == 1, _asInteger == 2, _asInteger == 3);
break;
case MaterialParameterType::GameplayGlobal:
if (_asAsset)
@@ -426,26 +435,33 @@ void MaterialParameter::Bind(BindMeta& meta) const
switch (e->Value.Type.Type)
{
case VariantType::Bool:
*((bool*)(meta.Constants + _offset)) = e->Value.AsBool;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(bool));
*((bool*)(meta.Constants.Get() + _offset)) = e->Value.AsBool;
break;
case VariantType::Int:
*((int32*)(meta.Constants + _offset)) = e->Value.AsInt;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(int32));
*((int32*)(meta.Constants.Get() + _offset)) = e->Value.AsInt;
break;
case VariantType::Uint:
*((uint32*)(meta.Constants + _offset)) = e->Value.AsUint;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(uint32));
*((uint32*)(meta.Constants.Get() + _offset)) = e->Value.AsUint;
break;
case VariantType::Float:
*((float*)(meta.Constants + _offset)) = e->Value.AsFloat;
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(float));
*((float*)(meta.Constants.Get() + _offset)) = e->Value.AsFloat;
break;
case VariantType::Vector2:
*((Vector2*)(meta.Constants + _offset)) = e->Value.AsVector2();
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector2));
*((Vector2*)(meta.Constants.Get() + _offset)) = e->Value.AsVector2();
break;
case VariantType::Vector3:
*((Vector3*)(meta.Constants + _offset)) = e->Value.AsVector3();
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector3));
*((Vector3*)(meta.Constants.Get() + _offset)) = e->Value.AsVector3();
break;
case VariantType::Vector4:
case VariantType::Color:
*((Vector4*)(meta.Constants + _offset)) = e->Value.AsVector4();
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Vector4));
*((Vector4*)(meta.Constants.Get() + _offset)) = e->Value.AsVector4();
break;
default: ;
}

View File

@@ -309,7 +309,7 @@ public:
/// <summary>
/// The pointer to the constants buffer in the memory.
/// </summary>
byte* Constants;
Span<byte> Constants;
/// <summary>
/// The input scene color. It's optional and used in forward/postFx rendering.

View File

@@ -11,13 +11,14 @@
#include "Engine/Level/Scene/Lightmap.h"
#include "Engine/Level/Actors/EnvironmentProbe.h"
void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv)
void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv)
{
auto context = params.GPUContext;
auto cache = params.RenderContext.List;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
auto& data = *(Data*)cb;
auto& data = *(Data*)cb.Get();
ASSERT_LOW_LAYER(cb.Length() >= sizeof(Data));
const int32 envProbeShaderRegisterIndex = srv + 0;
const int32 skyLightShaderRegisterIndex = srv + 1;
const int32 dirLightShaderRegisterIndex = srv + 2;
@@ -116,16 +117,17 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, byte*&
}
}
cb += sizeof(Data);
cb = Span<byte>(cb.Get() + sizeof(Data), cb.Length() - sizeof(Data));
srv += SRVs;
}
bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv)
bool LightmapFeature::Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv)
{
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
auto& data = *(Data*)cb;
auto& data = *(Data*)cb.Get();
ASSERT_LOW_LAYER(cb.Length() >= sizeof(Data));
const bool useLightmap = view.Flags & ViewFlags::GI
#if USE_EDITOR
@@ -145,8 +147,8 @@ bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, in
data.LightmapArea = drawCall.Features.LightmapUVsArea;
}
cb = Span<byte>(cb.Get() + sizeof(Data), cb.Length() - sizeof(Data));
srv += SRVs;
cb += sizeof(Data);
return useLightmap;
}

View File

@@ -4,6 +4,7 @@
#include "MaterialShader.h"
#include "Engine/Core/Math/Rectangle.h"
#include "Engine/Core/Types/Span.h"
// Material shader features are plugin-based functionalities that are reusable between different material domains.
struct MaterialShaderFeature
@@ -35,7 +36,7 @@ struct ForwardShadingFeature : MaterialShaderFeature
LightData LocalLights[MaxLocalLights];
});
static void Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv);
static void Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv);
#if USE_EDITOR
static void Generate(GeneratorData& data);
#endif
@@ -67,7 +68,7 @@ struct LightmapFeature : MaterialShaderFeature
Rectangle LightmapArea;
});
static bool Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv);
static bool Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv);
#if USE_EDITOR
static void Generate(GeneratorData& data);
#endif

View File

@@ -57,9 +57,10 @@ void ParticleMaterialShader::Bind(BindParameters& params)
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(cb);
cb += sizeof(ParticleMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(ParticleMaterialShaderData));
auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(ParticleMaterialShaderData), cb.Length() - sizeof(ParticleMaterialShaderData));
int32 srv = 2;
// Setup features
@@ -89,7 +90,8 @@ void ParticleMaterialShader::Bind(BindParameters& params)
{
const StringView name(param.GetName().Get() + 9, param.GetName().Length() - 9);
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset;
ASSERT_LOW_LAYER(bindMeta.Constants.Get() && bindMeta.Constants.Length() >= (int32)param.GetBindOffset() + sizeof(int32));
*((int32*)(bindMeta.Constants.Get() + param.GetBindOffset())) = offset;
}
}
}

View File

@@ -25,9 +25,10 @@ void PostFxMaterialShader::Bind(BindParameters& params)
// Prepare
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<PostFxMaterialShaderData*>(cb);
cb += sizeof(PostFxMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(PostFxMaterialShaderData));
auto materialData = reinterpret_cast<PostFxMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(PostFxMaterialShaderData), cb.Length() - sizeof(PostFxMaterialShaderData));
int32 srv = 0;
// Setup parameters

View File

@@ -53,9 +53,10 @@ void TerrainMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<TerrainMaterialShaderData*>(cb);
cb += sizeof(TerrainMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(TerrainMaterialShaderData));
auto materialData = reinterpret_cast<TerrainMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(TerrainMaterialShaderData), cb.Length() - sizeof(TerrainMaterialShaderData));
int32 srv = 3;
// Setup features

View File

@@ -45,9 +45,10 @@ void VolumeParticleMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
byte* cb = _cbData.Get();
auto materialData = reinterpret_cast<VolumeParticleMaterialShaderData*>(cb);
cb += sizeof(VolumeParticleMaterialShaderData);
Span<byte> cb(_cbData.Get(), _cbData.Count());
ASSERT_LOW_LAYER(cb.Length() >= sizeof(VolumeParticleMaterialShaderData));
auto materialData = reinterpret_cast<VolumeParticleMaterialShaderData*>(cb.Get());
cb = Span<byte>(cb.Get() + sizeof(VolumeParticleMaterialShaderData), cb.Length() - sizeof(VolumeParticleMaterialShaderData));
int32 srv = 1;
auto customData = (VolumetricFogPass::CustomData*)params.CustomData;
@@ -74,7 +75,8 @@ void VolumeParticleMaterialShader::Bind(BindParameters& params)
{
const StringView name(param.GetName().Get() + 9, param.GetName().Length() - 9);
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset;
ASSERT_LOW_LAYER(bindMeta.Constants.Get() && bindMeta.Constants.Length() >= (int32)param.GetBindOffset() + sizeof(int32));
*((int32*)(bindMeta.Constants.Get() + param.GetBindOffset())) = offset;
}
}
}

View File

@@ -162,7 +162,7 @@ void GPUParticles::Execute(GPUContext* context, ParticleEmitter* emitter, Partic
// Setup parameters
MaterialParameter::BindMeta bindMeta;
bindMeta.Context = context;
bindMeta.Constants = hasCB ? _cbData.Get() + sizeof(GPUParticlesData) : nullptr;
bindMeta.Constants = hasCB ? Span<byte>(_cbData.Get() + sizeof(GPUParticlesData), _cbData.Count() - sizeof(GPUParticlesData)) : Span<byte>(nullptr, 0);
bindMeta.Input = nullptr;
if (viewTask)
{