@@ -1555,6 +1555,60 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
1555
1555
return _.diag (SPV_ERROR_INVALID_ID, inst)
1556
1556
<< " Base type must be a non-pointer type" ;
1557
1557
}
1558
+
1559
+ const auto ContainsBlock = [&_](const Instruction* type_inst) {
1560
+ if (type_inst->opcode () == spv::Op::OpTypeStruct) {
1561
+ if (_.HasDecoration (type_inst->id (), spv::Decoration::Block) ||
1562
+ _.HasDecoration (type_inst->id (), spv::Decoration::BufferBlock)) {
1563
+ return true ;
1564
+ }
1565
+ }
1566
+ return false ;
1567
+ };
1568
+
1569
+ // Block (and BufferBlock) arrays cannot be reinterpreted via untyped access
1570
+ // chains.
1571
+ const bool base_type_block_array =
1572
+ base_type->opcode () == spv::Op::OpTypeArray &&
1573
+ _.ContainsType (base_type->id (), ContainsBlock,
1574
+ /* traverse_all_types = */ false );
1575
+
1576
+ const auto base_index = untyped_pointer ? 3 : 2 ;
1577
+ const auto base_id = inst->GetOperandAs <uint32_t >(base_index);
1578
+ auto base = _.FindDef (base_id);
1579
+ // Strictly speaking this misses trivial access chains and function
1580
+ // parameter chasing, but that would be a significant complication in the
1581
+ // traversal.
1582
+ while (base->opcode () == spv::Op::OpCopyObject) {
1583
+ base = _.FindDef (base->GetOperandAs <uint32_t >(2 ));
1584
+ }
1585
+ const Instruction* base_data_type = nullptr ;
1586
+ if (base->opcode () == spv::Op::OpVariable) {
1587
+ const auto ptr_type = _.FindDef (base->type_id ());
1588
+ base_data_type = _.FindDef (ptr_type->GetOperandAs <uint32_t >(2 ));
1589
+ } else if (base->opcode () == spv::Op::OpUntypedVariableKHR) {
1590
+ if (base->operands ().size () > 3 ) {
1591
+ base_data_type = _.FindDef (base->GetOperandAs <uint32_t >(3 ));
1592
+ }
1593
+ }
1594
+
1595
+ if (base_data_type) {
1596
+ const bool base_block_array =
1597
+ base_data_type->opcode () == spv::Op::OpTypeArray &&
1598
+ _.ContainsType (base_data_type->id (), ContainsBlock,
1599
+ /* traverse_all_types = */ false );
1600
+
1601
+ if (base_type_block_array != base_block_array) {
1602
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
1603
+ << " Both Base Type and Base must be Block or BufferBlock arrays "
1604
+ " or neither can be" ;
1605
+ } else if (base_type_block_array && base_block_array &&
1606
+ base_type->id () != base_data_type->id ()) {
1607
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
1608
+ << " If Base or Base Type is a Block or BufferBlock array, the "
1609
+ " other must also be the same array" ;
1610
+ }
1611
+ }
1558
1612
}
1559
1613
1560
1614
// Base must be a pointer, pointing to the base of a composite object.
@@ -1845,14 +1899,34 @@ spv_result_t ValidatePtrAccessChain(ValidationState_t& _,
1845
1899
1846
1900
const bool untyped_pointer = spvOpcodeGeneratesUntypedPointer (inst->opcode ());
1847
1901
1848
- const auto base_id = inst->GetOperandAs <uint32_t >(2 );
1849
- const auto base = _.FindDef (base_id);
1850
- const auto base_type = untyped_pointer
1851
- ? _.FindDef (inst->GetOperandAs <uint32_t >(2 ))
1852
- : _.FindDef (base->type_id ());
1902
+ const auto base_idx = untyped_pointer ? 3 : 2 ;
1903
+ const auto base = _.FindDef (inst->GetOperandAs <uint32_t >(base_idx));
1904
+ const auto base_type = _.FindDef (base->type_id ());
1853
1905
const auto base_type_storage_class =
1854
1906
base_type->GetOperandAs <spv::StorageClass>(1 );
1855
1907
1908
+ const auto element_idx = untyped_pointer ? 4 : 3 ;
1909
+ const auto element = _.FindDef (inst->GetOperandAs <uint32_t >(element_idx));
1910
+ const auto element_type = _.FindDef (element->type_id ());
1911
+ if (!element_type || element_type->opcode () != spv::Op::OpTypeInt) {
1912
+ return _.diag (SPV_ERROR_INVALID_DATA, inst) << " Element must be an integer" ;
1913
+ }
1914
+ uint64_t element_val = 0 ;
1915
+ if (_.EvalConstantValUint64 (element->id (), &element_val)) {
1916
+ if (element_val != 0 ) {
1917
+ const auto interp_type =
1918
+ untyped_pointer ? _.FindDef (inst->GetOperandAs <uint32_t >(2 ))
1919
+ : _.FindDef (base_type->GetOperandAs <uint32_t >(2 ));
1920
+ if (interp_type->opcode () == spv::Op::OpTypeStruct &&
1921
+ (_.HasDecoration (interp_type->id (), spv::Decoration::Block) ||
1922
+ _.HasDecoration (interp_type->id (), spv::Decoration::BufferBlock))) {
1923
+ return _.diag (SPV_ERROR_INVALID_DATA, inst)
1924
+ << " Element must be 0 if the interpretation type is a Block- or "
1925
+ " BufferBlock-decorated structure" ;
1926
+ }
1927
+ }
1928
+ }
1929
+
1856
1930
if (_.HasCapability (spv::Capability::Shader) &&
1857
1931
(base_type_storage_class == spv::StorageClass::Uniform ||
1858
1932
base_type_storage_class == spv::StorageClass::StorageBuffer ||
0 commit comments