2012-10-31 19 views
5

Ho una libreria di base che uso per dipingere il testo OpenGL e quando mai uso valgrind per assicurarmi che sia a tenuta d'aria. Continuo a ricevere un errore insolito che mi sembra come se le librerie di Linux cux fossero difettose. Mi piacerebbe vedere se voi ragazzi potete individuare il mio errore o autenticare ciò che temo, e cioè che le mie librerie C++ sono difettose e devono essere sostituite. Il codice è molto semplice ma usa sia OpenGL che FreeImage, quindi alcune linee non hanno senso.Che cosa significa questo errore valgrind?

Ecco fontsystem.h:

#ifndef FONTSYSTEM_H 
#define FONTSYSTEM_H 

/* 
    The Font System works by loading all the font images (max image size 32px^2) into memory and storing 
    the OpenGL texture ID's into an array that can be access at all times. The DrawString() functions will 
    search through the string for the specified character requested to draw and then it will draw a quad 
    and paint the texture on it. Since all the images are pre-loaded, no loading of the images at load time 
    is necessary, this is memory consuming but efficiant for the CPU. ALL functions WILL return a character 
    string specifing errors or success. A function will work as long as it can and when an error happens, 
    unless the error is fatal, the functions will NOT rollback changes! This ensures that during testing, a 
    very certain bug can be spotted. 
*/ 

#include <cstdio> 
#include <cstdlib> 
#include <iostream> 
#include <string.h> 
#include <assert.h> 
#include <GL/gl.h> 
#include <GL/glu.h> 
#include <GL/glext.h> 
#include <FreeImage.h> 

#define REPORT(x) (std::cout<<x) 
#define TIME clock() 

class CFont 
{ 
public: 
    CFont(); 
    ~CFont(); 

    void DrawString(char *apString, int aiLetterSize, int aiX, int aiY); 
    void DrawString(long anNumber, int aiLetterSize, int aiX, int aiY); 
    void SetPath(char avPath[]); 
    void SetupFont(); // This function will load as many images as possible into memory. 

private: 
    GLuint *mpTextIDs; 
    int *mpDrawIDs; 
    char *mpPath; 

public: 
    CFont(const CFont& a): 
     mpTextIDs(a.mpTextIDs), 
     mpDrawIDs(a.mpDrawIDs), 
     mpPath(a.mpPath) 
    { 
     std::copy(a.mpTextIDs, a.mpTextIDs+128, mpTextIDs); 
     std::copy(a.mpDrawIDs, a.mpDrawIDs+128, mpDrawIDs); 
     std::copy(a.mpPath, a.mpPath + strlen(a.mpPath), mpPath); 
    } 

    CFont& operator=(const CFont& a) 
    { 
     GLuint *iTmpTex = new GLuint[128]; 
     int *iTmpDraw = new int[1024]; 
     char *vTmpPath = new char[4096]; 

     delete[] mpTextIDs; 
     delete[] mpDrawIDs; 
     delete[] mpPath; 

     std::copy(a.mpTextIDs, a.mpTextIDs+128, iTmpTex); 
     std::copy(a.mpDrawIDs, a.mpDrawIDs+128, iTmpDraw); 
     std::copy(a.mpPath, a.mpPath + strlen(a.mpPath), vTmpPath); 

     mpTextIDs = iTmpTex; 
     mpDrawIDs = iTmpDraw; 
     mpPath = vTmpPath; 

     return *this; 
    } 
}; 

#endif // FONTSYSTEM_H 

qui è fontsystem.cpp:

#include "fontsystem.h" 

CFont::CFont() 
{ 
    mpTextIDs = new GLuint[128]; 
    mpDrawIDs = new int[1024]; 
    mpPath = new char[4096]; 
} 

CFont::~CFont() 
{ 
    delete[] mpTextIDs; 
    delete[] mpDrawIDs; 
    delete[] mpPath; 
} 

void CFont::DrawString(char *apString, int aiLetterSize, int aiX, int aiY) 
{ 
    // Sanity check! 
    if(apString == NULL) 
    { 
     REPORT("{Gfx}["<< TIME<< "]Error: Drawing string is NULL! <Font System>\n"); 
     return; 
    } 

    if(aiLetterSize <= 0) 
    { 
     REPORT("{Gfx}["<< TIME<< "]Error: Letter size is less than zero! <Font System>\n"); 
     return; 
    } 

    // Search the string from most significant character to least significant. 
    int iSelectIndex = 0; 
    int iNumOfSymb = 0; 
    for(size_t i = 0; apString[i] != '\0'; ++i) 
    { 
     iSelectIndex = apString[i] >= '0' && apString[i] <= '9' ? (apString[i] - '0') : 
         apString[i] >= 'A' && apString[i] <= 'Z' ? (apString[i] - 'A' + 10) : 
         apString[i] >= 'a' && apString[i] <= 'z' ? (apString[i] - 'a' + 10) : 
         apString[i] == ' ' ? 36 : // This is a special case, This see's if the current character is a space or not. 
         -1; 

     if(iSelectIndex == -1) 
     { 
      return; 
     } 

     // Add the current selected character to the drawing array. 
     mpDrawIDs[i] = iSelectIndex; 
     ++iNumOfSymb; 
    } 

    // Go through and draw each and every character. 
    for(size_t i = 0; apString[i] != '\0'/*static_cast<size_t>(iNumOfSymb)*/; ++i) 
    { 
     // Paint each qaud with the X,Y coordinates. After each quad has been successfully drawn, 
     // Add the size to the X coordinate. NOTE: Each character is square!!! 

     glBindTexture(GL_TEXTURE_2D, mpTextIDs[(uint)apString[i]]); 

     int yPos = apString[i] != 'q' || apString[i] != 'j' || apString[i] != 'y' ? aiY : aiY + (aiLetterSize/2); 

     glBegin(GL_QUADS); 
      glTexCoord2d(0, 0); 
      glVertex2d(aiX, yPos); 

      glTexCoord2d(1, 0); 
      glVertex2d(aiX + aiLetterSize, yPos); 

      glTexCoord2d(1, 1); 
      glVertex2d(aiX + aiLetterSize, yPos + aiLetterSize); 

      glTexCoord2d(0, 1); 
      glVertex2d(aiX, yPos + aiLetterSize); 
     glEnd(); 

     // Now, increase the X position by the size. 
     aiX += aiLetterSize; 
    } 
} 

void CFont::DrawString(long anNumber, int aiLetterSize, int aiX, int aiY) 
{ 
    // Sanity Check! 
    if(aiLetterSize <= 0) 
    { 
     REPORT("{Gfx}["<< TIME<< "]Error: Letter size is less than zero! <Font System>\n"); 
     return; 
    } 

    // Convert the supplied number to a character string via snprintf(). 
    char *vTempString = new char[1024]; 
    snprintf(vTempString, 1024, "%ld", anNumber); 

    // Next, run DrawString(). 
    DrawString(vTempString, aiLetterSize, aiX, aiY); 
} 

void CFont::SetupFont() 
{ 
    // First Load The PNG file holding the font. 
    FreeImage_Initialise(false); 

    FIBITMAP *spBitmap = FreeImage_Load(FIF_PNG, mpPath, BMP_DEFAULT); 

    if(!spBitmap) 
    { 
     REPORT("{Gfx}["<< TIME<< "]Error: Was Unable to opne/decode font bitmap! <FreeImage>\n"); 
     return; 
    } 

    // Do an image sanity check. 
    if(!FreeImage_HasPixels(spBitmap)) 
    { 
     REPORT("{Gfx}["<< TIME<< "]Error: The font bitmap contains nothing! <FreeImage>\n"); 
     return; 
    } 

    // Retrieve all the image data from FreeImage. 
    unsigned char *pData = FreeImage_GetBits(spBitmap); 
    int iWidth = FreeImage_GetWidth(spBitmap); 
    int iHeight = FreeImage_GetHeight(spBitmap); 
    size_t const ciCharWidth = iHeight; 
    size_t const ciCharHeight = iHeight; 

    // Cutup the PNG. 
    int iFontElementSize = (ciCharWidth*ciCharHeight)*4; // The first two numbers, are the dimensions fo the element, the last number (4) is the number of color channels (Red Green Blue and Alpha) 
    unsigned char *pElemBuff = new unsigned char[iFontElementSize]; // The temporary element buffer. 

    // Create all 37 OpenGL textures. 0-9 and A-Z and finally space (' ') 
    glGenTextures(128, mpTextIDs); 

    for (size_t iCharIdx = 0; 128 > iCharIdx; ++iCharIdx) 
    { 
     // Create character texture. 
     size_t const ciScanOfst = ciCharWidth * iCharIdx * 4; 
     for (size_t iScanLineIdx = 0; ciCharHeight > iScanLineIdx; ++iScanLineIdx) 
     { 
      memcpy(pElemBuff + ciCharWidth * iScanLineIdx * 4, 
        pData + ciScanOfst + iWidth * (ciCharHeight - iScanLineIdx - 1) * 4, 
        ciCharWidth * 4); 
     } 

     // Create The OpenGL Texture with the current Element. 
     glBindTexture(GL_TEXTURE_2D, mpTextIDs[iCharIdx]); 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, pElemBuff); 

     // Create the correct texture environment to the current texture. 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
     glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); 
    } 

    // Do a little house cleaning! 
    delete[] pElemBuff; 
    FreeImage_Unload(spBitmap); 
    FreeImage_DeInitialise(); 

    REPORT("{Gfx}["<< TIME<< "]Information: Font was created succesfully! <Font System>\n"); 
} 

void CFont::SetPath(char avPath[]) 
{ 
    mpPath = avPath; 
} 

Valgrind riporta quanto segue:

Starting the FontSystem... 
FontSystem Started! 
==5058== Invalid free()/delete/delete[]/realloc() 
==5058== at 0x402A8DC: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==5058== by 0x8048F03: CFont::~CFont() (fontsystem.cpp:14) 
==5058== by 0x8048DE0: main (main.cpp:13) 
==5058== Address 0x804972f is not stack'd, malloc'd or (recently) free'd 
==5058== 
==5058== 
==5058== HEAP SUMMARY: 
==5058==  in use at exit: 4,172 bytes in 3 blocks 
==5058== total heap usage: 153 allocs, 151 frees, 135,457 bytes allocated 
==5058== 
==5058== 20 bytes in 1 blocks are still reachable in loss record 1 of 3 
==5058== at 0x402A5E6: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==5058== by 0x64DB3AD: _dlerror_run (dlerror.c:142) 
==5058== by 0x444EC64: ??? (in /usr/lib/libGL.so.295.59) 
==5058== 
==5058== 56 bytes in 1 blocks are still reachable in loss record 2 of 3 
==5058== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==5058== by 0x442860E: ??? (in /usr/lib/libGL.so.295.59) 
==5058== by 0xBE872481: ??? 
==5058== by 0x4E45504E: ??? 
==5058== 
==5058== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3 
==5058== at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==5058== by 0x8048EAC: CFont::CFont() (fontsystem.cpp:7) 
==5058== by 0x8048D68: main (main.cpp:7) 
==5058== 
==5058== LEAK SUMMARY: 
==5058== definitely lost: 4,096 bytes in 1 blocks 
==5058== indirectly lost: 0 bytes in 0 blocks 
==5058==  possibly lost: 0 bytes in 0 blocks 
==5058== still reachable: 76 bytes in 2 blocks 
==5058==   suppressed: 0 bytes in 0 blocks 
==5058== 
==5058== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) 

spero che voi ragazzi mi può aiutare con questo perché questi sembrano essere errori comuni in tutti i miei programmi. E come programmatore, non mi piacciono molto gli errori sottili, ma cattivi.

risposta

7

Il problema più evidente è questo:

==5058== Invalid free()/delete/delete[]/realloc() 
==5058== at 0x402A8DC: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==5058== by 0x8048F03: CFont::~CFont() (fontsystem.cpp:14) 
==5058== by 0x8048DE0: main (main.cpp:13) 
==5058== Address 0x804972f is not stack'd, malloc'd or (recently) free'd 
==5058== 

Come si può vedere, si riferisce alla linea 14 di fontsystem.cpp, nel distruttore di CFont, qui:

delete[] mpPath; 

A quanto pare quello che tentativo di delete [] non è mai stato assegnato in modo dinamico, o non nel modo giusto. Come può essere? La dichiarazione corrispondente nel costruttore guarda bene:

mpPath = new char[4096]; 

Quindi il valore di mpPath deve essere stato cambiato da qualche parte dopo il costruttore è stato chiamato. In effetti, c'è questa funzione:

void CFont::SetPath(char avPath[]) 
{ 
    mpPath = avPath; 
} 

Probabilmente chiamano questo posto, cercando di trasferire un array di stack ad esso assegnato. Non dovresti farlo. Se CFont è responsabile per l'allocazione e la deallocazione, non ci dovrebbe essere una funzione che tenta di prendere una matrice esterna e impostare un puntatore membro su di essa. Prendere in considerazione alternative, ad esempio la creazione di una copia dell'array avPath in una matrice appena allocata nell'heap. E de-allocare quello precedentemente assegnato. Meglio ancora, utilizzare o puntatori intelligenti.

L'altro problema è legato:

==5058== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3 
==5058== at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==5058== by 0x8048EAC: CFont::CFont() (fontsystem.cpp:7) 
==5058== by 0x8048D68: main (main.cpp:7) 

Questa è una perdita di memoria relative allo stesso membro, mpPath. E, naturalmente, questa perdita si verifica perché setPath ripristina il puntatore senza de-allocare l'array esistente. Lo stesso problema di cui sopra.

Il resto dei messaggi è correlato a varie chiamate di librerie esterne. Perdite di memoria minori di cui probabilmente non si può fare molto.

+0

Si scopre che la funzione 'void CFont :: SetPath (char *)' stava causando gli errori. È strano come piccole cose del genere possano causare errori così strani e crypt. Ora lo ho modificato in: 'void CFont :: SetPath (char * avPath) { assert (avPath! = NULL); if (mpPath == NULL) { mpPath = new char [4096]; } std :: copy (avPath, avPath + strlen (avPath), mpPath); } ' – user1787379

+0

Sì, sembra corretto (supponendo che la stringa' avPath' non sia mai più lunga di 4096 caratteri, incluso il terminale '\ x0'). E, forse inutile dire, la soluzione migliore sarebbe quella di eliminare gli array di caratteri e utilizzare invece 'std :: string'. – jogojapan

2

I 4096 byte si stanno perdendo è probabilmente da qui:

void CFont::SetPath(char avPath[]) 
{ 
    mpPath = avPath; 
} 

Si sono semplicemente copiando il puntatore (e sovrascrivendo quella vecchia); devi strcpy o usare std :: copy come in altre parti del codice.

Problemi correlati