Dav1dde / glad

Multi-Language Vulkan/GL/GLES/EGL/GLX/WGL Loader-Generator based on the official specs.
https://glad.dav1d.de/
Other
3.8k stars 450 forks source link

g++/gcc STATUS_ACCESS_VIOLATION on gladLoadGLLoader((GLADloadproc) glfwGetProcAddress) #124

Closed BtheDestroyer closed 6 years ago

BtheDestroyer commented 6 years ago

I've been writing a program that compiles with g++/gcc and temporarily switched over to Visual Studio for its debugger. I got OpenGL working perfectly with VS and then tried to compile the same code with g++/gcc and it crashed with the following stackdump:

Exception: STATUS_ACCESS_VIOLATION at eip=6116E7EE
eax=20057338 ebx=0063CC7C ecx=00000021 edx=61227D70 esi=00000021 edi=20057338
ebp=00000022 esp=0063CBC0 program=D:\3dshacking\BrewTools\Testing\Testingwin.exe, pid 17048, thread main
cs=0023 ds=002B es=002B fs=0053 gs=002B ss=002B
Stack trace:
Frame     Function  Args

I used gdb to find the line of the crash and it's when I call gladLoadGLLoader((GLADloadproc) glfwGetProcAddress):

gdb

To check if it was just my code I copied the c++ example from this repo over my main.cpp and it gave the same result. Anyone have any ideas?

Dav1dde commented 6 years ago

Works with VS but not mingw gcc/g++, or on Linux? Does it crash on that exact line or in the loader function (worst case add some printf's if the debugger doesn't show properly).

What are the exact commands you use to compile and can you paste a minimal example?

BtheDestroyer commented 6 years ago

I'll run some tests with gdb. For now, here's the lines I'm using to compile (I've shortened verbose folder names) main.cpp:

g++ -MMD -MP -MF build/Windows/main.d -g -D_WIN32 -Wall -Werror -Wextra -ansi -pedantic -c -Iinclude -Ilib/include -fno-rtti -fno-exceptions -std=gnu++11 -c source/main.cpp -o main.o

for glad.c I've tried

gcc -MMD -MP -MF build/Windows/glad.d -Iinclude -Ilib/include -Ibuild/Windows -g -D_WIN32 -c glad.c -o glad.o

and

g++ -x c -MMD -MP -MF build/Windows/glad.d -Iinclude -Ilib/include -Ibuild/Windows -g -D_WIN32 -c glad.c -o glad.o

Linking:

gcc-ar -rc lib/libglad.a glad.o
g++ main.o -Llib -lglad -lglfw3 -lopengl32 -lgdi32 -o Testingwin.exe

I'm manually defining _WIN32 because gcc and g++ weren't for some reason (I am indeed on Windows)

EDIT: File structure info: ./lib contiains libglfw3.a and libglad.a (made with gcc-ar) ./lib/include contains glad GLFW and KHR header folders ./build/Windows contains generated *.d dependency files

EDIT2: Here's the program that worked in VS but not with GNU:

#include <iostream>

// THIS IS OPTIONAL AND NOT REQUIRED, ONLY USE THIS IF YOU DON'T WANT GLAD TO INCLUDE windows.h
// GLAD will include windows.h for APIENTRY if it was not previously defined.
// Make sure you have the correct definition for APIENTRY for platforms which define _WIN32 but don't use __stdcall
#ifdef _WIN32
    #define APIENTRY __stdcall
#endif

// GLAD
#include <glad/glad.h>

// confirm that GLAD didn't include windows.h
#ifdef _WINDOWS_
    #error windows.h was included!
#endif

// GLFW
#include <GLFW/glfw3.h>

// This example is taken from http://learnopengl.com/
// http://learnopengl.com/code_viewer.php?code=getting-started/hellowindow2
// The code originally used GLEW, I replaced it with Glad

// Compile:
// g++ example/c++/hellowindow2.cpp -Ibuild/include build/src/glad.c -lglfw -ldl

// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);

// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;

// The MAIN function, from here we start the application and run the game loop
int main()
{
    std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
    // Init GLFW
    glfwInit();
    // Set all the required options for GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    // Create a GLFWwindow object that we can use for GLFW's functions
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", NULL, NULL);
    glfwMakeContextCurrent(window);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);

    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
    {
        std::cout << "Failed to initialize OpenGL context" << std::endl;
        return -1;
    }

    // Define the viewport dimensions
    glViewport(0, 0, WIDTH, HEIGHT);

    // Game loop
    while (!glfwWindowShouldClose(window))
    {
        // Check if any events have been activated (key pressed, mouse moved etc.) and call corresponding response functions
        glfwPollEvents();

        // Render
        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Swap the screen buffers
        glfwSwapBuffers(window);
    }

    // Terminates GLFW, clearing any resources allocated by GLFW.
    glfwTerminate();
    return 0;
}

// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    std::cout << key << std::endl;
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}
BtheDestroyer commented 6 years ago

So I just stepped through gladLoadGLLoader and then find_extensionsGL with gdb and here's what I found:

  1. get_exts() (called at glad.c:1040) checks if (max_loaded_major < 3) which returns false as max_loaded_major = 3
  2. num_exts_i is set to 231 by glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); (glad.c:160) so exts_i got set to (const char **) 0x2003f1b0 by (const char **)realloc((void *)exts_i, (size_t)num_exts_i * (sizeof *exts_i))
  3. glad.c:173 correctly mallocs local_str with a size of (len+1) * sizeof(*exts_i) bytes. On the first pass, this is strlen("GL_3DFX_texture_compression_FXT1") + 1 * sizeof(char*) or 132 bytes
  4. glad.c:178 crashes as strncpy attempts to copy the first 33 (len+1) bytes of gl_str_tmp which has a size of 32 bytes to local_str which has a size of 132 bytes causing it to crash on the last byte. EDIT: After reading a documentation page on strncpy, that's not what's happening

Currently messing around to see if I can find a solution

BtheDestroyer commented 6 years ago

It seems like there are even weirder things going on for some reason. I checked len when strncpy was being called and it had been changed to 1 at some point. See len's value at glad.c:173 compared to glad.c:174 weird len

Replacing the malloc(n) call at glad.c:173 with calloc(n,1) to initalize local_str to be filled with 0s and changing strncpy at glad:178 to strcpy caused the first pass to be successful, but the second pass resulted in gl_str_tmp being set to 0x70 for some reason, so I'm back to being lost

BtheDestroyer commented 6 years ago

I just tried using g++ source/main.cpp source/glad.c -Ilibs/include -o Test.exe -std=c++11 -Llibs -lglfw3 -lopengl32 -lgdi32 to compile with as little as possible and Test.exe still crashes. Either something's up with g++, glfw, or glad. I've already tried redownloading glfw and glad, so I'll see if I can update g++

BtheDestroyer commented 6 years ago

Turns out it was g++'s fault all along.

Note to anyone else with this problem: Make sure you're not using cygwin's g++. Compiling worked when I used mingw-g++ version: (MinGW.org GCC-6.3.0-1) 6.3.0 Compiling failed when I used cygwin's g++ version: (GCC) 5.4.0 AND (GCC) 6.4.0

Dav1dde commented 6 years ago

Thanks for looking into it.