2015-10-20 47 views
5

使用libxml解析文件時出現奇怪的段錯誤。當我將它編譯爲32位應用程序時,此代碼以前可用。我將其更改爲64位應用程序,並停止工作。閱讀xml時地址超出範圍錯誤

賽格的故障出現在 「如果(xmlStrcmp(CUR->名稱,(常量XMLCHAR *) 」服務器「))」

CUR->名稱是一個const XMLCHAR *和它指向的地址這說明了它的出界。但是,當我調試並轉到該內存位置時,該數據是正確的。

int XmlGetServers() 
{ 
xmlDocPtr doc; 
xmlNodePtr cur; 

doc = xmlParseFile("Pin.xml"); 
if (doc == NULL) 
{ 
    std::cout << "\n Pin.xml not parsed successfully." << std::endl; 
    return -1; 
} 
cur = xmlDocGetRootElement(doc); 

if (cur == NULL) 
{ 
    std::cout << "\n Pin.xml is empty document." << std::endl; 
    xmlFreeDoc(doc); 
    return -1; 
} 
if (xmlStrcmp(cur->name, (const xmlChar *) "servers")) 
{ 
    std::cout << "\n ERROR: Pin.xml of the wrong type, root node != servers." << std::endl; 
    xmlFreeDoc(doc); 
    return -1; 
} 
} 

之前CUR初始化參數name是

Name : name 
    Details:0xed11f72000007fff <Address 0xed11f72000007fff out of bounds> 

CUR初始化後的名稱參數

Name : name 
    Details:0x64c43000000000 <Address 0x64c43000000000 out of bounds> 

引用的XML文件

<?xml version="1.0"?> 

<servers> 

<server_info> 

    <server_name>Server1</server_name> 

    <server_ip>127.0.0.1</server_ip> 

    <server_data_port>9000</server_data_port> 

</server_info> 

<server_info> 

    <server_name>Server2</server_name> 

    <server_ip>127.0.0.1</server_ip> 

    <server_data_port>9001</server_data_port> 

</server_info> 

</servers> 

系統:

OS:紅帽企業Linux 6.4的64位

GCC:4.4.7-3

包:libxml2-2.7.6-8.el6_3.4.x86_64

+0

你有64位版本的libxml嗎? – vmg

+0

是libxml2-2.7.6-8.el6_3.4.x86_64 – user758114

+0

您是否曾嘗試使用valgrind運行應用程序,如Sam Varshavchik所做的那樣? –

回答

0

問題在於我們在我們的代碼中使用了#pragma pack(1), 這意味着DOMParser中的bools被壓縮到1個字節,而Xerces沒有#pragma pack並獲得4的默認包裝字節。

17

我把你的碼,如,並加入:

#include <libxml/parser.h> 
#include <iostream> 

然後改名函數main()和編譯它的x86-64的Fedora 22,其具有的libxml2 2.9.2

生成的代碼使用示例文件成功運行,沒有段錯誤。即使valgrind未找到內存訪問衝突。作爲證明,所產生的,簡稱strace的日誌如下:

stat("Pin.xml", {st_mode=S_IFREG|0644, st_size=362, ...}) = 0 
stat("Pin.xml", {st_mode=S_IFREG|0644, st_size=362, ...}) = 0 
stat("Pin.xml", {st_mode=S_IFREG|0644, st_size=362, ...}) = 0 
open("Pin.xml", O_RDONLY)    = 3 
lseek(3, 0, SEEK_CUR)     = 0 
read(3, "<?xml version=\"1.0\"?>\n\n<servers>\n\n<server_info>\n\n <server_name>Server1</server_name>\n\n <server_ip>127.0.0.1</server_ip> \n\n <server_data_port>9000</server_data_port> \n\n</server_info>\n\n<server_info>\n\n <server_name>Server2</server_name> \n\n <ser"..., 8192) = 362 
read(3, "", 7830)      = 0 
getcwd("/tmp", 1024)     = 5 
close(3)        = 0 
exit_group(0)       = ? 
+++ exited with 0 +++ 

雖然這是Fedora的略有新的libxml2和gcc,這種差異並不重要。這裏的答案是這裏顯示的代碼沒有問題。我沒有看到任何錯誤。

但它顯然是一個更大的應用程序的一部分,並且您的內存損壞發生在您的應用程序的某些其他部分,並且只有當您的應用程序的執行達到此部分時纔會顯現出來。

關於C++的一點是,僅僅因爲代碼在特定點崩潰,並不意味着這行代碼就是問題所在。拿出一個簡單的例子不應該太難:

#include <iostream> 
#include <cstring> 

int main() 
{ 

    char foo[3]; 

    strcpy(foo, "FoobarbazXXXXXXXXXXXXXXXXXXXXXX"); 

    for (int i=0; i<100; i++) 
     std::cout << i << std::endl; 
    return 0; 
} 

這個錯誤顯然發生在strcpy行。但代碼將運行得很好,並從0到99打印100個數字,並在main()返回時崩潰。但是,顯然,「返回0」並不是錯誤所在。

這與您的應用程序發生的情況類似。某些內存損壞發生在某些時刻,直到您的代碼嘗試解析您的XML文件時纔會實質性影響代碼執行。

歡迎來到C++。

+0

謝謝,它並沒有讓我想到問題可能來自其他地方。只需快速跟進,是否有任何方法可以重新編譯代碼以更改發生內存衝突的點? – user758114

+0

關於破壞記憶的事情是結果是不可預測的,沒有任何規則或準則可以遵循。真的,沒有簡單的,按數字,配方或過程來追蹤和定位真正的錯誤。我在這種情況下嘗試的典型做法是使用像valgrind這樣的靜態分析工具,或者臨時更改代碼邏輯以跳過通常會執行的大部分代碼,以查看內存損壞是否消失。這一切都歸結爲經驗,知識和理解CPU如何運行代碼,以及您的應用程序如何工作。 –