2015-10-20 34 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如何运行代码,以及您的应用程序如何工作。 –