2012-07-23 101 views
0

我一直在撓我的頭髮,但似乎無法找到以下代碼有什麼問題。這裏是它在0x4c22d82產生無效的讀取大小1 valgrind

尺寸1的讀出無效的valgrind輸出的小片段:strlen的(mc_replace_strmem.c:242) 由0x5E65CA:應用:: readConfigurationFile()(char_traits.h:262)通過0x5694BD:主地址0xafc9660是一個大小爲 39 free'd在0x4C20E0D處的24個字節:操作員刪除(void *) (vg_replace_malloc.c:342)by 0x635618: Configurator :: getParameterValue(char const * char **)by 0x5E65B2: Application:readConfigurationFile()(Application.cpp:77)by 0x5694BD: main

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。

回答

1

你實際上是返回一個指針到一個局部變量。在getParameterValue變量qs在塊內是本地的,並且您將該字符串指針分配給p_pParameterValue。當getParameterValue以前被qs佔用的堆棧空間現在被回收,並且指針pTemp現在指向未使用的內存。這是未定義的行爲,並可能導致很多不好的事情發生。從qs.toStdString()返回

+0

感謝您的迴應,所以不要這樣做,我應該使用strncpy,是嗎? – 2012-07-23 12:08:04

+1

@erinc否,那麼你必須分配和釋放內存。我的建議是,你要麼使用對'QString'或'std :: string'的引用。 – 2012-07-23 12:16:37

2
​​

爲什麼你這樣做? 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)爲 i的[0,size()]。 2複雜性:時間不變。 3要求: 程序不得更改存儲在字符 數組中的任何值。

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

錯誤。由於刪除了pTemp中的值,因此臨時對象qs.toStdString()被刪除。

1

臨時字符串對象的字符串,當臨時被破壞(充分表達的評估之後),其被釋放分配內存。如果您正在編譯優化,則很可能將std::string標記內聯到您的函數中,因此它不會顯示在您的調用堆棧中。

如果您希望繼續使用該功能完成後的字符串數據,你需要使它堅持。 (在我看來)最簡單的方法是返回一個std::string對象而不是char *,因此最後一個參數可以是std::string **(由new std::string(qs.toStdString())填充)或std::string &分配給。

如果您有Boost庫,也可以使用boost::optional<std::string>作爲返回類型,它提供了一個「帶有有效標誌的字符串」數據類型。