c – 为什么这个指针是fu-segfault?

我似乎已经达到了我的Pointer-Fu的极限并且正在寻求帮助(或某种脑部医学).

该项目的大致概述:运行Linux的嵌入式ARM视频编码器板,使用制造商提供的记录不良的支持不足的SDK.在它庞大的代码中,有一大堆是由gSoap从某些WSDL生成的,而这正是导致头疼的问题.

在gSoap自动生成的巨大数据结构的一部分中,我们可以编写一些数据(或者写一个指向我们写入数据的地方的指针):

 struct tt__IPAddress
 {
    enum tt__IPType Type;   /* required element of type tt:IPType */
    char *IPv4Address;  /* optional element of type tt:IPv4Address */
    char *IPv6Address;  /* optional element of type tt:IPv6Address */
 };

然后我们有这个代码,简而言之,应该是在IPv4Address上写一个字符串:

DNSInformation->DNSManual = ((struct tt__IPAddress *)soap_malloc(soap, sizeof(struct tt__IPAddress)));
DNSInformation->DNSManual->IPv4Address = (char **)soap_malloc(soap, sizeof(char *));
DNSInformation->DNSManual->IPv4Address[0] = (char *)soap_malloc(soap, sizeof(char) * LARGE_INFO_LENGTH);
// Code crashes at this next line:
strncpy(*DNSInformation->DNSManual->IPv4Address, dns_string, LARGE_INFO_LENGTH-1);

dns_string是你所期望的 – 类似于“192.168.2.254”.它正确地以null结尾,LARGE_INFO_LENGTH的值很大(比如1024),因此字符串有足够的空间.为了安全起见,我从strcpy()更改为strncpy().

我的背景是较小的嵌入式东西(没有操作系统,没有使用malloc())所以我在说服自己理解这段代码的作用时遇到了一些麻烦.代码是自动生成的/ SDK的一部分,因此它不是我的创建,也没有记录/评论.

这是我认为它正在做的事情:

DNSInformation->DNSManual = ((struct tt__IPAddress *)soap_malloc(soap, sizeof(struct tt__IPAddress)));

正在分配由DNSManual指向的一块RAM,其中tt__IPAddress结构将存在.

DNSInformation->DNSManual->IPv4Address = (char **)soap_malloc(soap, sizeof(char *));

正在分配由IPv4Address指向的一块RAM,其中将写入指向包含该地址的字符串的指针.

DNSInformation->DNSManual->IPv4Address[0] = (char *)soap_malloc(soap, sizeof(char) * LARGE_INFO_LENGTH);

现在这个让我有点兴趣,看起来它正在尝试分配RAM来保存IPv4Address [0]将指向的字符串,除了看起来像他们试图写一个(32位)指针可能是一个char.

此代码以前有效,但是在其他地方进行了一些更改之后,它现在是段错误,总是在strncpy()处或期间.

我的问题有两个:

>有人可以帮我正确理解mallocs / pointer-fu的情况吗?
>有关如何跟踪/调试此问题的任何指导?

遗憾的是,我们没有这种设置的GDB设施 – 是的我确信可以设置它,但是现在让我们假设这对于许多蹩脚和乏味的原因是不实际的.

目前我通过代码调试printf散乱,实际上在这个小片段的每一行,它总是在strncpy()行停止使用SIGSEGV.

编辑关闭,因为WhozCraig找到答案:

由于其自身最为人所知的原因,gSoap已经更改了struct tt__IPAddress,也许它已经用完了星号,但它在以前的版本中已经存在,它应该是什么,是这样的:

struct tt__IPAddress
 {
    enum tt__IPType Type; 
    char **IPv4Address;  /* note ptr to ptr */
    char **IPv6Address;
 };

最佳答案 代码不遵循结构布局.布局是:

 struct tt__IPAddress
 {
    enum tt__IPType Type;   /* required element of type tt:IPType */
    char *IPv4Address;  /* optional element of type tt:IPv4Address */
    char *IPv6Address;  /* optional element of type tt:IPv6Address */
 };

含义:IPv4Address是一个char指针.这个:

DNSInformation->DNSManual->IPv4Address = (char **)soap_malloc(soap, sizeof(char *));

正在为它分配一个char **.但类型仍然是char *所以这个:

strncpy(*DNSInformation->DNSManual->IPv4Address, dns_string, LARGE_INFO_LENGTH-1);

解除引用指向单个字符的指针,我可以向你保证它与你平台上的char *不兼容(可能还有其他任何问题).

应该至少在这个编译上运行警告,如果你的编译器有任何大脑,那么就会出现完全错误.这看起来像是原始的意图:

 struct tt__IPAddress
 {
    enum tt__IPType Type; 
    char **IPv4Address;  /* note ptr to ptr */
    char **IPv6Address;
 };

为了拥有动态指针数组,每个指针都是为单个IP地址动态分配的内存.如果它是这样的话,它会更有意义.也就是说,如果您打算每个结构只有一个IPv4地址,那么应该更改:

DNSInformation->DNSManual = soap_malloc(soap, sizeof(struct tt__IPAddress)));
if (DNSInformation->DNSManual)
{
    DNSInformation->DNSManual->IPv4Address = soap_malloc(soap, sizeof(char) * LARGE_INFO_LENGTH);
    if (DNSInformation->DNSManual->IPv4Address)
    {
        strncpy(DNSInformation->DNSManual->IPv4Address, dns_string, LARGE_INFO_LENGTH-1);
        DNSInformation->DNSManual->IPv4Address[LARGE_INFO_LENGTH-1] = 0;
    }
}

或类似的东西.

点赞