Jarrett
Jarrett

Reputation: 1778

segfault on glBufferData

I'm trying to port my fixed function pipeline openGL code to use GLSL, but I'm having a segfault happen with glBufferData. This was all working very well with the fixed-function stuff (i.e. I could render the loaded mesh no problem).

Here's the code that loads the vertices (from the AssImp importer library):

Defined in the Mesh.h file:

...
glm::detail::uint32 vaoId_[];
    glm::detail::uint32 vboIds_[];

    std::vector< glm::vec3 > vertices_;
    std::vector< glm::vec3 > normals_;
    std::vector< glm::vec2 > textureCoordinates_;
    std::vector< glm::vec4 > colors_;
...

implemented in Mesh.cpp:

...
Mesh::Mesh(const aiMesh* mesh) {
    vaoId_[1];
    vboIds_[4];

    BOOST_LOG_TRIVIAL(debug) << "loading mesh...";

    glm::detail::uint32 currentIndex = 0;

    for (glm::detail::uint32 t = 0; t < mesh->mNumFaces; ++t) {
        const aiFace* face = &mesh->mFaces[t];
        GLenum face_mode;

        switch(face->mNumIndices) {
            case 1: face_mode = GL_POINTS; break;
            case 2: face_mode = GL_LINES; break;
            case 3: face_mode = GL_TRIANGLES; break;
            default: face_mode = GL_POLYGON; break;
        }

        glm::detail::uint32 numIndices = face->mNumIndices;

        vertices_.resize( currentIndex + numIndices );
        normals_.resize( currentIndex + numIndices );
        textureCoordinates_.resize( currentIndex + numIndices );
        colors_.resize( currentIndex + numIndices );

        //BOOST_LOG_TRIVIAL(debug) << "loading face: " << face->mNumIndices;
        // go through all vertices in face
        for(glm::detail::uint32 i = 0; i < numIndices; i++) {
            // get group index for current index i
            int vertexIndex = face->mIndices[i];

            if (mesh->mNormals != 0) {
                vertices_[currentIndex + i]     = glm::vec3( mesh->mVertices[vertexIndex].x, mesh->mVertices[vertexIndex].y, mesh->mVertices[vertexIndex].z );
                normals_[currentIndex + i]      = glm::vec3( mesh->mNormals[vertexIndex].x, mesh->mNormals[vertexIndex].y, mesh->mNormals[vertexIndex].z );
            }

            if (mesh->HasTextureCoords(0)) {
                textureCoordinates_[currentIndex + i] = glm::vec2( mesh->mTextureCoords[0][vertexIndex].x, mesh->mTextureCoords[0][vertexIndex].y );
            }

            //utilities::AssImpUtilities::color4_to_vec4(&mesh->mColors[0][vertexIndex], colors_[colors_.size() + i]);
            if (mesh->mColors[0] != 0) {
                colors_[currentIndex + i]           = glm::vec4(
                                                        (float)mesh->mColors[0][vertexIndex].a,
                                                        (float)mesh->mColors[0][vertexIndex].b,
                                                        (float)mesh->mColors[0][vertexIndex].g,
                                                        (float)mesh->mColors[0][vertexIndex].r
                                                    );
            }           
        }

        currentIndex += 3;
    }

    BOOST_LOG_TRIVIAL(debug) << "loading mesh into video memory...";

    BOOST_LOG_TRIVIAL(debug) << "blah: " << vertices_.size();
    BOOST_LOG_TRIVIAL(debug) << "blah: " << ( sizeof(glm::vec3) );
    BOOST_LOG_TRIVIAL(debug) << "blah: " << ( &vertices_[0] );

    // create our vao
    glGenVertexArrays(1, &vaoId_[0]);
    glBindVertexArray(vaoId_[0]);

    // create our vbos
    //glGenBuffers(4, &vboIds_[0]);
    glGenBuffers(1, &vboIds_[0]); // Using only '1' for now (otherwise causes seg fault)
    glBindBuffer(GL_ARRAY_BUFFER, vboIds_[0]);
    glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(glm::vec3), &vertices_[0], GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    // Disable our Vertex Buffer Object
    glBindVertexArray(0);

    BOOST_LOG_TRIVIAL(debug) << "done loading mesh...";
}
...

I can't seem to figure out why opengl gives a segfault when I call glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(glm::vec3), &vertices_[0], GL_STATIC_DRAW);.

full error is (using gdb in linux):

Program received signal SIGSEGV, Segmentation fault. 0x00007fffefb1ae70 in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.304.64

Anyone have any ideas?

Upvotes: 1

Views: 1943

Answers (2)

Ben Voigt
Ben Voigt

Reputation: 283921

What is this at the top of your constructor?

vaoId_[1];
vboIds_[4];

It looks like your class contains arrays of size zero (that shouldn't even be allowed except as the very last data member, I have no clue how the compiler allowed you to have two of them) and you are writing beyond the boundaries of these arrays, which overwrites the next member (the metadata of the vertices_ vector). This is trashing either the size or data pointer portion of vertices_ and then you pass the trashed data to glBufferData with predictably bad consequences.

The clue was that glGenBuffers(4, &vboIds_[0]); also crashed your program. It's because you don't have any space named vboIds for OpenGL to store the results into.

Change

glm::detail::uint32 vaoId_[];
glm::detail::uint32 vboIds_[];

to actually have the correct dimensions. Arrays without dimensions require a lot of extra care, can only be done at the end of an object, and prevent subclassing. Avoid that if possible. Specify the dimensions or use a vector if the size is variable.

Upvotes: 2

Ben Voigt
Ben Voigt

Reputation: 283921

You need to call glBindBuffer before glBufferData.

Upvotes: 5

Related Questions