Go Back   nV News Forums > Linux Support Forums > NVIDIA Linux

Newegg Daily Deals

Reply
 
Thread Tools
Old 07-08-09, 10:31 AM   #1
leonard2009
Registered User
 
Join Date: Dec 2008
Posts: 2
Question Memory leak in NVIDIA OpenGL Core library?

I am learning OpenGL and find there is a memory leak in the example program tess (http://www.opengl.org/resources/code/samples/redbook/tess.c). The problem lies in the callback function combineCallback, in which memory is allocated on the heap for new vertices generated during tessellation. But this memory is not released upon program exit. A simple solution is to keep track of the pointers for these dynamical memories and release them after tessellation (see my code below). I have tried this solution on three machines:
1, Windows Vista, Visual C++ 2008;
2, Linux CentOS 5.2, gcc 4.1.2, valgrind 3.4.1. x.org graphical driver (driver on installation DVD).
3, Linux CentOS 5.2, gcc 4.1.2, valgrind 3.4.1. NVIDIA graphical driver 185.18.14.
Memory leak is found on the third machine, but not on first two machines. Here is the output of valgrind on the third machine:
==3428== Memcheck, a memory error detector.
==3428== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==3428== Using LibVEX rev 1658, a library for dynamic binary translation.
==3428== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==3428== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==3428== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==3428== For more details, rerun with: -v
==3428==
==3428== Conditional jump or move depends on uninitialised value(s)
==3428== at 0x4CABD00: (within /usr/lib/libGLcore.so.185.18.14)
==3428==
==3428== Conditional jump or move depends on uninitialised value(s)
==3428== at 0x4CABD09: (within /usr/lib/libGLcore.so.185.18.14)
==3428==
==3428== Use of uninitialised value of size 4
==3428== at 0x4CABD12: (within /usr/lib/libGLcore.so.185.18.14)
0,0x5784e08
1,0x5785010
2,0x5785150
3,0x53d3a38
4,0x53d3d30
==3428==
==3428== ERROR SUMMARY: 29 errors from 3 contexts (suppressed: 37 from 2)
==3428== malloc/free: in use at exit: 316,719 bytes in 447 blocks.
==3428== malloc/free: 1,957 allocs, 1,510 frees, 2,631,386 bytes allocated.
==3428== For counts of detected errors, rerun with: -v
==3428== searching for pointers to 447 not-freed blocks.
==3428== checked 2,420,316 bytes.
==3428==
==3428== LEAK SUMMARY:
==3428== definitely lost: 152 bytes in 3 blocks.
==3428== possibly lost: 262,140 bytes in 1 blocks.
==3428== still reachable: 54,427 bytes in 443 blocks.
==3428== suppressed: 0 bytes in 0 blocks.
==3428== Use --leak-check=full to see details of leaked memory.

In short, valgrind finds something is wrong in /usr/lib/libGLcore.so.185.18.14, i.e. the NVIDIA OpenGL core library. Interestingly, no memory leak is found on another Linux machine that differs only in graphical driver and OpenGL libraries. I am not sure if the memory leak results from /usr/lib/libGLcore.so.185.18.14 and appreciate your opinions.

Here is my code to fix the memory leak based on the original tess.c code:
#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>

// For memory leak detection in Windows/VC++
#ifdef WIN32
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif

// For memory leak detection in Linux with mtrace
#ifdef USEMTRACE
#include <mcheck.h>
#endif

// MACRO for comparison between original version and leak-free version.
#define NOMEMLEAK

#ifndef CALLBACK
#define CALLBACK
#endif

// Global variables to keep dynamic-allocated memory for new vertices
// during tessellation.
GLdouble** newVertices;
int newVertexCount = 0;
int vertexCapacity = 128;

GLuint startList;

void display (void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glCallList(startList);
glCallList(startList + 1);
glFlush();
}

void CALLBACK beginCallback(GLenum which)
{
glBegin(which);
}

void CALLBACK errorCallback(GLenum errorCode)
{
const GLubyte *estring;

estring = gluErrorString(errorCode);
fprintf(stderr, "Tessellation Error: %s\n", estring);
exit(0);
}

void CALLBACK endCallback(void)
{
glEnd();
}

void CALLBACK vertexCallback(GLvoid *vertex)
{
const GLdouble *pointer;

pointer = (GLdouble *) vertex;
glColor3dv(pointer+3);
glVertex3dv(vertex);
}

/* combineCallback is used to create a new vertex when edges
* intersect. coordinate location is trivial to calculate,
* but weight[4] may be used to average color, normal, or texture
* coordinate data. In this program, color is weighted.
*/
void CALLBACK combineCallback(GLdouble coords[3],
GLdouble *vertex_data[4],
GLfloat weight[4], GLdouble **dataOut )
{
GLdouble *vertex;
int i;

vertex = (GLdouble *) malloc(6*sizeof(GLdouble));

vertex[0] = coords[0];
vertex[1] = coords[1];
vertex[2] = coords[2];
for (i = 3; i < 6; i++)
vertex[i] = weight[0] * vertex_data[0][i]
+ weight[1] * vertex_data[1][i]
+ weight[2] * vertex_data[2][i]
+ weight[3] * vertex_data[3][i];
*dataOut = vertex;

// Save the pointer for memory release later
newVertices[newVertexCount++] = vertex;
// double the capacity when necessary.
if ( newVertexCount >= vertexCapacity ) {
vertexCapacity <<= 1;
newVertices = (GLdouble **)realloc(newVertices, vertexCapacity);
}
}

void init (void)
{
GLUtesselator *tobj;
GLdouble rect[4][3] = {50.0, 50.0, 0.0,
200.0, 50.0, 0.0,
200.0, 200.0, 0.0,
50.0, 200.0, 0.0};
GLdouble tri[3][3] = {75.0, 75.0, 0.0,
125.0, 175.0, 0.0,
175.0, 75.0, 0.0};
GLdouble star[5][6] = {250.0, 50.0, 0.0, 1.0, 0.0, 1.0,
325.0, 200.0, 0.0, 1.0, 1.0, 0.0,
400.0, 50.0, 0.0, 0.0, 1.0, 1.0,
250.0, 150.0, 0.0, 1.0, 0.0, 0.0,
400.0, 150.0, 0.0, 0.0, 1.0, 0.0};

glClearColor(0.0, 0.0, 0.0, 0.0);

startList = glGenLists(2);

tobj = gluNewTess();
gluTessCallback(tobj, GLU_TESS_VERTEX, glVertex3dv);
gluTessCallback(tobj, GLU_TESS_BEGIN, beginCallback);
gluTessCallback(tobj, GLU_TESS_END, endCallback);
gluTessCallback(tobj, GLU_TESS_ERROR, errorCallback);

/* rectangle with triangular hole inside */
glNewList(startList, GL_COMPILE);
glShadeModel(GL_FLAT);
gluTessBeginPolygon(tobj, NULL);
gluTessBeginContour(tobj);
gluTessVertex(tobj, rect[0], rect[0]);
gluTessVertex(tobj, rect[1], rect[1]);
gluTessVertex(tobj, rect[2], rect[2]);
gluTessVertex(tobj, rect[3], rect[3]);
gluTessEndContour(tobj);
gluTessBeginContour(tobj);
gluTessVertex(tobj, tri[0], tri[0]);
gluTessVertex(tobj, tri[1], tri[1]);
gluTessVertex(tobj, tri[2], tri[2]);
gluTessEndContour(tobj);
gluTessEndPolygon(tobj);
glEndList();

gluTessCallback(tobj, GLU_TESS_VERTEX, vertexCallback);
gluTessCallback(tobj, GLU_TESS_BEGIN, beginCallback);
gluTessCallback(tobj, GLU_TESS_END, endCallback);
gluTessCallback(tobj, GLU_TESS_ERROR, errorCallback);
gluTessCallback(tobj, GLU_TESS_COMBINE, combineCallback);

/* smooth shaded, self-intersecting star */
glNewList(startList + 1, GL_COMPILE);
glShadeModel(GL_SMOOTH);
gluTessProperty(tobj, GLU_TESS_WINDING_RULE,
GLU_TESS_WINDING_POSITIVE);
gluTessBeginPolygon(tobj, NULL);
gluTessBeginContour(tobj);
gluTessVertex(tobj, star[0], star[0]);
gluTessVertex(tobj, star[1], star[1]);
gluTessVertex(tobj, star[2], star[2]);
gluTessVertex(tobj, star[3], star[3]);
gluTessVertex(tobj, star[4], star[4]);
gluTessEndContour(tobj);
gluTessEndPolygon(tobj);
glEndList();
gluDeleteTess(tobj);

// Release the memory allocated for new vertices during tessellation.
#ifdef NOMEMLEAK
int i;
for ( i = 0; i < newVertexCount; i++ ) {
printf("%d,0x%x\n", i, newVertices[i]);
free(newVertices[i]);
}
#endif
free(newVertices);
}

void reshape (int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);
}

void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27: {
exit(0);
break;
}
}
}

int main(int argc, char** argv)
{
#ifdef WIN32
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

#ifdef USEMTRACE
mtrace();
#endif

newVertices = (GLdouble **)malloc(vertexCapacity*sizeof(GLdouble*));
if ( !newVertices )
exit(-1);

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();

return 0;
}
leonard2009 is offline   Reply With Quote
Reply


Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT -5. The time now is 07:45 AM.


Powered by vBulletin® Version 3.7.1
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Copyright 1998 - 2014, nV News.