[SOLVED][EXCEPTION_ACCESS_VIOLATION] Input Handling

Started by ShadowDragon, November 29, 2018, 18:56:19

Previous topic - Next topic

ShadowDragon

Hi there,

I've got the following problem whenever I close my window:
Quote#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffaf48377d0, pid=8052, tid=13844
#
# JRE version: Java(TM) SE Runtime Environment (11.0.1+13) (build 11.0.1+13-LTS)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.0.1+13-LTS, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# C  [lwjgl.dll+0x177d0]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# D:\XXXX\Game\hs_err_pid8052.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
---------------  S U M M A R Y ------------

Command Line: -Dfile.encoding=UTF-8 test.game.HelloWorld
[...]

---------------  T H R E A D  ---------------

Current thread (0x0000019dee63d800):  JavaThread "main" [_thread_in_native, id=13844, stack(0x0000003edfc00000,0x0000003edfd00000)]

Stack: [0x0000003edfc00000,0x0000003edfd00000],  sp=0x0000003edfcff498,  free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [lwjgl.dll+0x177d0]

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  org.lwjgl.system.dyncall.DynCallback.ndcbGetUserData(J)J+0
j  org.lwjgl.system.dyncall.DynCallback.dcbGetUserData(J)J+12
org.lwjgl.system.Callback.free(J)V+1
j  org.lwjgl.glfw.Callbacks.glfwFreeCallbacks(J)V+165
test.game.HelloWorld.run()V+59
j  test.game.HelloWorld.main([Ljava/lang/String;)V+7
v  ~StubRoutines::call_stub

siginfo: EXCEPTION_ACCESS_VIOLATION (0xc0000005), reading address 0x0000019da5df0020

Minimal code example:
public class HelloWorld {

    // The window handle
    private long window;
    
    private InputHandler input;

    public void run() {
        System.out.println("Hello LWJGL " + Version.getVersion() + "!");

        init();
        this.input = new InputHandler();
        loop();

        this.input.dispose();
        // Free the window callbacks and destroy the window
        glfwFreeCallbacks(window);
        glfwDestroyWindow(window);

        // Terminate GLFW and free the error callback
        glfwTerminate();
        glfwSetErrorCallback(null).free();
    }

    private void init() {
        // Setup an error callback. The default implementation
        // will print the error message in System.err.
        GLFWErrorCallback.createPrint(System.err).set();

        // Initialize GLFW. Most GLFW functions will not work before doing this.
        if ( !glfwInit() )
            throw new IllegalStateException("Unable to initialize GLFW");

        // Configure GLFW
        glfwDefaultWindowHints(); // optional, the current window hints are already the default
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable

        // Create the window
        window = glfwCreateWindow(300, 300, "Hello World!", NULL, NULL);
        if ( window == NULL )
            throw new RuntimeException("Failed to create the GLFW window");

        // Setup a key callback. It will be called every time a key is pressed, repeated or released.
        glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
            if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
                glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
        });

        // Get the thread stack and push a new frame
        try ( MemoryStack stack = stackPush() ) {
            IntBuffer pWidth = stack.mallocInt(1); // int*
            IntBuffer pHeight = stack.mallocInt(1); // int*

            // Get the window size passed to glfwCreateWindow
            glfwGetWindowSize(window, pWidth, pHeight);

            // Get the resolution of the primary monitor
            GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());

            // Center the window
            glfwSetWindowPos(
                window,
                (vidmode.width() - pWidth.get(0)) / 2,
                (vidmode.height() - pHeight.get(0)) / 2
            );
        } // the stack frame is popped automatically

        // Make the OpenGL context current
        glfwMakeContextCurrent(window);
        // Enable v-sync
        glfwSwapInterval(1);

        // Make the window visible
        glfwShowWindow(window);
    }

    private void loop() {
        // This line is critical for LWJGL's interoperation with GLFW's
        // OpenGL context, or any context that is managed externally.
        // LWJGL detects the context that is current in the current thread,
        // creates the GLCapabilities instance and makes the OpenGL
        // bindings available for use.
        GL.createCapabilities();

        // Set the clear color
        glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

        // Run the rendering loop until the user has attempted to close
        // the window or has pressed the ESCAPE key.
        while ( !glfwWindowShouldClose(window) ) {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

            glfwSwapBuffers(window); // swap the color buffers

            // Poll for window events. The key callback above will only be
            // invoked during this call.
            this.input.update();
        }
    }

    public static void main(String[] args) {
        new HelloWorld().run();
    }
}

And the Input Handler itself:
public class InputHandler {
    
    private long window;
    private GLFWKeyCallback keyCallback;
    
    public InputHandler() {
        this.window = GLFW.glfwGetCurrentContext();
        this.initInputs();
    }
    
    private void initInputs() {
        glfwSetKeyCallback(this.window, this.keyCallback = GLFWKeyCallback.create((window, key, scancode, action, mods) -> {
            this.keyInput(key, action, mods);
        }));
    }
    
    public void update() {
        glfwPollEvents();
    }
    
    public void dispose() {
        this.keyCallback.free();
        this.keyCallback = null;
    }
	
    public void keyInput(int key, int action, int mods) {
		// TODO: ...
    }
}


Any ideas why I'm getting this crash? I'm also wondering how someone should read this hs_err_pid8052 file.. To me such a file looks like a lot of unreadable hex values (probaby memory addresses and their data???) printed out into a txt file. ^^

Thx in advance.
ShadowDragon

KaiHH

You dispose of the keycallback twice. Once in InputHandler.dispose() and then afterwards let LWJGL dispose of it again in HelloWorld.run() -> glfwFreeCallbacks, because LWJGL (or rather GLFW) does not know of your first disposal, since you did not clear/unregister the callback back in InputHandler.dispose().

ShadowDragon

Quote from: KaiHH on November 29, 2018, 19:10:04
You dispose of the keycallback twice. Once in InputHandler.dispose() and then afterwards let LWJGL dispose of it again in HelloWorld.run() -> glfwFreeCallbacks, because LWJGL (or rather GLFW) does not know of your first disposal, since you did not clear/unregister the callback back in InputHandler.dispose().
How would I let GLFW know that this callback has already been disposed?

KaiHH

For example by calling `glfwSetKeyCallback(window, null);` at the beginning of your InputHandler.dispose() - or just not doing anything in that method.