From 6a982124879aa4d692669bc5e57b3a1d73f9fcfc Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Tue, 11 Feb 2025 15:04:47 -0800 Subject: [PATCH] Fix crash when handling uninitialized resource type close #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. --- source/slang/slang-diagnostic-defs.h | 6 +++ source/slang/slang-ir-legalize-types.cpp | 47 ++++++++++++------- source/slang/slang-legalize-types.h | 3 +- .../uninitialized-resource-type.slang | 33 +++++++++++++ ...uninitialized-resource-type.slang.expected | 9 ++++ 5 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 tests/diagnostics/uninitialized-resource-type.slang create mode 100644 tests/diagnostics/uninitialized-resource-type.slang.expected diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index acb9beb945..c54132a1f8 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -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, diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index a3e47fd556..994a400698 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -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; @@ -100,6 +100,8 @@ IRTypeLegalizationContext::IRTypeLegalizationContext(TargetProgram* target, IRMo builderStorage = IRBuilder(inModule); builder = &builderStorage; + + m_sink = sink; } static void registerLegalizedValue( @@ -2046,6 +2048,22 @@ static LegalVal coerceToLegalType(IRTypeLegalizationContext* context, LegalType } } +static LegalVal legalizeUndefined(IRTypeLegalizationContext* context, IRInst* inst) +{ + if (auto structType = as(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, @@ -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 @@ -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) { } @@ -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) { } @@ -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) { } @@ -4129,9 +4147,7 @@ void legalizeResourceTypes(TargetProgram* target, IRModule* module, DiagnosticSi { SLANG_PROFILE; - SLANG_UNUSED(sink); - - IRResourceTypeLegalizationContext context(target, module); + IRResourceTypeLegalizationContext context(target, module, sink); legalizeTypes(&context); } @@ -4139,18 +4155,13 @@ void legalizeExistentialTypeLayout(TargetProgram* target, IRModule* module, Diag { 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); } diff --git a/source/slang/slang-legalize-types.h b/source/slang/slang-legalize-types.h index eaee373b20..de574be0d4 100644 --- a/source/slang/slang-legalize-types.h +++ b/source/slang/slang-legalize-types.h @@ -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; diff --git a/tests/diagnostics/uninitialized-resource-type.slang b/tests/diagnostics/uninitialized-resource-type.slang new file mode 100644 index 0000000000..84d398adf2 --- /dev/null +++ b/tests/diagnostics/uninitialized-resource-type.slang @@ -0,0 +1,33 @@ +//DIAGNOSTIC_TEST:SIMPLE: -target hlsl + +SamplerState sampler; + +struct Foo +{ + bool sample_bar = false; + Texture2D 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; +} diff --git a/tests/diagnostics/uninitialized-resource-type.slang.expected b/tests/diagnostics/uninitialized-resource-type.slang.expected new file mode 100644 index 0000000000..9ae44cdd3a --- /dev/null +++ b/tests/diagnostics/uninitialized-resource-type.slang.expected @@ -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 + ^~~ +}