On MacOS, the following code will cause a segfault when the user quits the application using command+Q:
using Glfw;
// ...
public static void Main()
{
using var window = new NativeWindow(1920, 1080, "My App");
while (!window.IsClosed)
{
Glfw.PollEvents();
}
Console.WriteLine("Goodbye!");
}
The access violation happens after the NativeWindow.Closed event is finished dispatching, where the window close request callback returns control back to GLFW. Looking into the implementation of the protected NativeWindow.OnClosing handler, this seems to happen because underlying window is destroyed in the middle of the callback (see this line, which is responsible for destroying the window handle). This is illegal, with the GLFW reference documentation for glfwDestroyWindow stating that:
Reentrancy
This function must not be called from a callback.
This is a logical error, not an error in C#'s FFI. Here is the equivalent C code which exhibits the same faulty behavior:
#include <stdio.h>
#include <GLFW/glfw3.h>
static void onClosing(GLFWwindow* window)
{
printf("Destroying %p\n", window);
// ...
glfwDestroyWindow(window);
}
int main(void)
{
// Setup GLFW
if (!glfwInit())
return -1;
// Setup window
GLFWwindow* window = glfwCreateWindow(1920, 1080, "My App", NULL, NULL);
if (!window)
goto stop;
glfwSetWindowCloseCallback(window, onClosing);
// Main loop
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
// Cleanup
puts("Goodbye!");
stop:
glfwTerminate();
return 0;
}
There's no easy way to fix this without changing the API. A non-breaking (but potentially confusing) fix could be to invisibly handle window destruction at the end of the Glfw.PollEvents method call by destroying all windows that still have the shouldClose flag, but that breaks the user expectation that the Glfw class is just raw FFI. A better (but breaking) approach would be to introduce a dedicated wrapper around Glfw.PollEvents that "handles higher-level behavior for the GLFW-NET-specific wrapper objects" i.e. implements the behavior of the previous proposal but in a different method.
On MacOS, the following code will cause a
segfaultwhen the user quits the application usingcommand+Q:The access violation happens after the
NativeWindow.Closedevent is finished dispatching, where the window close request callback returns control back to GLFW. Looking into the implementation of theprotected NativeWindow.OnClosinghandler, this seems to happen because underlying window is destroyed in the middle of the callback (see this line, which is responsible for destroying the window handle). This is illegal, with the GLFW reference documentation forglfwDestroyWindowstating that:This is a logical error, not an error in C#'s FFI. Here is the equivalent C code which exhibits the same faulty behavior:
There's no easy way to fix this without changing the API. A non-breaking (but potentially confusing) fix could be to invisibly handle window destruction at the end of the
Glfw.PollEventsmethod call by destroying all windows that still have theshouldCloseflag, but that breaks the user expectation that theGlfwclass is just raw FFI. A better (but breaking) approach would be to introduce a dedicated wrapper aroundGlfw.PollEventsthat "handles higher-level behavior for the GLFW-NET-specific wrapper objects" i.e. implements the behavior of the previous proposal but in a different method.