Merge pull request #699 from billhollings/master
Fix crash when VkDeviceCreateInfo specifies queue families out of numerical order.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index a3a2ce3..7000655 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -20,6 +20,7 @@
- Revert to supporting host-coherent memory for linear images on macOS.
- Ensure Vulkan loader magic number is set every time before returning any dispatchable Vulkan handle.
+- Fix crash when `VkDeviceCreateInfo` specifies queue families out of numerical order.
- Consolidate the various linkable objects into a `MVKLinkableMixin` template base class.
- Use `MVKVector` whenever possible in MoltenVK, especially within render loop.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 438674c..b1930c2 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -2499,7 +2499,11 @@
VkQueueFamilyProperties qfProps;
qFam->getProperties(&qfProps);
- _queuesByQueueFamilyIndex.resize(qfIdx + 1); // Ensure an entry for this queue family exists
+ // Ensure an entry for this queue family exists
+ uint32_t qfCntMin = qfIdx + 1;
+ if (_queuesByQueueFamilyIndex.size() < qfCntMin) {
+ _queuesByQueueFamilyIndex.resize(qfCntMin);
+ }
auto& queues = _queuesByQueueFamilyIndex[qfIdx];
uint32_t qCnt = min(pQFInfo->queueCount, qfProps.queueCount);
for (uint32_t qIdx = 0; qIdx < qCnt; qIdx++) {
diff --git a/MoltenVK/MoltenVK/Utility/MVKVector.h b/MoltenVK/MoltenVK/Utility/MVKVector.h
index eac2b57..e7843a8 100755
--- a/MoltenVK/MoltenVK/Utility/MVKVector.h
+++ b/MoltenVK/MoltenVK/Utility/MVKVector.h
@@ -412,14 +412,14 @@
iterator begin() const { return iterator( 0, *this ); }
iterator end() const { return iterator( alc.num_elements_used, *this ); }
- const Type &operator[]( const size_t i ) const override { return alc.ptr[i]; }
- Type &operator[]( const size_t i ) override { return alc.ptr[i]; }
- const Type &at( const size_t i ) const override { return alc.ptr[i]; }
- Type &at( const size_t i ) override { return alc.ptr[i]; }
- const Type &front() const override { return alc.ptr[0]; }
- Type &front() override { return alc.ptr[0]; }
- const Type &back() const override { return alc.ptr[alc.num_elements_used - 1]; }
- Type &back() override { return alc.ptr[alc.num_elements_used - 1]; }
+ const Type &operator[]( const size_t i ) const override { return alc[i]; }
+ Type &operator[]( const size_t i ) override { return alc[i]; }
+ const Type &at( const size_t i ) const override { return alc[i]; }
+ Type &at( const size_t i ) override { return alc[i]; }
+ const Type &front() const override { return alc[0]; }
+ Type &front() override { return alc[0]; }
+ const Type &back() const override { return alc[alc.num_elements_used - 1]; }
+ Type &back() override { return alc[alc.num_elements_used - 1]; }
const Type *data() const override { return alc.ptr; }
Type *data() override { return alc.ptr; }
@@ -820,16 +820,16 @@
iterator begin() { return iterator( 0, *this ); }
iterator end() { return iterator( alc.num_elements_used, *this ); }
- const Type * const at( const size_t i ) const override { return alc.ptr[i]; }
- Type * &at( const size_t i ) override { return alc.ptr[i]; }
- const Type * const operator[]( const size_t i ) const override { return alc.ptr[i]; }
- Type * &operator[]( const size_t i ) override { return alc.ptr[i]; }
- const Type * const front() const override { return alc.ptr[0]; }
- Type * &front() override { return alc.ptr[0]; }
- const Type * const back() const override { return alc.ptr[alc.num_elements_used - 1]; }
- Type * &back() override { return alc.ptr[alc.num_elements_used - 1]; }
- const Type * const *data() const override { return &alc.ptr[0]; }
- Type * *data() override { return &alc.ptr[0]; }
+ const Type * const at( const size_t i ) const override { return alc[i]; }
+ Type * &at( const size_t i ) override { return alc[i]; }
+ const Type * const operator[]( const size_t i ) const override { return alc[i]; }
+ Type * &operator[]( const size_t i ) override { return alc[i]; }
+ const Type * const front() const override { return alc[0]; }
+ Type * &front() override { return alc[0]; }
+ const Type * const back() const override { return alc[alc.num_elements_used - 1]; }
+ Type * &back() override { return alc[alc.num_elements_used - 1]; }
+ const Type * const *data() const override { return alc.ptr; }
+ Type * *data() override { return alc.ptr; }
size_t size() const override { return alc.num_elements_used; }
bool empty() const override { return alc.num_elements_used == 0; }
diff --git a/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
index 4379af6..9726922 100755
--- a/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
+++ b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
@@ -21,6 +21,10 @@
#include <new>
#include <type_traits>
+
+#define MVK_VECTOR_CHECK_BOUNDS if (i >= num_elements_used) { throw std::out_of_range("Index out of range"); }
+
+
namespace mvk_memory_allocator
{
inline char *alloc( const size_t num_bytes )
@@ -53,8 +57,8 @@
mvk_vector_allocator_base( T *_ptr, const size_t _num_elements_used ) : ptr{ _ptr }, num_elements_used{ _num_elements_used } { }
virtual ~mvk_vector_allocator_base() { }
- const T &operator[]( const size_t i ) const { return ptr[i]; }
- T &operator[]( const size_t i ) { return ptr[i]; }
+ const T &operator[]( const size_t i ) const { MVK_VECTOR_CHECK_BOUNDS return ptr[i]; }
+ T &operator[]( const size_t i ) { MVK_VECTOR_CHECK_BOUNDS return ptr[i]; }
size_t size() const { return num_elements_used; }