Fix crash when VkDeviceCreateInfo specifies queue families out of numerical order.

MVKDevice check highest queue family index before expanding queue family collection.
MVKVector add bounds check to at(), [], front() & back() functions.
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; }