1

私は自分の髪をかき集めてきましたが、次のコードの何が問題なのかを見つけることができないようです. これは、それが生成する valgrind 出力の小さなスニペットです

0x4c22d82 でのサイズ 1 の無効な読み取り: 0x5E65CA による strlen (mc_replace_strmem.c:242): 0x5694BD による Application::readConfigurationFile() (char_traits.h:262): メイン アドレス 0xafc9660 は、サイズ 39 のブロック内の 24 バイトです。 0x4C20E0D: operator delete(void*) (vg_replace_malloc.c:342) by 0x635618: Configurator::getParameterValue(char const*, char**) by 0x5E65B2: Application: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 も使用していません。

4

3 に答える 3

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; 

&operator[](i)1 戻り値:各 i in に対してp + i == となるポインター p [0,size()]。2 複雑さ: 一定時間。3 必須: プログラムは、文字配列に格納されている値を変更してはなりません。

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

違う。pTemp の値が削除されたため、一時オブジェクトqs.toStdString()が削除されたとき。

于 2012-07-23T09:36:01.223 に答える
1

実際には、ローカル変数へのポインターを返しています。getParameterValue変数はブロック内でローカルであり、そのqs文字列ポインターをに割り当てますp_pParameterValuegetParameterValue以前占有されていたスタック領域qsが再利用され、ポインタ pTemp が未使用のメモリを指すようになったとき。これは未定義の動作であり、多くの悪いことが起こる可能性があります。

于 2012-07-23T09:44:15.603 に答える
1

から返される一時的な文字列オブジェクトはqs.toStdString()、文字列にメモリを割り当てます。このメモリは、一時オブジェクトが破棄されると解放されます (完全な式の評価後)。最適化を使用してコンパイルしている場合、std::stringd'tor が関数にインライン化されている可能性が高いため、コール スタックに表示されません。

関数の実行後に文字列データを引き続き使用する場合は、永続化する必要があります。std::string(私の意見では)最も健全な方法は、ではなくオブジェクトを返すことですchar *。そのため、最後のパラメーターstd::string **は で埋められるnew std::string(qs.toStdString())、または にstd::string &割り当てられた になります。

Boost ライブラリがある場合boost::optional<std::string>は、「有効なフラグを持つ文字列」データ型を提供する戻り値の型として使用することもできます。

于 2012-07-23T09:44:50.983 に答える