函数的返回值已损坏

时间:2014-03-05 01:34:20

标签: c

我有以下代码:

static char sessionid[SESSIONID_LEN+1] = { '\0' };

static void generate_sessionid() {
  char set[] = "0123456789"
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  int len;

  memset(sessionid, 0, sizeof(char) * SESSIONID_LEN);
  for (len = 0; len < SESSIONID_LEN; len++) {
    size_t index = (double) rand()/RAND_MAX*(sizeof(set) - 1);
    sessionid[len] = set[index];
  }
}

char *get_sessionid() {
  if (strlen(sessionid) == 0) generate_sessionid();
  char * dup = strdup(sessionid);
  return dup;
}

我从另一个线程(其功能在不同的文件中定义)中调用get_sessionid()。当我在get_sessionid()的第2行中断并检查strdup()返回的指针地址时,这是值:

0x7f7788c004f50

现在,当我从这个函数返回并检查线程函数中捕获的返回值时,返回值是不同的:

0xfffffffffc004f50

随后当我在此返回的指针值上调用strlen()时,我得到一个SIGSEGV,原因是Address 0xfffffffffc004f50 out of bounds

这两个文件是一个大型应用程序的一部分,该应用程序运行大约30个线程,并且在其他地方发生了更多的内存分配。我还认为内存已被其他线程泄露。但我想确保上述代码中没有错误。

我分别验证了上面的代码,一切正常,返回值没有损坏,即当与程序的其余部分隔离时,它完全正常。但我不明白为什么在整个程序的上下文中运行时返回值会发生变化。

修改(附件)

在线程函数中,我调用:

thread.c

#include <header.h>

login_sessionid = (char*)get_sessionid();

标题: header.h

char * get_sessionid(void);

编译器警告:

warning: implicit declaration of function ‘get_sessionid’ [-Wimplicit-function-declaration]
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]

以上警告均位于文件thread.c

所示的行(上方)

2 个答案:

答案 0 :(得分:4)

另一个文件中的代码没有意识到get_sessionid()返回一个指针所以它假定它返回一个整数,然后用它来签名扩展它以创建一个指针。

您的编译器可能会警告未声明的函数;如果不是,请调高警告级别,直到警告级别为止。它也应该警告将整数转换为不同大小的指针。

注意编译器给出的警告。请记住,它比你更了解C语言。

还要确保编译器为您提供尽可能多的警告。如果您使用gcc,则应使用gcc -Wall -Wextra -Werror -Wmissing-prototypes -Wold-style-definition -Wold-style-declaration干净地编译;那是我目前的基准(-std=c11-std=c99)。如果您的版本不支持旧式警告,您可以直接将其删除。

答案 1 :(得分:3)

除了@Jonathan Leffler所说的,如果多个线程可以调用此例程,则存在竞争条件,允许不同的线程获得不同的id,即使它们是单独的副本。

可能发生的一个例子:

  • 多个线程检查静态会话ID并看到零,因此开始初始化并停止。
  • 一次一个线程完成初始化并创建自己的副本。因此每个线程都有不同的id。

通常,静态存储(没有互斥)和多个线程不会混合。这是多线程环境中singleton pattern的典型问题。