无效的读取大小为1 valgrind

时间:2012-07-23 09:28:38

标签: c++ valgrind

我一直在抓我的头发,但似乎无法找到以下代码的错误。这是它生成的valgrind输出的小片段

  

在0x4c22d82读取大小1无效:strlen(mc_replace_strmem.c:242)   by 0x5E65CA:Application :: readConfigurationFile()(char_traits.h:262)   通过0x5694BD:主地址0xafc9660在一个大小的块内是24个字节   39免费在0x4C20E0D:操作员删除(void *)   (vg_replace_malloc.c:342)by 0x635618:   Configurator :: getParameterValue(char const *,char **)by 0x5E65B2:   应用程序:readConfigurationFile()(Application.cpp:77)by 0x5694BD:   主

bool Configurator::getParameterValue(const char *p_pParameterName, char** p_pParameterValue)
{
    bool blReturnValue = false;

    QDomElement element;
    QDomNode node;
    QDomNodeList list;

    list = doc.elementsByTagName(p_pParameterName);
    if (!list.isEmpty())  
    {
        node = list.item(0);
        element = node.toElement();
        QString qs = element.text().toUtf8();
        *p_pParameterValue = (char *)(qs.toStdString().c_str());
        blReturnValue = true;
    }
    else
    {
        char sMessage[200];
        sprintf(sMessage, "<Configurator::getParameterValue> Error! Parameter %s could not be found\n", p_pParameterName);
        m_outputFunction(sMessage);
    }

    return blReturnValue;
}

bool Configurator::parseFile()
{
    bool blReturnValue = false;

    QString errorStr;
    int errorLine;
    int errorColumn;

    if (!doc.setContent((QIODevice*)(&file), true, &errorStr, &errorLine, &errorColumn))
    {
        char aTemp[512];
        sprintf(aTemp, "<Configurator::parseFile> error! can not read the file row: %d, column: %d:\n",errorLine, errorColumn);
        m_outputFunction(aTemp);
    }
    else
    {
        closeFile();
        blReturnValue = true;
    }

    return blReturnValue;
}

bool Application::readConfigurationFile()
{
    bool blReturnValue = false;

    m_outputFunction("<Application::readConfigurationFile> Reading configuration..\n");

    if(m_configurator.parseFile())
    {
        blReturnValue = true;

        m_configurator.writeParameters();

        char *pTemp = 0;


        if(!m_configurator.getParameterValue("center_no", m_bCenterNo)) 
            m_bCenterNo = 1;
        if(m_configurator.getParameterValue("highway_header", &pTemp))
            m_strHighwayHeader.assign(pTemp);
        else
            m_strHighwayHeader.assign("... HIGHWAY"); // Default value
    }
    return blReturnValue;
}

有人可以告诉我为什么我看到无效的读取,我甚至不在这段代码中使用malloc / calloc。

3 个答案:

答案 0 :(得分:2)

*p_pParameterValue = (char *)(qs.toStdString().c_str());

你为什么这样做? QString是局部变量,toStdString返回新的std::string

std::string QString::toStdString () const

因此,返回的std :: string将被删除。 c_str()返回指向const char *的指针。引自n3337草案:

const charT* c_str() const noexcept;
const charT* data() const noexcept; 
  

1返回:指针p,使得p + i == &operator[](i)   我[0,size()]中的每一个。 2复杂性:恒定时间。 3要求:   程序不得更改存储在字符中的任何值   阵列。

if(m_configurator.getParameterValue("highway_header", &pTemp))
                m_strHighwayHeader.assign(pTemp);

错误。由于删除了pTemp中的值,因此删除了临时对象qs.toStdString()

答案 1 :(得分:1)

您实际上是返回指向局部变量的指针。在getParameterValue中,变量qs在块内是本地的,并且您将该字符串指针指定给p_pParameterValue。当getParameterValue以前由qs占用的堆栈空间现在被回收并且指针pTemp现在指向未使用的内存。这是未定义的行为,并且可能导致许多不良事件发生。

答案 2 :(得分:1)

qs.toStdString()返回的临时字符串对象为字符串分配内存,在临时销毁时(在评估完整表达式之后)释放该字符串。如果您正在使用优化进行编译,则可能会将std::string d}内联到您的函数中,因此它不会显示在您的调用堆栈中。

如果要在功能完成后继续使用字符串数据,则需要使其保持不变。 (在我看来)sanest方式是返回std::string对象而不是char *,因此最后一个参数可以是std::string **(由new std::string(qs.toStdString())填充) ,或分配给的std::string &

如果你有Boost库,你也可以使用boost::optional<std::string>作为返回类型,它提供了一个“带有效标志的字符串”数据类型。