Check for out-of-range bindings during IO mapping.
diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index 5d30ac2..f0a4f93 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -584,6 +584,12 @@
if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
LinkFailed = true;
+ // Map IO
+ if (Options & EOptionSpv) {
+ if (!program.mapIO())
+ LinkFailed = true;
+ }
+
// Report
if (! (Options & EOptionSuppressInfolog) &&
! (Options & EOptionMemoryLeakMode)) {
@@ -591,10 +597,6 @@
PutsIfNonEmpty(program.getInfoDebugLog());
}
- // Map IO
- if (Options & EOptionSpv)
- program.mapIO();
-
// Reflect
if (Options & EOptionDumpReflection) {
program.buildReflection();
diff --git a/Test/baseResults/spv.register.autoassign.rangetest.frag.out b/Test/baseResults/spv.register.autoassign.rangetest.frag.out
new file mode 100644
index 0000000..a521a13
--- /dev/null
+++ b/Test/baseResults/spv.register.autoassign.rangetest.frag.out
@@ -0,0 +1,12 @@
+spv.register.autoassign.rangetest.frag
+
+Linked fragment stage:
+
+INTERNAL ERROR: mapped binding out of range: g_tScene
+INTERNAL ERROR: mapped binding out of range: g_tSamp
+INTERNAL ERROR: mapped binding out of range: g_tScene
+INTERNAL ERROR: mapped binding out of range: g_tSamp
+INTERNAL ERROR: mapped binding out of range: g_tSamp
+INTERNAL ERROR: mapped binding out of range: g_tScene
+
+SPIR-V is not generated for failed compile or link
diff --git a/Test/spv.register.autoassign.rangetest.frag b/Test/spv.register.autoassign.rangetest.frag
new file mode 100644
index 0000000..c81c395
--- /dev/null
+++ b/Test/spv.register.autoassign.rangetest.frag
@@ -0,0 +1,15 @@
+
+SamplerState g_tSamp : register(s5);
+
+Texture2D g_tScene[2] : register(t5);
+
+struct PS_OUTPUT
+{
+ float4 Color : SV_Target0;
+};
+
+void main(out PS_OUTPUT psout)
+{
+ psout.Color = g_tScene[0].Sample(g_tSamp, 0.3) +
+ g_tScene[1].Sample(g_tSamp, 0.3);
+}
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index e00638b..5333af4 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -1724,7 +1724,7 @@
for (int s = 0; s < EShLangCount; ++s) {
if (intermediate[s]) {
- if (! ioMapper->addStage((EShLanguage)s, *intermediate[s]))
+ if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink))
return false;
}
}
diff --git a/glslang/MachineIndependent/iomapper.cpp b/glslang/MachineIndependent/iomapper.cpp
index d69cc13..15847dd 100644
--- a/glslang/MachineIndependent/iomapper.cpp
+++ b/glslang/MachineIndependent/iomapper.cpp
@@ -34,6 +34,7 @@
//
#include "../Include/Common.h"
+#include "../Include/InfoSink.h"
#include "iomapper.h"
#include "LiveTraverser.h"
#include "localintermediate.h"
@@ -150,11 +151,30 @@
class TIoMappingTraverser : public TBindingTraverser {
public:
TIoMappingTraverser(TIntermediate& i, TBindingMap& bindingMap, TUsedBindings& usedBindings,
- bool traverseDeadCode) :
- TBindingTraverser(i, bindingMap, usedBindings, traverseDeadCode)
+ TInfoSink& infoSink, bool traverseDeadCode) :
+ TBindingTraverser(i, bindingMap, usedBindings, traverseDeadCode),
+ infoSink(infoSink),
+ assignError(false)
{ }
+ bool success() const { return !assignError; }
+
protected:
+ unsigned checkBindingRange(const TIntermSymbol& base, unsigned binding)
+ {
+ if (binding >= TQualifier::layoutBindingEnd) {
+ TString err = "mapped binding out of range: ";
+ err += base.getName();
+
+ infoSink.info.message(EPrefixInternalError, err.c_str());
+ assignError = true;
+
+ return 0;
+ }
+
+ return binding;
+ }
+
void addUniform(TIntermSymbol& base) override
{
// Skip things we don't intend to bind.
@@ -165,7 +185,7 @@
// Apply existing binding, if we were given one or already made one up.
if (existingBinding != -1) {
- base.getWritableType().getQualifier().layoutBinding = existingBinding;
+ base.getWritableType().getQualifier().layoutBinding = checkBindingRange(base, existingBinding);
return;
}
@@ -174,7 +194,7 @@
const int freeBinding = getFreeBinding(base.getType(), getBindingBase(base.getType()));
markBinding(base, freeBinding);
- base.getWritableType().getQualifier().layoutBinding = freeBinding;
+ base.getWritableType().getQualifier().layoutBinding = checkBindingRange(base, freeBinding);
}
}
@@ -195,13 +215,17 @@
return nextBinding;
}
+
+private:
+ bool assignError; // true if there was an error assigning the bindings
+ TInfoSink& infoSink;
};
// Map I/O variables to provided offsets, and make bindings for
// unbound but live variables.
//
// Returns false if the input is too malformed to do this.
-bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate)
+bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate, TInfoSink& infoSink)
{
// Trivial return if there is nothing to do.
if (intermediate.getShiftSamplerBinding() == 0 &&
@@ -223,7 +247,7 @@
TBindingTraverser it_binding_all(intermediate, bindingMap, usedBindings, true);
TBindingTraverser it_binding_live(intermediate, bindingMap, usedBindings, false);
- TIoMappingTraverser it_iomap(intermediate, bindingMap, usedBindings, true);
+ TIoMappingTraverser it_iomap(intermediate, bindingMap, usedBindings, infoSink, true);
// Traverse all (live+dead) code to find explicit bindings, so we can avoid those.
root->traverse(&it_binding_all);
@@ -240,7 +264,7 @@
// Bind everything that needs a binding and doesn't have one.
root->traverse(&it_iomap);
- return true;
+ return it_iomap.success();
}
} // end namespace glslang
diff --git a/glslang/MachineIndependent/iomapper.h b/glslang/MachineIndependent/iomapper.h
index 69ed4c5..68dec77 100644
--- a/glslang/MachineIndependent/iomapper.h
+++ b/glslang/MachineIndependent/iomapper.h
@@ -42,6 +42,8 @@
// A reflection database and its interface, consistent with the OpenGL API reflection queries.
//
+class TInfoSink;
+
namespace glslang {
class TIntermediate;
@@ -53,7 +55,7 @@
virtual ~TIoMapper() {}
// grow the reflection stage by stage
- bool addStage(EShLanguage, TIntermediate&);
+ bool addStage(EShLanguage, TIntermediate&, TInfoSink&);
};
} // end namespace glslang
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index ee27db2..d0296f8 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -285,6 +285,10 @@
{ "spv.register.noautoassign.frag", "main_ep", 5, 10, 15, false, false },
{ "spv.register.autoassign-2.frag", "main", 5, 10, 15, true, true },
{ "spv.buffer.autoassign.frag", "main", 5, 10, 15, true, true },
+ { "spv.register.autoassign.rangetest.frag", "main",
+ glslang::TQualifier::layoutBindingEnd-2,
+ glslang::TQualifier::layoutBindingEnd+5,
+ 20, true, false },
}),
FileNameAsCustomTestSuffixIoMap
);