PDA

View Full Version : OpenGL 3.1 stack overflow



fiodis
11-29-2012, 11:02 AM
I recently made my own vertex class, vertexColored, to hold position and color data. I changed from passing a std::vector of glm::vec3 to my VBO, to passing a std::vector of vectorColored. The class is defined like this:

//vertexTypes.h
#ifndef VERTEXTYPES_H
#define VERTEXTYPES_H
#include <glm\glm.hpp>
class vertexColored
{
public:
vertexColored();
~vertexColored();
glm::vec3 vertexPos;
glm::vec4 vertexColor;
};
#endif // VERTEXTYPES_H

//vertexTypes.cpp
#include "vertexTypes.h"
vertexColored::vertexColored()
{
this->vertexPos = glm::vec3(0.0f, 0.0f, 0.0f);
this->vertexColor = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
}
vertexColored::~vertexColored()
{
}
And I have also brush.h:

//brush.h
#ifndef BRUSH_H
#define BRUSH_H
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <vector>
#include "vertexTypes.h"
class brush
{
public:
brush();
~brush();
void updateVertices();
void render();
void makeBuffers();
//other stuff...

private:
GLuint vboId, iboId;
std::vector<vertexColored> brushVecs;
std::vector<GLuint> brushIndices;
//other stuff...
};
#endif // BRUSH_H
And inside brush.cpp:

#include "brush.h"
brush::brush()
{
this->size = 2;
this->brushVecs.reserve(0);
this->brushIndices.reserve(0);
}
brush::~brush()
{
glDeleteBuffers(1, &(this->vboId));
glDeleteBuffers(1, &(this->iboId));
}

void brush::updateVertices(){
int numPoints = ((2 * this->size) + 1) * ((2 * this->size) + 1);
if (this->brushVecs.capacity() < numPoints)
{
this->brushVecs.reserve(numPoints);
}
vertexColored baseVertex;
this->brushVecs.resize(numPoints, baseVertex);
int curX = this->pos.x - this->size;
int index = 0;
while (curX <= this->pos.x + this->size){
int curZ = this->pos.z - this->size;
while (curZ <= this->pos.z + this->size){
this->brushVecs[index].vertexPos = glm::vec3((float)curX, 0.0f, (float)curZ);
this->brushVecs[index].vertexColor = glm::vec4(0.0f, 0.7f, 0.5f, 1.0f);
index++;
curZ++;
}
curX++;
}

if (this->brushIndices.capacity() < numPoints)
{
this->brushIndices.reserve(numPoints);
}
this->brushIndices.resize(numPoints, 0);
index = 0;
while (index < numPoints){
this->brushIndices[index] = index;
index++;
}
}

void brush::makeBuffers(){
glGenBuffers(1, &(this->vboId));
glBindBuffer(GL_ARRAY_BUFFER, this->vboId);
glBufferData(GL_ARRAY_BUFFER, this->brushVecs.size()*sizeof(vertexColored), &this->brushVecs[0], GL_DYNAMIC_DRAW);

glGenBuffers(1, &(this->iboId));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->iboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->brushIndices.size()*sizeof(GLuint), &this->brushIndices[0], GL_DYNAMIC_DRAW);
}

void brush::render(){
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glUseProgram(this->progId);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->iboId);
glBindBuffer(GL_ARRAY_BUFFER, this->vboId);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertexColored), (GLvoid*)0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(vertexColored), (GLvoid*)sizeof(glm::vec3));

glDrawElements(GL_POINTS, this->getNumPoints(), GL_UNSIGNED_INT, (GLvoid*)0);

glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(0);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
}
All this renders correctly - I don't detect any problems while the program's running. However, when I close the window (I'm using Qt for windowing), my IDE (Visual Studio 2010) stays in debugging mode for a few seconds. Then a popup shows up, saying:

Windows has triggered a breakpoint in qt_integration_test.exe.
This may be due to a corruption of the heap, which indicates a bug in qt_integration_test.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while qt_integration_test.exe has focus.
The output window may have more diagnostic information.
The output window contains multiple copies of the same message, all preceded by something like:

HEAP[qt_integration_test.exe]: Invalid address specified to RtlFreeHeap( 005F0000, 03CDF180 )
Or:

First-chance exception at 0x76f71bee in qt_integration_test.exe: 0xC0000005: Access violation reading location 0x07440018.
First-chance exception at 0x76f71bee in qt_integration_test.exe: 0xC0000005: Access violation reading location 0x07440018.
HEAP[qt_integration_test.exe]: HEAP: Free Heap block 745f840 modified at 745f854 after it was freed

I have no idea why these errors are arising. I googled heap corruption and found it could be a buffer overflow somewhere, but my buffers were fine back when I was passing a plain old vector of glm::vec3's - and I'm pretty sure I set the stride and everything right for my own custom class. And if it is the VBO or IBO overflowing, why didn't I get an error while running the program? Why only after I close it?

I tried defining a struct instead of a class in vertexTypes.h and got the same errors. At this point I'm lost. I'm not sure what could possibly be trying to access things in memory after the window closes. Has anyone experienced something similar, or have any idea why this is happening?

tonyo_au
11-29-2012, 11:29 PM
The error is probably being generated on a destructor call. This will be the first time the debugger can probably tell some correuption occured.
The usual cause is over running a buffer - typically an array of some sort - I would look hard at the code in updateVertices

fiodis
11-30-2012, 06:15 AM
I scrutinized my updateVertices code more closely but couldn't see anything that would be a problem - I reserve memory and resize the vectors properly, and the loop never iterates beyond the vector's capacity.

Then, on a hunch, I commented out the call to brush.render() in the actual OpenGL draw() loop. The brush doesn't render - naturally - but after I close the window, the IDE goes straight out of debugging mode, and no popup shows. :)

From that I conclude that there's something wrong with my rendering code, or maybe the makeBuffers() code. Trouble now is, I can't see what. It all looks valid to me. Maybe something's wrong with the glEnable- and glDisableVertexAttribArray calls? The code for getNumPoints, referenced in glDrawElements, is:

//brush.cpp
int brush::getNumPoints(){
return this->brushVecs.size();
}
which always worked for me before I used a custom class.

fiodis
12-02-2012, 10:50 AM
I've run a few more tests, and I've found this:
I get a heap corruption error on application closing even when I don't use a custom struct or class to represent a single vertex.

The problem only seems to arise when I'm passing a color as well as a position to the shader programs. So, for instance, if I just pass vertex position data, and in the fragment shader just set the color of every fragment to some constant, I get no error. But if I pass vertex position and color data, everything renders as it should - the vertices are the appropriate colors - but I get that heap corruption error when closing the window.

Is this thread in the right forum? I'm not sure if this is a beginner-level issue. :(

tonyo_au
12-02-2012, 04:41 PM
Is this thread in the right forum? I'm not sure if this is a beginner-level issue.
This forum is fine - your code is not "advanced" as far as OpenGL goes; also the OpenGL gurus tend to read both forums anyhow.

This looks more like a standard coding error - just a bit difficult to spot :(.
You could put some gGetlError calls in - they are always a good idea. Also post your shader in case it has something strange in there.

fiodis
12-03-2012, 09:27 AM
Here's the vertex shader:

#version 130

in vec4 in_Position;
in vec4 in_Color;
out vec4 ex_Color;

uniform mat4 MVPMatrix;

void main(void)
{
ex_Color = in_Color;
gl_PointSize = 8;
gl_Position = MVPMatrix * in_Position;
}
and the fragment shader:

#version 130

in vec4 ex_Color;
out vec4 out_Color;

void main(void)
{
out_Color = ex_Color;
}
Both pretty much as basic as it gets. And here's the code that actually loads the shaders:

//in brush.cpp:
void brush::loadShaders(const char * vertFile, const char * fragFile){
GLuint vsId = glCreateShader(GL_VERTEX_SHADER);
GLuint fsId = glCreateShader(GL_FRAGMENT_SHADER);

std::string vsCode;
std::ifstream vsCodeStream(vertFile, std::ios::in);
if (vsCodeStream.is_open())
{
std::string line = "";
while(std::getline(vsCodeStream, line))
vsCode += "\n" + line;
vsCodeStream.close();
}

std::string fsCode;
std::ifstream fsCodeStream(fragFile, std::ios::in);
if (fsCodeStream.is_open())
{
std::string line = "";
while(std::getline(fsCodeStream, line))
fsCode += "\n" + line;
fsCodeStream.close();
}

char const * vsSourcePtr = vsCode.c_str();
glShaderSource(vsId, 1, &vsSourcePtr, NULL);
glCompileShader(vsId);

char const * fsSourcePtr = fsCode.c_str();
glShaderSource(fsId, 1, &fsSourcePtr, NULL);
glCompileShader(fsId);

GLuint programId = glCreateProgram();
glAttachShader(programId, vsId);
glAttachShader(programId, fsId);
glBindAttribLocation(programId, 0, "in_Position");
glBindAttribLocation(programId, 1, "in_Color");

glLinkProgram(programId);

glDeleteShader(vsId);
glDeleteShader(fsId);

this->progId = programId;
}
As I mentioned, it works fine when I'm only passing vertex position data to the shader programs. When I pass vertex color data also (even using just float arrays, not any fancy custom structs or whatever) then everything renders correctly but I get that heap corruption when I close the window.

tonyo_au
12-03-2012, 09:30 PM
your in for position is

in vec4 in_Position;
but the size in the vertex structure is vec3 - this can't be good

V-man
12-04-2012, 06:29 AM
your in for position is

in vec4 in_Position;
but the size in the vertex structure is vec3 - this can't be good

It is good.
The W component is set to 1 automatically.

Dan Bartlett
12-04-2012, 06:29 AM
Having OpenGL calls in a destructor:

brush::~brush()
{
glDeleteBuffers(1, &(this->vboId));
glDeleteBuffers(1, &(this->iboId));
}
can sometimes cause problems depending on when the object is destroyed. The context could potentially have been destroyed already, there could be no context current, or a different context could be current to the one you expected. It may be better to have a brush::deleteBuffers() instead.

tonyo_au
12-04-2012, 04:44 PM
The W component is set to 1 automatically.
Is this true for any vec3 input?

fiodis
12-05-2012, 09:18 AM
Having OpenGL calls in a destructor:

brush::~brush()
{
glDeleteBuffers(1, &(this->vboId));
glDeleteBuffers(1, &(this->iboId));
}
can sometimes cause problems depending on when the object is destroyed. The context could potentially have been destroyed already, there could be no context current, or a different context could be current to the one you expected. It may be better to have a brush::deleteBuffers() instead.

It didn't seem to cause problems when I was only passing vertex position data, though. As soon as I pass vertex color data, either in the same VBO or in a seperate one, I get issues.

fiodis
12-05-2012, 01:20 PM
It turns out the gl calls in the destructor were, actually, the problem. Once I moved all the appropriate glDelete calls inside their own Cleanup() function, and called that at the right time, the issue was resolved. Thanks everyone. :)

And I'm not sure if every vec3 input is converted to a vec4 implicitly, but it seems like it would - after all, the shader doesn't know if the first vec3 you're passing to it is position or color data or something else.

tonyo_au
12-05-2012, 03:47 PM
It's good to hear your problem is resloved. I put a macro after every OpenGL call that resolves to a check on current context and OpenGL error check in debug mode and nothing in release. It makes the code run a bit slower but helps catch some of these things.

I am looking forward to the callback error code working the new drivers.