Freeing const pointer after enabling extra extensions in Vulkan - c

I have just began learning the Vulkan API and as a challenge to myself I wanted to create a function that could enable any specific extensions. This function enables required instance extensions as well as any extensions the programmer asks for. The function works fine but with how the Vulkan implementation specifies that extensions are stored in VkInstanceCreateInfo as a const char* const* it seems that I have to allocate and free memory of a const pointer which I have been told is code smell. Found below are the EnableExtensions function as well as some code around the caller of this function, error checking omitted for brevity. Additionally, the code below is using some pseudo-interface which abstracts some of the Vulkan-ness away from the code.
int EnableExtensions(VkInstanceCreateInfo* createInfo, const char** extraExt, uint32_t numExtraExt)
{
uint32_t numRequired;
const char** required = getInstanceExtensions(&numRequired);
//the code smell I am talking about
const char** used = malloc(sizeof *used * (numRequired+numExtraExt);
for(uint32_t i = 0; i < numRequired; i++)
{
used[i] = required[i];
}
for(uint32_t i = 0; i < numExtraExt; i++)
{
used[numRequired + i] = extraExt[i];
}
populateCreateInfoStruct(createInfo, used, numRequired+numExtraExt);
return VK_SUCCESS;
}
In main.c
//Initalization code above
VkInstance instance;
VkApplicationInfo appInfo;
populateAppInfoStruct(&appInfo);
VkInstanceCreateInfo createInfo;
createInfo.pApplicationInfo = &appInfo;
const char* extra[4] = {"VK_EXT_one", "VK_EXT_two", "VK_EXT_three", "VK_EXT_four"};
EnableExtensions(&createInfo, extra, 4);
vkCreateInstance(&createInfo, NULL, &instance);
//Application code here
//I am worried about this
free((void*) createInfo.ppEnabledExtensionNames);
vkDestroyInstance(instance, NULL);
As you can see at the bottom of main.c I free the memory I allocated in EnableExtensions which I think I should do as to not cause a memory leak. However, if I remove the cast to void* then gcc complains. Is there any way around this issue or am I stuck doing something like this if I continue using C for this project?

Related

why simple Vulkan fails at vkCreateInstance()?

I'm trying to vulkanize my life. so I can use Vulkan compute. But creating a simple instance fails every way I tried.
Here is the code :
#include <vulkan/vulkan.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
VkApplicationInfo vkAppInfo;
vkAppInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
vkAppInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo vkCreateInfo;
vkCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
vkCreateInfo.pApplicationInfo = &vkAppInfo;
VkInstance instance = VK_NULL_HANDLE;
VkResult result = vkCreateInstance(&vkCreateInfo, NULL, &instance);
return -1;
if (result != VK_SUCCESS) {
return -2;
} else {
return -3;
}
return 0;
}
I tried Vulkan Tutorial (without the graphics function GLFW)
The problem here is that you assume the rest of the fields you do not fill out will be filled out somehow automatically with some valid data, but that is not the case. It will be filled with garbage. Don't forget this is a very general thing in C and C++: Every memory that is not explicitely initialized is just garbage.
I propose you write some wrapper functions for filling your Vulkan structs such as VkApplicationInfo. It could look like this:
VkApplicationInfo fill_app_info(const char* app_name, const char* app_version,
const char* engine_name, uint32_t engine_version,
uint32_t vk_api_version) {
VkApplicationInfo info;
info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
info.pNext = NULL;
info.pApplicationName = app_name;
info.applicationVersion = app_version;
info.pEngineName = engine_name;
info.engineVersion = engine_version;
info.apiVersion = vk_api_version;
return info;
}
This might seem not worth it for VkApplicationInfo, but there are Vulkan structures you will need more often.
Once you wrote the most verbose version of fill_app_info, you can use two powerful tools to make it even more easy for you: default parameters and overloading:
// This is even better: it has default parameters
VkApplicationInfo fill_app_info(const char* app_name, const char* app_version,
const char* engine_name = "MyEngine",
uint32_t engine_version = VK_MAKE_VERSION(1,0,0),
uint32_t vk_api_version = VK_API_VERSION_1_2) {
VkApplicationInfo info;
info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
info.pNext = NULL;
info.pApplicationName = app_name;
info.applicationVersion = app_version;
info.pEngineName = engine_name;
info.engineVersion = engine_version;
info.apiVersion = vk_api_version;
return info;
}
VkApplicationInfo fill_app_info(const char* app_name) {
// Call the other function
return fill_app_info(app_name, VK_MAKE_VERSION(1,0,0));
}
// Call function 1 with all parameters specified
VkApplicationInfo example1 = fill_app_info("MyApp", VK_MAKE_VERSION(1,0,0),
"MyCustomEngine1000", VK_MAKE_VERSION(1,0,6),
VK_API_VERSION_1_1);
// Call function 1 and use default parameters
VkApplicationInfo example2 = fill_app_info("MyApp", VK_MAKE_VERSION(1,0,0));
// Call function 2 and let it fill out everything but the app name
VkApplicationInfo example3 = fill_app_info("MyApp");
As you can see, example3 is created with only one argument specified. This makes your overall code much shorter if you create functions like this for all Vulkan structs. In Vulkan we often have the that we do need to fill out all members of the struct, even if some of the members are not really used. I would also suggest to enable validation layers to check if you use the API ccorrectly. Also, read the Vulkan docs. They tell you how to fill out every struct correctly: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkApplicationInfo.html

Issues using realloc (old size)

I'm trying to use realloc function in C, to dynamically operate on a char array of strings (char**).
I usually get a realloc():invalid old size error after 41st cicle of the for loop and I really can't understand why.
So, thanks to everyone who will help me ^-^
[EDIT] I'm trying to make the post more clear and following your advices, as a "new active member" of this community, so thank you all!
typedef struct _WordsOfInterest { // this is in an header file containing just
char **saved; // the struct and libraries
int index;
} wordsOfInterest;
int main() {
char *token1, *token2, *save1 = NULL, file[LEN], *temp, *word, **tokenArr;
int n=0, ch,ch2, flag=0, size, init=0,position,currEdit,init2=0,tempEdit,size_arr=LEN,
oldIndex=0,totalIndex=0,*editArr,counterTok=0;
wordsOfInterest toPrint;
char **final;
toPrint.index = 0;
toPrint.saved = malloc(sizeof(char*)*LEN);
editArr = malloc(sizeof(int)*LEN);
tokenArr = malloc(sizeof(char*)*LEN);
final = malloc(sizeof(char*)*1);
// external for loop
for(...) {
tokenArr[counterTok] = token1;
// internal while loop
while(...) {
// some code here surely not involved in the issue
} else {
if(init2 == 0) {
currEdit = config(token1,token2);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
init2 = 1;
} else {
if((abs((int)strlen(token1)-(int)strlen(token2)))<=currEdit) {
if((tempEdit = config(token1,token2)) == currEdit) {
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
if(toPrint.index == size_arr-1) {
size_arr = size_arr*2;
toPrint.saved = realloc(toPrint.saved, size_arr);
}
} else if((tempEdit = config(token1,token2))<currEdit) {
freeArr(toPrint, size_arr);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
currEdit = tempEdit;
}
}
}
flag = 0;
word = NULL;
temp = NULL;
freeArr(toPrint, size_arr);
}
}
editArr[counterTok] = currEdit;
init2 = 0;
totalIndex = totalIndex + toPrint.index + 1;
final = realloc(final, (sizeof(char*)*totalIndex));
uniteArr(toPrint, final, oldIndex);
oldIndex = toPrint.index;
freeArr(toPrint,size_arr);
fseek(fp2,0,SEEK_SET);
counterTok++;
}
You start with final uninitialized.
char **final;
change it to:
char **final = NULL;
Even if you are starting with no allocation, it needs a valid value (e.g. NULL) because if you don't initialize a local variable to NULL, it gets garbage, and realloc() will think it is reallocating a valid chunk of memory and will fail into Undefined Behaviour. This is probably your problem, but as you have eliminated a lot of code in between the declaration and the first usage of realloc, whe cannot guess what is happening here.
Anyway, if you have indeed initialized it, I cannot say, as you have hidden part of the code, unlistening the recommendation of How to create a Minimal, Reproducible Example
.
There are several reasons (mostly explained there) to provide a full but m inimal, out of the box, failing code. This allows us to test that code without having to provide (and probably solving, all or part) the neccesary code to make it run. If you only post a concept, you cannot expect from us complete, full running, and tested code, degrading strongly the quality of SO answers.
This means you have work to do before posting, not just eliminating what you think is not worth mentioning.
You need to build a sample that, with minimum code, shows the actual behaviour you see (a nonworking complete program) This means eliminating everything that is not related to the problem.
You need (and this is by far more important) to, before sending the code, to test it at your site, and see that it behaves as you see at home. There are many examples that, when eliminated the unrelated code, don't show the commented behaviour.
...and then, without touching anymore the code, send it as is. Many times we see code that has been touched before sending, and the problem dissapeared.
If we need to build a program, we will probably do it with many other mistakes, but not yours, and this desvirtuates the purpose of this forum.
Finally, sorry for the flame.... but it is necessary to make people read the rules.

Vulkan vkCreateInstance - Access violation writing location 0x0000000000000000

I am trying to write a basic program using Vulkan, but I keep getting a runtime error.
Exception thrown at 0x00007FFDC27A8DBE (vulkan-1.dll) in VulkanTest.exe: 0xC0000005: Access violation writing location 0x0000000000000000.
This seems to be a relatively common issue, resulting from a failure to initialize the arguments of the vkCreateInstance function. I have tried all of the solutions I found proposed to others, even initializing things I am fairly certain I don't need to, and I still haven't been able to solve the problem. The program is written in C using the MSVC compiler.
#include "stdio.h"
#include "SDL.h"
#include "vulkan\vulkan.h"
#include "System.h"
int main(int argc, char *argv[])
{
//Initialize SDL
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
printf("Error");
}
printf("Success");
//Initialize Vulkan
VkInstance VulkanInstance;
VkApplicationInfo VulkanApplicationInfo;
VulkanApplicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
VulkanApplicationInfo.pNext = 0;
VulkanApplicationInfo.pApplicationName = "VulkanTest";
VulkanApplicationInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
VulkanApplicationInfo.pEngineName = "VulkanTest";
VulkanApplicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
VulkanApplicationInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo VulkanCreateInfo = {0,0,0,0,0,0,0,0};
VulkanCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
VulkanCreateInfo.pNext = 0;
VulkanCreateInfo.pApplicationInfo = &VulkanApplicationInfo;
VulkanCreateInfo.enabledLayerCount = 1;
VulkanCreateInfo.ppEnabledLayerNames = "VK_LAYER_KHRONOS_validation";
vkEnumerateInstanceExtensionProperties(0, VulkanCreateInfo.enabledExtensionCount,
VulkanCreateInfo.ppEnabledExtensionNames);
//Create Vulkan Instance
if(vkCreateInstance(&VulkanCreateInfo, 0, &VulkanInstance) != VK_SUCCESS)
{
printf("Vulkan instance was not created");
}
//Create SDL Window
SDL_Window* window;
window = SDL_CreateWindow("VulkanTest", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 0, 0, SDL_WINDOW_VULKAN || SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_Delay(10000);
return 0;
}
Are you sure the call to vkCreateInstance() is what is crashing? I have not tried to debug the code you have shown (that is your job), but just looking at the calls that the code is making, it should be the call to vkEnumerateInstanceExtensionProperties() that is crashing (if it even compiles at all!).
The 2nd parameter of vkEnumerateInstanceExtensionProperties() expects a uint32_t* pointer, but you are passing in a uint32_t value (VulkanCreateInfo.enabledExtensionCount) that has been initialized to 0. So, that would make the pPropertyCount parameter be a NULL pointer (if it even compiles).
You are passing VulkanCreateInfo.ppEnabledExtensionNames in the 3rd parameter (if that even compiles), and ppEnabledExtensionNames has been initialized to NULL. Per the documentation for vkEnumerateInstanceExtensionProperties():
If pProperties is NULL, then the number of extensions properties available is returned in pPropertyCount. Otherwise, pPropertyCount must point to a variable set by the user to the number of elements in the pProperties array, and on return the variable is overwritten with the number of structures actually written to pProperties.
Since pPropertCount is NULL, vkEnumerateInstanceExtensionProperties() has nowhere to write the property count to! That would certainly cause an Access Violation trying to write to address 0x0000000000000000.
The documentation clears states:
pPropertyCount must be a valid pointer to a uint32_t value
On top of that, your call to vkEnumerateInstanceExtensionProperties() is just logically wrong anyway, because the 3rd parameter expects a pointer to an array of VkExtensionProperties structs, but VulkanCreateInfo.ppEnabledExtensionNames is a pointer to an array of const char* UTF-8 strings instead.
In other words, you should not be using vkEnumerateInstanceExtensionProperties() to initialize criteria for the call to vkCreateInstance(). You are completely misusing vkEnumerateInstanceExtensionProperties(). You probably meant to use SDL_Vulkan_GetInstanceExtensions() instead, eg:
uint32_t ExtensionCount = 0;
if (!SDL_Vulkan_GetInstanceExtensions(NULL, &ExtensionCount, NULL))
{
...
}
const char **ExtensionNames = (const char **) SDL_malloc(sizeof(const char *) * ExtensionCount);
if (!ExtensionNames)
{
...
}
if (!SDL_Vulkan_GetInstanceExtensions(NULL, &ExtensionCount, ExtensionNames))
{
SDL_free(ExtensionNames);
...
}
VulkanCreateInfo.enabledExtensionCount = ExtensionCount;
VulkanCreateInfo.ppEnabledExtensionNames = ExtensionNames;
if (vkCreateInstance(&VulkanCreateInfo, 0, &VulkanInstance) != VK_SUCCESS)
{
...
}
SDL_free(ExtensionNames);
...

Segmentation fault 11 in following code. How to avoid overflow?

void main(int argc, char* argv[]) {
char* hostname = (char*)malloc(sizeof(char)*1024);
hostname = getClientHostName("122.205.26.34");
printf("%s\n", hostname);
free(hostname);
}
char* getClientHostName(char* client_ip) {
char hostnames[5][2];
hostnames[0][0] = "122.205.26.34";
hostnames[0][1] = "aaaaa";
hostnames[1][0] = "120.205.36.30";
hostnames[1][1] = "bbbbb";
hostnames[2][0] = "120.205.16.36";
hostnames[2][1] = "ccccc";
hostnames[3][0] = "149.205.36.46";
hostnames[3][1] = "dddddd";
hostnames[4][0] = "169.205.36.33";
hostnames[4][1] = "eeeeee";
for(int i = 0; i<5; i++) {
if(!strcmp(hostnames[i][0], client_ip))
return (char*)hostnames[i][1];
}
return NULL;
}
Beginner in C.
I am not sure if there would be a better way to implement what I am trying to implement. The code is self-explanatory. Is there any way that I can predefine the size of hostname, using some general size of IP addresses, to avoid seg fault? Is there a even better way where I don't have to hardcode the size?
After fixing the compiler errors and warnings you get:
const char* getClientHostName(const char* client_ip) {
const char * hostnames[5][2];
hostnames[0][0] = "122.205.26.34";
hostnames[0][1] = "aaaaa";
hostnames[1][0] = "120.205.36.30";
hostnames[1][1] = "bbbbb";
hostnames[2][0] = "120.205.16.36";
hostnames[2][1] = "ccccc";
hostnames[3][0] = "149.205.36.46";
hostnames[3][1] = "dddddd";
hostnames[4][0] = "169.205.36.33";
hostnames[4][1] = "eeeeee";
for(int i = 0; i<5; i++) {
if(!strcmp(hostnames[i][0], client_ip))
return hostnames[i][1];
}
return NULL;
}
int main(int argc, char* argv[]) {
const char * hostname = getClientHostName("128.205.36.34");
printf("%s\n", hostname);
}
Is there a even better way where I don't have to hardcode the size?
Take the habit to compile with all warnings and debug info: gcc -Wall -Wextra -g with GCC. Improve the code to get no warnings at all.
If you want to get genuine IP addresses, this is operating system specific (since standard C11 don't know about IP addresses; check by reading n1570). On Linux you would use name service routines such as getaddrinfo(3) & getnameinfo(3) or the obsolete gethostbyname(3).
If this is just an exercise without actual relationship to TCP/IP sockets (see tcp(7), ip(7), socket(7)) you could store the table in some global array:
struct myipentry_st {
const char* myip_hostname;
const char* myip_address;
};
then define a global array containing them, with the convention of terminating it by some {NULL, NULL} entry:
const struct myipentry_st mytable[] = {
{"aaaaa", "122.205.26.34"},
{"bbbb", "120.205.36.30"},
/// etc
{NULL, NULL} // end marker
};
You'll better have a global or static variable (not an automatic one sitting on the call stack) because you don't want to fill it on every call to your getClientHostName.
Then your lookup routine (inefficient, since in linear time) would be:
const char* getClientHostName(char* client_ip) {
for (const struct myipentry_st* ent = mytable;
ent->myip_hostname != NULL;
ent++)
// the if below is the only statement of the body of `for` loop
if (!strcmp(ent->myip_address, client_ip))
return ent->myip_hostname;
// this happens after the `for` when nothing was found
return NULL;
}
You could even declare that table as a heap allocated pointer:
const struct myipentry_st**mytable;
then use calloc to allocate it and read its data from some text file.
Read the documentation of every standard or external function that you are using. Don't forget to check against failure (e.g. of calloc, like here). Avoid memory leaks by appropriate calls to free. Use the debugger gdb and valgrind. Beware of undefined behavior.
In the real world, you would have perhaps thousands of entries and you would perform the lookup many times (perhaps millions of times, e.g. once per every HTTP request in a web server or client). Then choose a better data structure (hash table or red-black tree perhaps). Read some Introduction to Algorithms.
Add * to type definition char * hostnames[5][2]. This must be array of pointers, not simple chars. Another necessary change is strcpy instead of = in strcpy( hostname, getClientHostName("122.205.26.34") );.
PS: Always try to compile with 0 compiler warnings, not only 0 errors!

Mysterious crash report - looks like a CPU bug

A user sent me a crash dump of my program, and I cannot understand how what I'm seeing is possible. It looks like one of the registers just changed it's value, without any visible reason. I don't have any explanation except for a CPU bug, but I'm very skeptical about that. Perhaps you can spot what's going on here.
Here's the code disassembly, as seen when opening the crash report (clickable):
Here's, roughly, how the C code looks:
void **pp = *g_some_global;
if(!pp)
return NULL;
int array_count = (int)pp[0];
void **array_ptr = (void **)pp[1];
for(i = 0; i < array_count; i++)
{
LONG_PTR *contents = array_ptr[i];
if(contents[4] == compare)
{
void **pp2 = (LONG_PTR *)contents[7]; // contents is different here! pp2 is NULL
int array_count2 = (int)pp2[0]; // the CRASH!
void **array_ptr2 = (void **)pp2[1];
// ...
}
}

Resources