c++ – VkSurfaceKHR pointer's value changes after a function call without any explicit assignments-ThrowExceptions

Exception or error:

This is the abridged error message from Vulkan’s validation layers

Invalid VkSurfaceKHR Object 0x1000000002.
Objects: 1
        [0] 0x1000000002, type: 1000000000, name: NULL

thrown by this function

populateQueueFamilies(&physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, &surface);

Now this shouldn’t happen because

populatePhysicalDevice(&instance, &physicalDevice, &surface);
populateQueueFamilies(&physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, &surface);

the function before it also uses surface variable and doesn’t throw any errors!

I wroth some print functions to see if there’s something wrong with the variable and voila


  printf("%p\n", surface); // prints - 0x10000000001

  populatePhysicalDevice(&instance, &physicalDevice, &surface);

  printf("%p\n", surface); // prints - 0x10000000002

  populateQueueFamilies(&physicalDevice, &queueFamilyIndicesList, &queueFamilyCount, &surface);

I understand these sorts of problems happen when you assign to the pointer a local variable’s address.

But I don’t think that’s what’s going on here because the only function that touches surface var inside populateQueueFamilies is this one:

void populateSwapchainSupportDetails(SwapchainSupportDetails* gSwapchainSupportDetails,
                                     VkPhysicalDevice*        gPhysicalDevice,
                                     VkSurfaceKHR*            gSurface)
{

  VkSurfaceCapabilitiesKHR lCapabilities;
  uint32_t                 formatCount;
  uint32_t                 presentModeCount;

  vkGetPhysicalDeviceSurfaceCapabilitiesKHR(*gPhysicalDevice, *gSurface, &lCapabilities);

  uint32_t gFormatCount;
  vkGetPhysicalDeviceSurfaceFormatsKHR(*gPhysicalDevice, *gSurface, &gFormatCount, VK_NULL_HANDLE);

  VkSurfaceFormatKHR lFormats[gFormatCount];
  if (gFormatCount != 0)
    {
      vkGetPhysicalDeviceSurfaceFormatsKHR(*gPhysicalDevice, *gSurface, &gFormatCount, lFormats);
    }

  uint32_t gPresentModeCount;

  vkGetPhysicalDeviceSurfacePresentModesKHR(*gPhysicalDevice, *gSurface, &gPresentModeCount, VK_NULL_HANDLE);

  VkPresentModeKHR lPresentModes[gPresentModeCount];
  if (gPresentModeCount != 0)
    {
      vkGetPhysicalDeviceSurfacePresentModesKHR(
          *gPhysicalDevice, *gSurface, &gPresentModeCount, lPresentModes);
    }

  gSwapchainSupportDetails->capabilities     = lCapabilities;
  gSwapchainSupportDetails->formatCount      = gFormatCount;
  gSwapchainSupportDetails->presentModeCount = gPresentModeCount;

  gSwapchainSupportDetails->formats = malloc(sizeof(lFormats));
  memcpy(gSwapchainSupportDetails->formats, lFormats, sizeof(lFormats));

  gSwapchainSupportDetails->formats = malloc(sizeof(lPresentModes));
  memcpy(gSwapchainSupportDetails->formats, lPresentModes, sizeof(lPresentModes));

There’s a temporary fix that works tho:

VkSurfaceKHR surface1 = surface;
VkSurfaceKHR surface2 = surface;

and passing each surface(number) to different functions.

How to solve:

Oh boy was this an interesting journey that ended up in me being completely blown away by; to put it lightly – lack of genius.

After looking for a while, trying to debug stuff I ended up finding a really really stupid mistake that was causing all sorts of problems.

I got to it by using valgrind.

I ran it using this command

valgrind\
       --leak-check=full\
       --leak-resolution=high\
       --show-leak-kinds=all\
       --xtree-leak=yes\
       --track-origins=yes\
       --show-mismatched-frees=yes\

It gave me lots of messages, here’s an abridged version of them

Invalid write of size 8
    at <someaddress>: populateQueueFamilies ()
...
...
Invalid write of size 8
    at <someaddress>: populateQueueFamilies ()
...
...
Invalid write of size 8
    at <someaddress>: populateQueueFamilies ()
...
...

Invalid write means I’m writing into invalid memory location.
Some googling tells me that error message almost always occures due to wrong usage of malloc.

This was my populateQueueFamilies function

void populateQueueFamilies(const VkPhysicalDevice* gPhysicalDevice,
                           const VkSurfaceKHR*     surface,
                           uint32_t*               gQueueFamilyCount,
                           QueueFamilyIndices**    gQueueFamilyIndicesList)
{

  uint32_t lQueueFamilyCount;
  vkGetPhysicalDeviceQueueFamilyProperties(*gPhysicalDevice, &lQueueFamilyCount, VK_NULL_HANDLE);

  VkQueueFamilyProperties lQueueFamilies[lQueueFamilyCount];
  vkGetPhysicalDeviceQueueFamilyProperties(*gPhysicalDevice, &lQueueFamilyCount, lQueueFamilies);

  VkBool32 presentFamilySupported;

  (*gQueueFamilyIndicesList) = malloc(sizeof(*lQueueFamilies) * lQueueFamilyCount);

  for (int i = 0; i < lQueueFamilyCount; ++i)
    {
      QueueFamilyIndices gQueueFamilyIndices;

      populateQueueFamilyQueueIndices(lQueueFamilies[i], i, &gQueueFamilyIndices);

      presentFamilySupported = false;
      vkGetPhysicalDeviceSurfaceSupportKHR(*gPhysicalDevice, i, *surface, &presentFamilySupported);

      gQueueFamilyIndices.presentFamilySupportQueueIndex = presentFamilySupported ? i : -1;

      (*gQueueFamilyIndicesList)[i] = gQueueFamilyIndices;
    }

  *gQueueFamilyCount = lQueueFamilyCount;
}

There that line

(*gQueueFamilyIndicesList) = malloc(sizeof(*lQueueFamilies) * lQueueFamilyCount);

In my mind I was thinking, “yes, I need size to store information from this lQueueFamilies array” and I allocated memory to store information from *lQueueFamilies times the count.

BUT that’s wrong!

What I needed was

(*gQueueFamilyIndicesList) = malloc(sizeof(QueueFamilyIndices) * lQueueFamilyCount);

because I needed gQueueFamilyIndicesList to store a specific information from VkQueueFamilyProperties and not the struct itself.

I don’t know how I missed it. Thanks to @krOoze for suggesting using const and @solidpixel to suggest that this might be corrupted memory corruption, which it was.

Leave a Reply

Your email address will not be published. Required fields are marked *