Alex Morson
Alex Morson

Reputation: 33

Minimal C++ OpenGL Segmentation Fault

I am following the first instalment in Tom Dalling's Modern OpenGL tutorial and when I downloaded his code it worked perfectly. So then I wanted to create my own minimal version to help me understand how it all worked.

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <GLM/glm.hpp>

#include <stdexcept>

GLFWwindow* gWindow = NULL;

GLint gProgram = 0;

GLuint gVertexShader = 0;
GLuint gFragmentShader = 0;

GLuint gVAO = 0;
GLuint gVBO = 0;

int main() {
    /** Initialise GLFW **/
    if (!glfwInit()){
        throw std::runtime_error("GLFW not initialised.");
    }
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    gWindow = glfwCreateWindow(800, 600, "OpenGL 3.2", NULL, NULL);
    if(!gWindow) {
        throw std::runtime_error("glfwCreateWindow failed.");
    }
    glfwMakeContextCurrent(gWindow);

    /** Initialise GLEW **/
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        throw std::runtime_error("Glew not initialised.");
    }
    if (!GLEW_VERSION_3_2) {
        throw std::runtime_error("OpenGL 3.2 not supported.");
    }

    /** Set up shaders **/
    gVertexShader = glCreateShader(GL_VERTEX_SHADER); //Segmentation fault here
    gFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

    glShaderSource(gVertexShader, 1, (const GLchar* const*)R"(
        #version 150

        in vec3 vertexPos

        out vec colour;

        void main() {
            colour = vertexPos;
            gl_Position = vec4(vertexPos, 1);
        }
        )", NULL);
    glShaderSource(gFragmentShader, 1, (const GLchar* const*)R"(
        #version 150

        in vec3 colour;

        out vec4 fragColour;

        void main() {
            fragColour = colour;
        }
        )", NULL);

    glCompileShader(gVertexShader);
    glCompileShader(gFragmentShader);

    /** Set up program **/
    gProgram = glCreateProgram();

    glAttachShader(gProgram, gVertexShader);
    glAttachShader(gProgram, gFragmentShader);

    glLinkProgram(gProgram);

    glDetachShader(gProgram, gVertexShader);
    glDetachShader(gProgram, gFragmentShader);

    glDeleteShader(gVertexShader);
    glDeleteShader(gFragmentShader);

    /** Set up VAO and VBO **/
    float vertexData[] = {
        // X,    Y,    Z
        0.2f, 0.2f, 0.0f,
        0.8f, 0.2f, 0.0f,
        0.5f, 0.8f, 0.0f,
    };

    glGenVertexArrays(1, &gVAO);
    glBindVertexArray(gVAO);

    glGenBuffers(1, &gVBO);
    glBindBuffer(GL_ARRAY_BUFFER, gVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GL_FLOAT)*9, vertexData, GL_STATIC_DRAW);

    glVertexAttribPointer(glGetAttribLocation(gProgram, "vertexPos"), 3, GL_FLOAT, GL_FALSE, 0, NULL);

    /** Main Loop **/
    while (!glfwWindowShouldClose(gWindow)) {
        glfwPollEvents();

        glBindBuffer(GL_ARRAY_BUFFER, gVBO);
        glDrawArrays(GL_TRIANGLES, 0, 1);
        glfwSwapBuffers(gWindow);
    }

    return 0;
}

This is what I created and it builds correctly. However when running it I get a segmentation fault upon calling glCreateShader.

I have done a lot of searching to find a solution to this and so far I've found two main reasons for this happening:

From here I have no clue as of what to do, so any tips would be a great help!

EDIT: Thank you all for your help! I eventually managed to get it working and have uploaded the code to pastebin for future reference.

Upvotes: 3

Views: 719

Answers (1)

Sergey
Sergey

Reputation: 8248

Problem solution

You program crashes not at the line you pointed, but on the first glShaderSource call. You actually pass a pointer to a string as the third argument, casting it to (const GLchar* const*). That's not what glShaderSource expects. It rather expects a pointer to an array of pointers to strings, whose (array of pointer's) length should be passed as the second argument (see documentation).

As a quick-n-dirty fix for your code, I declared the following:

const char *vs_source[] = {
        "#version 150\n",
        "in vec3 vertexPos\n",
        "out vec colour;\n",
        "void main() {\n",
        "    colour = vertexPos;\n",
        "    gl_Position = vec4(vertexPos, 1);\n",
        "}\n"};

const char *fs_source[] = {
        "#version 150\n",
        "in vec3 colour;\n",
        "out vec4 fragColour;\n",
        "void main() {\n",
        "    fragColour = colour;\n",
        "}\n"};

and replaced the calls to glShaderSource to

glShaderSource(gVertexShader, 7, (const char**)vs_source, NULL);
glShaderSource(gFragmentShader, 6, (const char**)fs_source, NULL);

Now the program works fine and shows a window as expected.

Hints

  • Your code did not even compile on my machine (I use gcc 4.8.3 @ Linux) because of cast of a string literal to (const GLchar* const*). So try to set more restrictive flags in your compiler options and pay attention at compiler warnings. Moreover, treat warnings as errors.

  • Use some kind of memory profiler to determine the exact location of crashes. For example, I used Valgrind to localize the problem.

Upvotes: 4

Related Questions