layers: GH373 Add memory size/align tests&checks
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 2bc724d..28bffcd 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -5453,12 +5453,11 @@
     return skip_call;
 }
 
-static bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
+static bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
+                                            VkDeviceSize memoryOffset) {
     bool skip = false;
-    std::unique_lock<std::mutex> lock(global_lock);
-
-    auto buffer_state = GetBufferState(dev_data, buffer);
     if (buffer_state) {
+        std::unique_lock<std::mutex> lock(global_lock);
         // Track objects tied to memory
         uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
         skip = ValidateSetMemBinding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory()");
@@ -5497,6 +5496,18 @@
                             memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02174]);
         }
 
+        // Validate memory requirements size
+        if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) {
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+                            buffer_handle, __LINE__, VALIDATION_ERROR_02175, "DS",
+                            "vkBindBufferMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
+                            " but must be at least as large as "
+                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
+                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
+                            mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size,
+                            validation_error_map[VALIDATION_ERROR_02175]);
+        }
+
         // Validate device limits alignments
         static const VkBufferUsageFlagBits usage_list[3] = {
             static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
@@ -5534,10 +5545,10 @@
     return skip;
 }
 
-static void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
-    std::unique_lock<std::mutex> lock(global_lock);
-    auto buffer_state = GetBufferState(dev_data, buffer);
+static void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
+                                           VkDeviceSize memoryOffset) {
     if (buffer_state) {
+        std::unique_lock<std::mutex> lock(global_lock);
         // Track bound memory range information
         auto mem_info = GetMemObjInfo(dev_data, mem);
         if (mem_info) {
@@ -5557,11 +5568,12 @@
 VKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
     layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, mem, memoryOffset);
+    auto buffer_state = GetBufferState(dev_data, buffer);
+    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
     if (!skip) {
         result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
         if (result == VK_SUCCESS) {
-            PostCallRecordBindBufferMemory(dev_data, buffer, mem, memoryOffset);
+            PostCallRecordBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
         }
     }
     return result;
@@ -10062,12 +10074,11 @@
     return result;
 }
 
-static bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
+static bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
+                                           VkDeviceSize memoryOffset) {
     bool skip = false;
-    std::unique_lock<std::mutex> lock(global_lock);
-
-    auto image_state = GetImageState(dev_data, image);
     if (image_state) {
+        std::unique_lock<std::mutex> lock(global_lock);
         // Track objects tied to memory
         uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
         skip = ValidateSetMemBinding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory()");
@@ -10094,14 +10105,37 @@
             skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory()",
                                         VALIDATION_ERROR_00806);
         }
+
+        // Validate memory requirements alignment
+        if (vk_safe_modulo(memoryOffset, image_state->requirements.alignment) != 0) {
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            image_handle, __LINE__, VALIDATION_ERROR_02178, "DS",
+                            "vkBindImageMemory(): memoryOffset is 0x%" PRIxLEAST64
+                            " but must be an integer multiple of the "
+                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
+                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
+                            memoryOffset, image_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02178]);
+        }
+
+        // Validate memory requirements size
+        if (image_state->requirements.size > mem_info->alloc_info.allocationSize - memoryOffset) {
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            image_handle, __LINE__, VALIDATION_ERROR_02179, "DS",
+                            "vkBindImageMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
+                            " but must be at least as large as "
+                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
+                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
+                            mem_info->alloc_info.allocationSize - memoryOffset, image_state->requirements.size,
+                            validation_error_map[VALIDATION_ERROR_02179]);
+        }
     }
     return skip;
 }
 
-static void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
-    std::unique_lock<std::mutex> lock(global_lock);
-    auto image_state = GetImageState(dev_data, image);
+static void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
+                                          VkDeviceSize memoryOffset) {
     if (image_state) {
+        std::unique_lock<std::mutex> lock(global_lock);
         // Track bound memory range information
         auto mem_info = GetMemObjInfo(dev_data, mem);
         if (mem_info) {
@@ -10122,11 +10156,12 @@
 VKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
     layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    bool skip = PreCallValidateBindImageMemory(dev_data, image, mem, memoryOffset);
+    auto image_state = GetImageState(dev_data, image);
+    bool skip = PreCallValidateBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
     if (!skip) {
         result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
         if (result == VK_SUCCESS) {
-            PostCallRecordBindImageMemory(dev_data, image, mem, memoryOffset);
+            PostCallRecordBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
         }
     }
     return result;
diff --git a/layers/vk_validation_error_database.txt b/layers/vk_validation_error_database.txt
index ad996db..2cb4d76 100644
--- a/layers/vk_validation_error_database.txt
+++ b/layers/vk_validation_error_database.txt
@@ -2101,12 +2101,12 @@
 VALIDATION_ERROR_02171~^~Y~^~ImageLayerViewTests~^~vkCreateImageView~^~For more information refer to Vulkan Spec Section '11.5. Image Views' which states 'If image was created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT flag, format must be compatible with the format used to create image, as defined in Format Compatibility Classes' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageViewCreateInfo)~^~Multi-purposing this for some format compatibility checks, need unique enums.
 VALIDATION_ERROR_02172~^~Y~^~ImageLayerViewTests~^~vkCreateImageView~^~For more information refer to Vulkan Spec Section '11.5. Image Views' which states 'If image was not created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT flag, format must be identical to the format used to create image' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageViewCreateInfo)~^~
 VALIDATION_ERROR_02173~^~N~^~Unknown~^~vkCreateImageView~^~For more information refer to Vulkan Spec Section '11.5. Image Views' which states 'subResourceRange and viewType must be compatible with the image, as described in the compatibility table' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageViewCreateInfo)~^~
-VALIDATION_ERROR_02174~^~Y~^~Unknown~^~vkBindBufferMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'memoryOffset must be an integer multiple of the alignment member of the VkMemoryRequirements structure returned from a call to vkGetBufferMemoryRequirements with buffer' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindBufferMemory)~^~
-VALIDATION_ERROR_02175~^~N~^~Unknown~^~vkBindBufferMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'The size member of the VkMemoryRequirements structure returned from a call to vkGetBufferMemoryRequirements with buffer must be less than or equal to the size of memory minus memoryOffset' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindBufferMemory)~^~
+VALIDATION_ERROR_02174~^~Y~^~BindInvalidMemory~^~vkBindBufferMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'memoryOffset must be an integer multiple of the alignment member of the VkMemoryRequirements structure returned from a call to vkGetBufferMemoryRequirements with buffer' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindBufferMemory)~^~
+VALIDATION_ERROR_02175~^~Y~^~BindInvalidMemory~^~vkBindBufferMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'The size member of the VkMemoryRequirements structure returned from a call to vkGetBufferMemoryRequirements with buffer must be less than or equal to the size of memory minus memoryOffset' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindBufferMemory)~^~
 VALIDATION_ERROR_02176~^~N~^~Unknown~^~vkBindBufferMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'If buffer was created with VkDedicatedAllocationBufferCreateInfoNV::dedicatedAllocation equal to VK_TRUE, memory must have been created with VkDedicatedAllocationMemoryAllocateInfoNV::buffer equal to buffer and memoryOffset must be zero' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindBufferMemory)~^~
 VALIDATION_ERROR_02177~^~N~^~Unknown~^~vkBindBufferMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'If buffer was not created with VkDedicatedAllocationBufferCreateInfoNV::dedicatedAllocation equal to VK_TRUE, memory must not have been allocated dedicated for a specific buffer or image' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindBufferMemory)~^~
-VALIDATION_ERROR_02178~^~N~^~Unknown~^~vkBindImageMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'memoryOffset must be an integer multiple of the alignment member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with image' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindImageMemory)~^~
-VALIDATION_ERROR_02179~^~N~^~Unknown~^~vkBindImageMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'The size member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with image must be less than or equal to the size of memory minus memoryOffset' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindImageMemory)~^~
+VALIDATION_ERROR_02178~^~Y~^~BindInvalidMemory~^~vkBindImageMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'memoryOffset must be an integer multiple of the alignment member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with image' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindImageMemory)~^~
+VALIDATION_ERROR_02179~^~Y~^~BindInvalidMemory~^~vkBindImageMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'The size member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with image must be less than or equal to the size of memory minus memoryOffset' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindImageMemory)~^~
 VALIDATION_ERROR_02180~^~N~^~Unknown~^~vkBindImageMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'If image was created with VkDedicatedAllocationImageCreateInfoNV::dedicatedAllocation equal to VK_TRUE, memory must have been created with VkDedicatedAllocationMemoryAllocateInfoNV::image equal to image and memoryOffset must be zero' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindImageMemory)~^~
 VALIDATION_ERROR_02181~^~N~^~Unknown~^~vkBindImageMemory~^~For more information refer to Vulkan Spec Section '11.6. Resource Memory Association' which states 'If image was not created with VkDedicatedAllocationImageCreateInfoNV::dedicatedAllocation equal to VK_TRUE, memory must not have been allocated dedicated for a specific buffer or image' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkBindImageMemory)~^~
 VALIDATION_ERROR_02182~^~Y~^~None~^~vkCmdBlitImage~^~For more information refer to Vulkan Spec Section '18.5. Image Copies with Scaling' which states 'srcImage must have been created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT usage flag' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#vkCmdBlitImage)~^~
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index 3d8c0d0..0840cd2 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -2584,8 +2584,8 @@
     ASSERT_NO_FATAL_FAILURE(InitState());
 
     const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
-    const int32_t tex_width = 32;
-    const int32_t tex_height = 32;
+    const int32_t tex_width = 256;
+    const int32_t tex_height = 256;
 
     VkImageCreateInfo image_create_info = {};
     image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
@@ -2606,8 +2606,8 @@
     buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
     buffer_create_info.pNext = NULL;
     buffer_create_info.flags = 0;
-    buffer_create_info.size = tex_width;
-    buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+    buffer_create_info.size = 4 * 1024 * 1024;
+    buffer_create_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
     buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
     // Create an image/buffer, allocate memory, free it, and then try to bind it
@@ -2701,7 +2701,7 @@
         vkDestroyBuffer(device(), buffer, NULL);
     }
 
-    // Try to bind memory to an object with an out-of-range memoryOffset
+    // Try to bind memory to an object with an invalid memoryOffset
     {
         VkImage image = VK_NULL_HANDLE;
         err = vkCreateImage(device(), &image_create_info, NULL, &image);
@@ -2714,9 +2714,10 @@
         vkGetBufferMemoryRequirements(device(), buffer, &buffer_mem_reqs);
         VkMemoryAllocateInfo image_alloc_info = {}, buffer_alloc_info = {};
         image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
-        image_alloc_info.allocationSize = image_mem_reqs.size;
+        // Leave some extra space for alignment wiggle room
+        image_alloc_info.allocationSize = image_mem_reqs.size + image_mem_reqs.alignment;
         buffer_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
-        buffer_alloc_info.allocationSize = buffer_mem_reqs.size;
+        buffer_alloc_info.allocationSize = buffer_mem_reqs.size + buffer_mem_reqs.alignment;
         pass = m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0);
         ASSERT_TRUE(pass);
         pass = m_device->phy().set_memory_type(buffer_mem_reqs.memoryTypeBits, &buffer_alloc_info, 0);
@@ -2727,17 +2728,61 @@
         err = vkAllocateMemory(device(), &buffer_alloc_info, NULL, &buffer_mem);
         ASSERT_VK_SUCCESS(err);
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_00805);
-        VkDeviceSize image_offset = (image_mem_reqs.size + (image_mem_reqs.alignment - 1)) & ~(image_mem_reqs.alignment - 1);
-        err = vkBindImageMemory(device(), image, image_mem, image_offset);
-        (void)err;  // This may very well return an error.
-        m_errorMonitor->VerifyFound();
+        // Test unaligned memory offset
+        {
+            if (image_mem_reqs.alignment > 1) {
+                VkDeviceSize image_offset = 1;
+                m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_02178);
+                err = vkBindImageMemory(device(), image, image_mem, image_offset);
+                (void)err;  // This may very well return an error.
+                m_errorMonitor->VerifyFound();
+            }
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_00793);
-        VkDeviceSize buffer_offset = (buffer_mem_reqs.size + (buffer_mem_reqs.alignment - 1)) & ~(buffer_mem_reqs.alignment - 1);
-        err = vkBindBufferMemory(device(), buffer, buffer_mem, buffer_offset);
-        (void)err;  // This may very well return an error.
-        m_errorMonitor->VerifyFound();
+            if (buffer_mem_reqs.alignment > 1) {
+                VkDeviceSize buffer_offset = 1;
+                m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_02174);
+                err = vkBindBufferMemory(device(), buffer, buffer_mem, buffer_offset);
+                (void)err;  // This may very well return an error.
+                m_errorMonitor->VerifyFound();
+            }
+        }
+
+        // Test memory offsets outside the memory allocation
+        {
+            VkDeviceSize image_offset =
+                (image_alloc_info.allocationSize + image_mem_reqs.alignment) & ~(image_mem_reqs.alignment - 1);
+            m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_00805);
+            err = vkBindImageMemory(device(), image, image_mem, image_offset);
+            (void)err;  // This may very well return an error.
+            m_errorMonitor->VerifyFound();
+
+            VkDeviceSize buffer_offset =
+                (buffer_alloc_info.allocationSize + buffer_mem_reqs.alignment) & ~(buffer_mem_reqs.alignment - 1);
+            m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_00793);
+            err = vkBindBufferMemory(device(), buffer, buffer_mem, buffer_offset);
+            (void)err;  // This may very well return an error.
+            m_errorMonitor->VerifyFound();
+        }
+
+        // Test memory offsets within the memory allocation, but which leave too little memory for
+        // the resource.
+        {
+            VkDeviceSize image_offset = (image_mem_reqs.size - 1) & ~(image_mem_reqs.alignment - 1);
+            if (image_offset > 0) {
+                m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_02179);
+                err = vkBindImageMemory(device(), image, image_mem, image_offset);
+                (void)err;  // This may very well return an error.
+                m_errorMonitor->VerifyFound();
+            }
+
+            VkDeviceSize buffer_offset = (buffer_mem_reqs.size - 1) & ~(buffer_mem_reqs.alignment - 1);
+            if (buffer_offset > 0) {
+                m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_02175);
+                err = vkBindBufferMemory(device(), buffer, buffer_mem, buffer_offset);
+                (void)err;  // This may very well return an error.
+                m_errorMonitor->VerifyFound();
+            }
+        }
 
         vkFreeMemory(device(), image_mem, NULL);
         vkFreeMemory(device(), buffer_mem, NULL);