0

This is some of the strangest behavior I've ever seen and I have no answer from myself.

I tried -fno-delete-null-pointer-checks while compiling both my game and engine and still the same behavior was observed as follows:

So I'm working on a window manager to deal with multiple windows in an application and everything is working fine but when I delete a window and keep the app running still with the other window I receive "GLFW Error 65544, WGL: Failed to make context current: The handle is invalid." and "GLFW Error 65544, WGL: Failed to make context current: The requested transformation operation is not supported.". Ok so I thought maybe I'm still setting window context to the now deleted pointer so I log a check in the following for loop that tests if the window == NULL which I set it too after freeing the window:

void windowmanagerUpdate(WindowManager *manager)
{
    windowSystemPollEvents();

    for(int i = 0; i < array_length(manager->window_cache); i++)
    {
        Window *w = manager->window_cache[i].window;
        if(w)
        {
            //log_info("index: %i", i); - Check that stops error
            windowSetContextCurrent(w);
            windowUpdate(w);
        }
    }
}

After adding the one log to the statement just magically no more WGL errors, so what's going on this is so strange to me and as I said before explicitly telling gcc not to delete null pointer checks does not work either so maybe some people can shed some light on this issue.

Edit: sorry for not putting more info

So the Window type is just an abstracted window and under it is a WindowsWindow. windowSystemPollEvents just call glfwPollEvents(); windowSetContextCurrent(w) just calls glfwSetWindowCurrent(((WindowsWindow *)w)->native_window); windowUpdate(w) just calls glfwSwapBuffers(((WindowsWindow *)window)->native_window); and array_length just returns the length member of the dynamic array.

The manager is held in the applications data and doesn't change upon being created so it always points to the same address.

3
  • 1
    We need a bit more detail and shims around the isolated function so that it will compile in isolation and then use Godbolt to take a look at your MRE. My instinct is that for whatever reason the pointer for the deleted window entry for manager->window_cache[i].window is not actually null when if (w) executes. Does it fail if compiled in debug mode? Also try putting a log output in the else path. Commented Mar 3 at 10:11
  • 3
    Probably manager points at the wrong data when entering the function and/or array_length gives something out of bounds. And when you add an unrelated function call you scramble around the stack layout a bit so you hide the bug - you haven't fixed the bug. You'll need to carefully watch manager and every member of that one in your debugger. Because this bug really screams pointer to invalid data. Commented Mar 3 at 10:15
  • Please state which platform you are using and exactly with which command-line options you are compiling your program. In particular, are you compiling with optimizations active? Commented Mar 3 at 10:54

1 Answer 1

0

FINAL EDIT AND ANSWER I PROMISE: Im on my laptop so it was using my integrated intel driver and so I forced it to use my Nvidia GPU: __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; AMD: __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; And BOOM, all errors magically disappeared so theirs not much you can really do about it. Maybe theirs a driver to fix this but I could care less.

Still getting my understanding of pointers down and I thought that If you assign anything to a pointer it will change it everywhere but no not if you pass a pointer that is a local pointer then it acts like pass by value kind of (Horrible description)

Basically :

I changed my remove cached window to this when before the free and NULL set were happening in the window destroy which would pass the window * but would be local and only change in the context of the function

void windowmanagerRemoveCachedWindow(WindowManager *manager, const uint32_t index)
{
    log_info("Removing window at index %u from Window Manager", index);
    windowDestroy(manager->window_cache[index].window);
    array_append(manager->removed_indexes, index);
    free(manager->window_cache[index].window);
    manager->window_cache[index].window = NULL;
}
Sign up to request clarification or add additional context in comments.

4 Comments

"then it acts like pass by value kind of" That might be because in C all parameters are indeed passed by value.
Re "all parameters are indeed passed by value", Including pointers. This means that if you want to change a pointer in the caller, you will need to pass a pointer to that pointer (e.g. f( &ptr_to_change );) or return the new pointer.
C makes it look like arrays are passed by reference, but in fact it is pointers being passed by value. That's because it automatically adjusts the declarations of all parameters declared with array type to become the corresponding pointer to element types (so sizeof cannot be used to determine the length of the array, because it is not really an array), and also converts array arguments in function calls into pointer values. The pointer values are passed by value.
For some type T, you can declare a function parameter as a "double pointer" T **param, and have it modify the pointer value of type T * that is stored in *param. For example, you could declare your windowDestroy function as void windowDestroy(Window **pwindow) and call it as windowDestroy(&manager->window_cache[index].window);. The function can do Window *window = *pwindow; to get a copy of the Window * from the caller, and can set *pwindow = NULL; to change the caller's original Window * pointer to NULL.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.