[val] Fix crash evaluating >64-bit integer constants in EvalConstantVal{Uint,Int}64 (#6816)diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index fe57eea..c118fd6 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -1876,10 +1876,12 @@
return false;
} else if (inst->words().size() == 4) {
*val = inst->word(3);
- } else {
- assert(inst->words().size() == 5);
+ } else if (inst->words().size() == 5) {
*val = inst->word(3);
*val |= uint64_t(inst->word(4)) << 32;
+ } else {
+ // Literal value wider than 64 bits does not fit in a uint64_t.
+ return false;
}
return true;
}
@@ -1922,11 +1924,13 @@
return false;
} else if (inst->words().size() == 4) {
*val = int32_t(inst->word(3));
- } else {
- assert(inst->words().size() == 5);
+ } else if (inst->words().size() == 5) {
const uint32_t lo_word = inst->word(3);
const uint32_t hi_word = inst->word(4);
*val = static_cast<int64_t>(uint64_t(lo_word) | uint64_t(hi_word) << 32);
+ } else {
+ // Literal value wider than 64 bits does not fit in an int64_t.
+ return false;
}
return true;
}
diff --git a/test/val/val_extension_spv_intel_arbitrary_precision_integers_test.cpp b/test/val/val_extension_spv_intel_arbitrary_precision_integers_test.cpp
index c21bfc8..b8f4ea9 100644
--- a/test/val/val_extension_spv_intel_arbitrary_precision_integers_test.cpp
+++ b/test/val/val_extension_spv_intel_arbitrary_precision_integers_test.cpp
@@ -15,14 +15,21 @@
// Tests for SPV_INTEL_arbitrary_precision_integers extension
#include <string>
+#include <vector>
#include "gmock/gmock.h"
+#include "source/opcode.h"
+#include "source/util/string_utils.h"
+#include "test/unit_spirv.h"
#include "test/val/val_fixtures.h"
namespace spvtools {
namespace val {
namespace {
+using ::spvtest::Concatenate;
+using ::spvtest::MakeInstruction;
+using ::spvtest::ScopedContext;
using ::testing::HasSubstr;
using ValidateIntelArbitraryPrecisionIntegers = spvtest::ValidateBase<bool>;
@@ -173,6 +180,45 @@
EXPECT_THAT(getDiagnosticString(), HasSubstr("OpTypeInt has 0 bits"));
}
+// Built as a raw binary since the assembler rejects integer literals wider
+// than 64 bits.
+TEST_F(ValidateIntelArbitraryPrecisionIntegers,
+ WideIntegerConstantAsArrayLengthDoesNotCrash) {
+ const uint32_t kInt128Id = 1;
+ const uint32_t kConstId = 2;
+ const uint32_t kFloatId = 3;
+ const uint32_t kArrayId = 4;
+
+ std::vector<uint32_t> words = Concatenate({
+ {spv::MagicNumber, 0x10000, 0u, 5u /* id bound */, 0u},
+ MakeInstruction(spv::Op::OpCapability,
+ {uint32_t(spv::Capability::Shader)}),
+ MakeInstruction(
+ spv::Op::OpCapability,
+ {uint32_t(spv::Capability::ArbitraryPrecisionIntegersINTEL)}),
+ MakeInstruction(spv::Op::OpCapability,
+ {uint32_t(spv::Capability::Linkage)}),
+ MakeInstruction(
+ spv::Op::OpExtension,
+ utils::MakeVector("SPV_INTEL_arbitrary_precision_integers")),
+ MakeInstruction(spv::Op::OpMemoryModel,
+ {uint32_t(spv::AddressingModel::Logical),
+ uint32_t(spv::MemoryModel::GLSL450)}),
+ MakeInstruction(spv::Op::OpTypeInt, {kInt128Id, 128u, 0u}),
+ // A 128-bit OpConstant carries 4 literal words (16 bytes).
+ MakeInstruction(spv::Op::OpConstant,
+ {kInt128Id, kConstId, 4u, 0u, 0u, 0u}),
+ MakeInstruction(spv::Op::OpTypeFloat, {kFloatId, 32u}),
+ MakeInstruction(spv::Op::OpTypeArray, {kArrayId, kFloatId, kConstId}),
+ });
+
+ spv_diagnostic diagnostic = nullptr;
+ spv_const_binary_t binary{words.data(), words.size()};
+ ScopedContext context;
+ EXPECT_EQ(SPV_SUCCESS, spvValidate(context.context, &binary, &diagnostic));
+ spvDiagnosticDestroy(diagnostic);
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_validation_state_test.cpp b/test/val/val_validation_state_test.cpp
index 05a5de4..0a9b4ef 100644
--- a/test/val/val_validation_state_test.cpp
+++ b/test/val/val_validation_state_test.cpp
@@ -15,9 +15,11 @@
// Basic tests for the ValidationState_t datastructure.
#include <string>
+#include <vector>
#include "gmock/gmock.h"
#include "source/spirv_validator_options.h"
+#include "source/util/string_utils.h"
#include "test/unit_spirv.h"
#include "test/val/val_fixtures.h"
@@ -307,6 +309,45 @@
" %1 = OpFunction %void Pure|Const %3\n"));
}
+TEST_F(ValidationStateTest, EvalConstantValWiderThan64BitsIsNotEvaluable) {
+ const uint32_t kInt128Id = 1;
+ const uint32_t kConstId = 2;
+
+ std::vector<uint32_t> words = spvtest::Concatenate({
+ {spv::MagicNumber, 0x10000, 0u, 3u /* id bound */, 0u},
+ spvtest::MakeInstruction(spv::Op::OpCapability,
+ {uint32_t(spv::Capability::Shader)}),
+ spvtest::MakeInstruction(
+ spv::Op::OpCapability,
+ {uint32_t(spv::Capability::ArbitraryPrecisionIntegersINTEL)}),
+ spvtest::MakeInstruction(spv::Op::OpCapability,
+ {uint32_t(spv::Capability::Linkage)}),
+ spvtest::MakeInstruction(
+ spv::Op::OpExtension,
+ utils::MakeVector("SPV_INTEL_arbitrary_precision_integers")),
+ spvtest::MakeInstruction(spv::Op::OpMemoryModel,
+ {uint32_t(spv::AddressingModel::Logical),
+ uint32_t(spv::MemoryModel::GLSL450)}),
+ spvtest::MakeInstruction(spv::Op::OpTypeInt, {kInt128Id, 128u, 0u}),
+ spvtest::MakeInstruction(spv::Op::OpConstant,
+ {kInt128Id, kConstId, 4u, 0u, 0u, 0u}),
+ });
+
+ spv_diagnostic diagnostic = nullptr;
+ spvtest::ScopedContext context;
+ EXPECT_EQ(SPV_SUCCESS,
+ spvtools::val::ValidateBinaryAndKeepValidationState(
+ context.context, getValidatorOptions(), words.data(),
+ words.size(), &diagnostic, &vstate_));
+ spvDiagnosticDestroy(diagnostic);
+
+ uint64_t uval = 0xdeadbeef;
+ EXPECT_FALSE(vstate_->EvalConstantValUint64(kConstId, &uval));
+
+ int64_t ival = 0xdeadbeef;
+ EXPECT_FALSE(vstate_->EvalConstantValInt64(kConstId, &ival));
+}
+
} // namespace
} // namespace val
} // namespace spvtools