返回 malloc 的结构会给出段错误和不同的地址

Posted

技术标签:

【中文标题】返回 malloc 的结构会给出段错误和不同的地址【英文标题】:Returning malloc'd structs gives segfault and different address 【发布时间】:2020-11-07 22:02:25 【问题描述】:

我正在开发一个处理 C 中某些网络连接的库,我的计划是让 init 函数返回一个结构,其中包含连接的所有相关数据,然后调用者将传递给任何库函数。我还希望调用者可以访问结构的内容。

这是我的初始化(库)代码

//here is the struct
typedef struct 
  SSL_CTX* ctx;
  SSL* ssl;
  int socket;
  int usingSSL;
 twitch_connection;


struct twitch_connection* twlibc_init(int usingSSL) //returns a pointer to a struct that has to be freed
  twitch_connection *temp;
  temp = malloc(sizeof(twitch_connection)); //creates the address for the struct
  struct sockaddr_in twitchaddr;
  ...
  if(usingSSL == 0)
    //not using SSL
    temp->ctx = NULL;
    temp->ssl = NULL;
  else 
    //using SSL
    temp->ctx = ctx; //how I assign values to the struct
    temp->ssl = ssl;
  
  
  temp->socket = twitchsock;

  return temp; //returns the struct back to caller


这是我的演示代码

int main()
  
  twitch_connection* twlibc = twlibc_init(1);

  
  printf("address of struct from main of callers code is: %p\n", twlibc);

但是,当我打印结构的地址时,从代码中的不同区域打印时会得到不同的结果:

address of struct from inside init function: 0x56299befd260
address of struct from main of callers code is: 0xffffffff9befd260

如果我尝试从主函数中打印结构的成员,我会遇到分段错误。

【问题讨论】:

已关闭,但显示的代码不完整。我们需要查看能够重现问题的确切代码。请提供minimal verifiable example。 您向我们展示了一些很好的代码,但您只向我们展示了有效的部分。向我们展示失败的代码。 警告在哪里?你在关注他们中的任何一个吗?用-Wall -Werror编译! 【参考方案1】:

twitch_connection* twlibc = twlibc_init(1);

由于此时没有声明twlibc_init,所以C假定返回值是一个int,所以上面等价于twlibc = (twitch_connection*)(int)twlibc_init(1);

在具有 32 位 int 类型的 64 位平台上,这会将 0x56299befd260 截断为 32 位整数 0x9befd260,然后将其符号扩展为 64 位指针 0xffffffff9befd260

解决方案是在主文件中声明函数struct twitch_connection* twlibc_init(int usingSSL);,或者更好的是,将声明移动到两个位置都包含的公共头中。


[ EDIT ] 将int 转换为指针时的符号扩展是依赖于实现的,C 标准不保证,因此另一个编译器可能已经打印了0x9befd260,或者,实际上, 任何事物。来自 cppreference C cast operator 页面:

任何整数都可以转换为任何指针类型。除了 NULL 等空指针常量(不需要强制转换)外,结果是实现定义的,可能未正确对齐,可能不指向引用类型的对象,并且可能是陷阱表示。

【讨论】:

谢谢,这最终奏效了。原来我已经在我使用的头函数中声明了它,但是当这个方法返回一个 int (只是套接字)时,它是我旧代码的残余。 int twlibc_init(int usingSSL); @AnttiHaapala 这是一个中肯的建议,在开发(大概)供他人使用的库时两次。

以上是关于返回 malloc 的结构会给出段错误和不同的地址的主要内容,如果未能解决你的问题,请参考以下文章

释放时填充结构数据会导致段错误

malloc() 和 malloc_consolidate() 中的段错误

malloc中的电子围栏段错误

quiz 3

malloc必须有对应的free

探秘malloc是如何申请内存的