微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 这个valgrind错误是什么意思?

我有一个基本的库,我用它来绘制OpenGL文本,当我使用valgrind确保它是气密的.我不断得到一个不寻常的错误,看起来好像 linux c库有问题.我想看看你们是否可以发现我的错误或认证我担心的问题,那就是我的c库有问题需要更换.代码非常简单,但它同时使用OpenGL和Free Image,因此某些行没有意义.

这是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 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,iTmpTex);
        std::copy(a.mpDrawIDs,iTmpDraw);
        std::copy(a.mpPath,vTmpPath);

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

        return *this;
    }
};

#endif // FONTSYstem_H

这是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 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,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 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,GL_RGBA,32,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_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报告如下:

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)

我希望你们可以帮助我,因为这些似乎是我所有程序中常见的错误.作为一名程序员,我不太喜欢微妙而又令人讨厌的错误.

解决方法

最显着的问题是这一个
==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==

正如你所看到的,它引用了fontsystem.cpp的第14行,在CFont的析构函数中,这里:

delete[] mpPath;

显然你试图删除[]的东西从来没有动态分配,或者没有以正确的方式分配.怎么可能?构造函数中的相应语句看起来很好:

mpPath = new char[4096];

因此,在调用构造函数之后,必须在某处更改mpPath的值.的确,有这个功能

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

您可能在某处调用方法,尝试将堆栈分配的数组传输给它.你不应该这样做.如果CFont负责分配和释放,则不应该有一个函数尝试获取外部数组并设置指向它的成员指针.考虑替代方案,例如将avPath数组的副本复制到堆上新分配的数组中.并取消分配先前分配的一个.更好的是,使用std :: vector或智能指针.

一个问题是相关的:

==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)

这是与同一成员mpPath相关的内存泄漏.当然,这种泄漏的发生是因为setPath重置指针而不取消分配现有数组.与上述问题相同.

其余消息与各种外部库调用有关.轻微的内存泄漏你可能做不到多少.

原文地址:https://www.jb51.cc/c/111301.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐