Skip to content

Commit

Permalink
Fix crash when handling uninitialized resource type
Browse files Browse the repository at this point in the history
close shader-slang#6328.

When declare a var with struct type, if the struct has a resource
type field and it doesn't provide explicit constructor, because
slang won't implicit construct such variable at declare site if user
doesn't explicitly call the initializer list, we should report the
resource type field uninitialized as an error to prevent future possible
crash when legalize any use of such variable.
  • Loading branch information
kaizhangNV committed Feb 12, 2025
1 parent 0fee8c1 commit f642878
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 19 deletions.
6 changes: 6 additions & 0 deletions source/slang/slang-diagnostic-defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2551,6 +2551,12 @@ DIAGNOSTIC(
attemptToQuerySizeOfUnsizedArray,
"cannot obtain the size of an unsized array.")

DIAGNOSTIC(
56003,
Error,
useOfUninitializedResouceType,
"use of uninitialized resource type '$0'.")

// Metal
DIAGNOSTIC(
56100,
Expand Down
47 changes: 29 additions & 18 deletions source/slang/slang-ir-legalize-types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ LegalVal LegalVal::wrappedBuffer(LegalVal const& baseVal, LegalElementWrapping c

//

IRTypeLegalizationContext::IRTypeLegalizationContext(TargetProgram* target, IRModule* inModule)
IRTypeLegalizationContext::IRTypeLegalizationContext(TargetProgram* target, IRModule* inModule, DiagnosticSink* sink)
{
targetProgram = target;

Expand All @@ -100,6 +100,8 @@ IRTypeLegalizationContext::IRTypeLegalizationContext(TargetProgram* target, IRMo

builderStorage = IRBuilder(inModule);
builder = &builderStorage;

m_sink = sink;
}

static void registerLegalizedValue(
Expand Down Expand Up @@ -2046,6 +2048,22 @@ static LegalVal coerceToLegalType(IRTypeLegalizationContext* context, LegalType
}
}

static LegalVal legalizeUndefined(IRTypeLegalizationContext* context, IRInst* inst)
{
if (auto structType = as<IRStructType>(inst->getFullType()))
{
for (auto field: structType->getFields())
{
if (isResourceType(field->getFieldType()))
{
context->m_sink->diagnose(field, Diagnostics::useOfUninitializedResouceType, field->getFieldType());
SLANG_ABORT_COMPILATION("use of uninitialized resource type");
}
}
}
return LegalVal();
}

static LegalVal legalizeInst(
IRTypeLegalizationContext* context,
IRInst* inst,
Expand Down Expand Up @@ -2122,7 +2140,7 @@ static LegalVal legalizeInst(
result = legalizePrintf(context, args);
break;
case kIROp_undefined:
return LegalVal();
return legalizeUndefined(context, inst);
case kIROp_GpuForeach:
// This case should only happen when compiling for a target that does not support
// GpuForeach
Expand Down Expand Up @@ -4015,8 +4033,8 @@ static void legalizeTypes(IRTypeLegalizationContext* context)
//
struct IRResourceTypeLegalizationContext : IRTypeLegalizationContext
{
IRResourceTypeLegalizationContext(TargetProgram* target, IRModule* module)
: IRTypeLegalizationContext(target, module)
IRResourceTypeLegalizationContext(TargetProgram* target, IRModule* module, DiagnosticSink* sink)
: IRTypeLegalizationContext(target, module, sink)
{
}

Expand Down Expand Up @@ -4046,8 +4064,8 @@ struct IRResourceTypeLegalizationContext : IRTypeLegalizationContext
//
struct IRExistentialTypeLegalizationContext : IRTypeLegalizationContext
{
IRExistentialTypeLegalizationContext(TargetProgram* target, IRModule* module)
: IRTypeLegalizationContext(target, module)
IRExistentialTypeLegalizationContext(TargetProgram* target, IRModule* module, DiagnosticSink* sink)
: IRTypeLegalizationContext(target, module, sink)
{
}

Expand Down Expand Up @@ -4087,8 +4105,8 @@ struct IRExistentialTypeLegalizationContext : IRTypeLegalizationContext
// a public function signature.
struct IREmptyTypeLegalizationContext : IRTypeLegalizationContext
{
IREmptyTypeLegalizationContext(TargetProgram* target, IRModule* module)
: IRTypeLegalizationContext(target, module)
IREmptyTypeLegalizationContext(TargetProgram* target, IRModule* module, DiagnosticSink* sink)
: IRTypeLegalizationContext(target, module, sink)
{
}

Expand Down Expand Up @@ -4129,28 +4147,21 @@ void legalizeResourceTypes(TargetProgram* target, IRModule* module, DiagnosticSi
{
SLANG_PROFILE;

SLANG_UNUSED(sink);

IRResourceTypeLegalizationContext context(target, module);
IRResourceTypeLegalizationContext context(target, module, sink);
legalizeTypes(&context);
}

void legalizeExistentialTypeLayout(TargetProgram* target, IRModule* module, DiagnosticSink* sink)
{
SLANG_PROFILE;

SLANG_UNUSED(module);
SLANG_UNUSED(sink);

IRExistentialTypeLegalizationContext context(target, module);
IRExistentialTypeLegalizationContext context(target, module, sink);
legalizeTypes(&context);
}

void legalizeEmptyTypes(TargetProgram* target, IRModule* module, DiagnosticSink* sink)
{
SLANG_UNUSED(sink);

IREmptyTypeLegalizationContext context(target, module);
IREmptyTypeLegalizationContext context(target, module, sink);
legalizeTypes(&context);
}

Expand Down
3 changes: 2 additions & 1 deletion source/slang/slang-legalize-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,9 @@ struct IRTypeLegalizationContext
IRBuilder* builder;
TargetProgram* targetProgram;
IRBuilder builderStorage;
DiagnosticSink* m_sink;

IRTypeLegalizationContext(TargetProgram* target, IRModule* inModule);
IRTypeLegalizationContext(TargetProgram* target, IRModule* inModule, DiagnosticSink* sink);

// When inserting new globals, put them before this one.
IRInst* insertBeforeGlobal = nullptr;
Expand Down
33 changes: 33 additions & 0 deletions tests/diagnostics/uninitialized-resource-type.slang
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//DIAGNOSTIC_TEST:SIMPLE: -target hlsl

SamplerState sampler;

struct Foo
{
bool sample_bar = false;
Texture2D<float4> bar = {};
};

struct Result
{
float4 color = float4(0.0);
};

Result process(in Foo foo)
{
Result result = {};

if (foo.sample_bar) {
result.color = foo.bar.Sample(sampler, float2(0.0, 0.0));
}

return result;
}

[shader("compute")]
[numthreads(8, 8, 1)]
float4 cs_main(uint3 thread_id : SV_DispatchThreadID) {
Foo foo;
const let result = process(foo);
return result.color;
}
9 changes: 9 additions & 0 deletions tests/diagnostics/uninitialized-resource-type.slang.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
result code = -1
standard error = {
tests/diagnostics/test1.slang(31): warning 41016: use of uninitialized variable 'foo'
const let result = process(foo);
^
tests/diagnostics/test1.slang(5): error 56003: use of uninitialized resource type 'Texture2D'.
struct Foo
^~~
}

0 comments on commit f642878

Please sign in to comment.