4

我似乎已经达到了我的 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”。它正确地以空值结尾,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 位)指针可能是一个字符。

该代码以前可以工作,但是在其他地方进行了一些更改后,它现在总是在 strncpy() 处或期间出现段错误。

我的问题是双重的:

  1. 有人可以帮助我正确理解 mallocs/pointer-fu 发生了什么吗?
  2. 有关如何进行跟踪/调试的任何指导?

不幸的是,我们没有使用此设置的 GDB 工具 - 是的,我确信可以设置它,但现在让我们假设由于许多蹩脚和乏味的原因这不切实际。

目前,我已经通过代码大量地调试了 printf,实际上在这个小片段的每一行上,它总是在 strncpy() 行处以 SIGSEGV 停止。


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

出于众所周知的原因,gSoap 更改了 struct tt__IPAddress,也许它已经用完了星号,但它在以前的版本中是什么,应该是什么,是这样的:

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

4 回答 4

2

代码不遵循结构布局。布局是:

 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,我可以向您保证,它与您平台上的 a 不兼容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;
    }
}

或者类似的东西。

于 2013-08-27T17:06:57.507 回答
0

我觉得它看起来坏了。

这:

char *IPv4Address;  /* optional element of type tt:IPv4Address */

sayIPv4Address是一个指向字符数据的指针,即一个字符串。

但后来它是这样使用的:

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

这是错误的。soap_malloc()假设(即void *遵守)的合理返回值malloc(),则不需要强制转换,但强制转换实际类型不同的事实表明某种错误。

它将IPv4Address结构字段视为指向指针的指针,但显然不是。

于 2013-08-27T17:04:36.010 回答
0

我敢肯定它应该看起来像这样:

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

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

您的结构包含指向字符串的指针,但首先它分配一个指针数组(char**),然后为该数组中的第一个指针分配内存。

并且不要忘记在使用 strncpy() 后设置二进制零,因为它不会自行设置。

//编辑:第一部分是错误的,对不起

于 2013-08-27T17:07:25.973 回答
0

是一个可行的解决方案(我使用malloc而不是soap_malloc等):

#include <stdio.h>
#include <stdlib.h>

#define LARGE_INFO_LENGTH 1024

enum tt__IPType { tt__IPv4, tt__IPv6 };

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 */
};

struct tt__DNSInformation
{
  struct tt__IPAddress* DNSManual;
};

int main()
{
  struct tt__DNSInformation* DNSInformation;
  char dns_string[] = "192.168.2.254";

  DNSInformation = malloc(sizeof(struct tt__DNSInformation));
  DNSInformation->DNSManual = malloc(sizeof(struct tt__IPAddress));
  DNSInformation->DNSManual->IPv4Address = malloc(sizeof(char) * LARGE_INFO_LENGTH);
  strncpy(DNSInformation->DNSManual->IPv4Address, dns_string, LARGE_INFO_LENGTH - 1);

  printf("%s\n", DNSInformation->DNSManual->IPv4Address);
  return 0;
}
于 2013-08-27T17:07:28.133 回答