summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/slang-check-out-of-bound-access.cpp89
-rw-r--r--source/slang/slang-check-out-of-bound-access.h12
-rw-r--r--source/slang/slang-diagnostic-defs.h5
-rw-r--r--source/slang/slang-emit.cpp2
-rw-r--r--tests/diagnostics/array-out-of-bounds-2.slang29
-rw-r--r--tests/diagnostics/array-out-of-bounds.slang28
-rw-r--r--tests/language-feature/0-array-1.slang12
7 files changed, 173 insertions, 4 deletions
diff --git a/source/slang/slang-check-out-of-bound-access.cpp b/source/slang/slang-check-out-of-bound-access.cpp
new file mode 100644
index 000000000..51adc2b4c
--- /dev/null
+++ b/source/slang/slang-check-out-of-bound-access.cpp
@@ -0,0 +1,89 @@
+// slang-check-out-of-bound-access.cpp
+#include "slang-check-out-of-bound-access.h"
+
+#include "slang-ir-inst-pass-base.h"
+#include "slang-ir-insts.h"
+#include "slang-ir.h"
+
+namespace Slang
+{
+
+struct OutOfBoundAccessChecker : public InstPassBase
+{
+ DiagnosticSink* sink;
+
+ OutOfBoundAccessChecker(IRModule* inModule, DiagnosticSink* inSink)
+ : InstPassBase(inModule), sink(inSink)
+ {
+ }
+
+
+ void checkArrayAccess(IRInst* inst, IRInst* base, IRInst* index)
+ {
+ // Check if index is a constant integer
+ auto indexLit = as<IRIntLit>(index);
+ if (!indexLit)
+ return; // Skip non-constant indices
+
+ // Get the base type
+ auto baseType = base->getDataType();
+
+ // Handle pointer-to-array case (for GetElementPtr)
+ if (auto ptrType = as<IRPtrTypeBase>(baseType))
+ {
+ baseType = ptrType->getValueType();
+ }
+
+ // Check if base is an array type
+ auto arrayType = as<IRArrayTypeBase>(baseType);
+ if (!arrayType)
+ return; // Skip non-array types
+
+ // Check if array size is a constant
+ auto arraySizeInst = arrayType->getElementCount();
+ auto arraySizeLit = as<IRIntLit>(arraySizeInst);
+ if (!arraySizeLit)
+ return; // Skip arrays with non-constant size
+
+ // Get the actual values
+ IRIntegerValue indexValue = indexLit->getValue();
+ IRIntegerValue arraySizeValue = arraySizeLit->getValue();
+
+ // Check bounds: index should be >= 0 and < arraySize
+ if (indexValue < 0 || indexValue >= arraySizeValue)
+ {
+ sink->diagnose(inst, Diagnostics::arrayIndexOutOfBounds, indexValue, arraySizeValue);
+ }
+ }
+
+ void processModule()
+ {
+ processAllInsts(
+ [&](IRInst* inst)
+ {
+ switch (inst->getOp())
+ {
+ case kIROp_GetElement:
+ case kIROp_GetElementPtr:
+ {
+ if (inst->getOperandCount() < 2)
+ return;
+
+ auto base = inst->getOperand(0);
+ auto index = inst->getOperand(1);
+
+ checkArrayAccess(inst, base, index);
+ }
+ break;
+ }
+ });
+ }
+};
+
+void checkForOutOfBoundAccess(IRModule* module, DiagnosticSink* sink)
+{
+ OutOfBoundAccessChecker checker(module, sink);
+ checker.processModule();
+}
+
+} // namespace Slang \ No newline at end of file
diff --git a/source/slang/slang-check-out-of-bound-access.h b/source/slang/slang-check-out-of-bound-access.h
new file mode 100644
index 000000000..17f4e8c3d
--- /dev/null
+++ b/source/slang/slang-check-out-of-bound-access.h
@@ -0,0 +1,12 @@
+// slang-check-out-of-bound-access.h
+#pragma once
+
+#include "slang-ir.h"
+
+namespace Slang
+{
+struct IRModule;
+class DiagnosticSink;
+
+void checkForOutOfBoundAccess(IRModule* module, DiagnosticSink* sink);
+} // namespace Slang \ No newline at end of file
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 3d584679e..0ce5d9f47 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -659,6 +659,11 @@ DIAGNOSTIC(
"Cannot convert array of size $0 to array of size $1 as this would truncate data")
DIAGNOSTIC(30025, Error, invalidArraySize, "array size must be non-negative.")
DIAGNOSTIC(
+ 30029,
+ Error,
+ arrayIndexOutOfBounds,
+ "array index '$0' is out of bounds for array of size '$1'.")
+DIAGNOSTIC(
30026,
Error,
returnInComponentMustComeLast,
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 1657a2980..f40679bd9 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -9,6 +9,7 @@
#include "../core/slang-performance-profiler.h"
#include "../core/slang-type-text-util.h"
#include "../core/slang-writer.h"
+#include "slang-check-out-of-bound-access.h"
#include "slang-emit-c-like.h"
#include "slang-emit-cpp.h"
#include "slang-emit-cuda.h"
@@ -1109,6 +1110,7 @@ Result linkAndOptimizeIR(
{
checkForRecursiveTypes(irModule, sink);
checkForRecursiveFunctions(codeGenContext->getTargetReq(), irModule, sink);
+ checkForOutOfBoundAccess(irModule, sink);
if (requiredLoweringPassSet.missingReturn)
checkForMissingReturns(irModule, sink, target, false);
diff --git a/tests/diagnostics/array-out-of-bounds-2.slang b/tests/diagnostics/array-out-of-bounds-2.slang
new file mode 100644
index 000000000..978f61d9f
--- /dev/null
+++ b/tests/diagnostics/array-out-of-bounds-2.slang
@@ -0,0 +1,29 @@
+// array-out-of-bounds-2.slang
+
+// Test the specific scenario from the issue (array of size 3, accessing index 3)
+
+//TEST:SIMPLE(filecheck=CHECK): -target spirv -entry computeMain -stage compute
+
+struct SH3_t
+{
+ float coeffs[4];
+};
+
+RWStructuredBuffer<float> outputBuffer;
+
+[numthreads(1, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ SH3_t a[3];
+ SH3_t b;
+
+ for (int i = 0; i < 3; ++i)
+ {
+ // This should be fine
+ outputBuffer[i] = a[i].coeffs[0];
+ }
+
+ // This reproduces the issue - accessing index 3 in array of size 3
+ //CHECK: error 30029: array index '3' is out of bounds for array of size '3'.
+ outputBuffer[3] = a[3].coeffs[0];
+} \ No newline at end of file
diff --git a/tests/diagnostics/array-out-of-bounds.slang b/tests/diagnostics/array-out-of-bounds.slang
new file mode 100644
index 000000000..81c243031
--- /dev/null
+++ b/tests/diagnostics/array-out-of-bounds.slang
@@ -0,0 +1,28 @@
+// array-out-of-bounds.slang
+
+// Test that out-of-bounds array access with constant indices generates an error
+
+//TEST:SIMPLE(filecheck=CHECK): -target spirv -entry computeMain -stage compute
+
+RWStructuredBuffer<int> outputBuffer;
+
+[numthreads(1, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ int a[3];
+ a[0] = 10;
+ a[1] = 20;
+ a[2] = 30;
+
+ // Valid access - should be fine
+ outputBuffer[0] = a[0];
+ outputBuffer[1] = a[2];
+
+ // Invalid access - index 3 is out of bounds for array of size 3
+ //CHECK: error 30029: array index '3' is out of bounds for array of size '3'.
+ outputBuffer[2] = a[3];
+
+ // Invalid access - negative index
+ //CHECK: error 30029: array index '-1' is out of bounds for array of size '3'.
+ outputBuffer[3] = a[-1];
+} \ No newline at end of file
diff --git a/tests/language-feature/0-array-1.slang b/tests/language-feature/0-array-1.slang
index 327f71444..b02be1af0 100644
--- a/tests/language-feature/0-array-1.slang
+++ b/tests/language-feature/0-array-1.slang
@@ -10,7 +10,7 @@ uniform MyData* myData;
uniform int * output;
[numthreads(1, 1, 1)]
-void computeMain()
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
// These are all ill-formed, but we want to still ensure our backend
// can handle them gracefully without crashing.
@@ -18,9 +18,13 @@ void computeMain()
// by a `if` statement that checks the size before accessing.
// The condition would then evaluate to false and causing all the accessing
// code to be optimized out.
- InterlockedAdd(myData.a[0][0][0], 1);
- myData.a[0][0][0] += 1;
- output[0] = myData.a[0][0][0];
+
+ // Use runtime values to access the 0-sized array to avoid triggering
+ // the new out-of-bounds diagnostic for constant indices
+ uint runtimeIndex = dispatchThreadID.x;
+ InterlockedAdd(myData.a[runtimeIndex][runtimeIndex][runtimeIndex], 1);
+ myData.a[runtimeIndex][runtimeIndex][runtimeIndex] += 1;
+ output[0] = myData.a[runtimeIndex][runtimeIndex][runtimeIndex];
}
//SPV: OpEntryPoint