Search code examples
cfree

Using free() corrupts char array data in C


The problem:

I need to malloc a struct to populate a char *[64] array. This array gets corrupted when I free the struct. Specifically the first index. How should I deal with this?

int main(void) {
char *names[64];
uint32_t aCount = 0;
uint32_t count = 0;
vkEnumerateInstanceExtensionProperties(NULL,&count, NULL);
VkExtensionProperties *extension_names = malloc(sizeof(VkExtensionProperties) * count);
vkEnumerateInstanceExtensionProperties(NULL,&count,extension_names);

for(uint32_t i = 0; i < count; i++) {
    names[aCount++] = extension_names[i].extensionName;
}

printf("First extension available: %s\n",names[0]);

free(extension_names);

printf("First extension available: %s\n",names[0]);
return 0;}

Here is the result:

Before free()

First extension available: VK_KHR_device_group_creation

After free()

First extension available: ���yUU


Solution

  • You can use strdup to make copies of the strings and solve the "use after free" problem you are having:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define UNUSED(x) \
        ((void)(x))
    
    #define VK_MAX_EXTENSION_NAME_SIZE 256
    
    typedef struct VkExtensionProperties {
        char        extensionName[VK_MAX_EXTENSION_NAME_SIZE];
        uint32_t    specVersion;
    } VkExtensionProperties;
    
    void vkEnumerateInstanceExtensionProperties(void *unused, 
            uint32_t *count, VkExtensionProperties *result) {
        UNUSED(unused);
        *count = 64;
        if (result) {
            for (int index = 0; index < *count; index++) {
                snprintf(result[index].extensionName, 
                        sizeof(result->extensionName), 
                        "extension%03d", 
                        index);
            }
        }
    }
    
    int main()
    {
        char *names[64];
        uint32_t aCount = 0;
        uint32_t count = 0;
        vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
        VkExtensionProperties *extension_names = malloc(sizeof(VkExtensionProperties) * count);
        vkEnumerateInstanceExtensionProperties(NULL, &count, extension_names);
    
        for (uint32_t i = 0; i < count; i++) {
            names[aCount++] = strdup(extension_names[i].extensionName);
        }
        printf("First extension available: %s\n", names[0]);
    
        free(extension_names);
    
        printf("First extension available: %s\n", names[0]);
    
        return 0;
    }
    

    Output

    First extension available: extension000
    First extension available: extension000
    

    I don't have Vulcan installed, so I simulated the behavior of the function you called.

    Helpful GCC Flags

    While I have your attention, don't forget to compile your code with -Wall -Werror to help you fix problems at compile time:

    $ gcc -Wall -Werror -o program program.c