C 函数的返回值正在损坏

C 函数的返回值正在损坏,c,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_

我有以下代码:

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;
}
现在,当我从此函数返回并检查线程函数中捕获的返回值时,返回值不同:

0xfffffffffc004f50
随后,当我对这个返回的指针值调用strlen时,我得到一个SIGSEGV,原因是地址0xfffffffc004f50超出范围

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

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

编辑附件

在线程函数中,我调用为:

螺纹c

编译器警告:

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的上面所示的行。另一个文件中的代码很可能没有意识到get_sessionid返回指针,因此它假设它返回一个整数,然后符号扩展该整数以创建指针

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

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


还要确保编译器给你尽可能多的警告。如果您使用gcc,那么应该使用gcc-Wall-Wextra-Werror-Wmissing原型-Wold样式定义-Wold样式声明干净地编译;这是我当前使用-std=c11或-std=c99的基准测试。如果您的版本不支持旧式警告,您可以简单地将其删除。

另一个文件中的代码很可能没有意识到get_sessionid返回指针,因此它假设它返回整数,然后对其进行符号扩展以创建指针

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

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


还要确保编译器给你尽可能多的警告。如果您使用gcc,那么应该使用gcc-Wall-Wextra-Werror-Wmissing原型-Wold样式定义-Wold样式声明干净地编译;这是我当前使用-std=c11或-std=c99的基准测试。如果您的版本不支持旧式警告,您可以简单地将其删除。

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

可能发生的情况的一个例子:

多个线程检查静态会话id并看到零,因此开始初始化并停止。 一次一个线程完成初始化并创建自己的副本。因此,每个线程获得不同的id。
通常,没有互斥和多线程的静态存储不会混合使用。这是多线程环境中的一个典型问题。

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

可能发生的情况的一个例子:

多个线程检查静态会话id并看到零,因此开始初始化并停止。 一次一个线程完成初始化并创建自己的副本。因此,每个线程获得不同的id。
通常,没有互斥和多线程的静态存储不会混合使用。这是多线程环境中的一个典型问题。

是!我在文件和调用上述函数的行中注意到了编译器的警告:警告:赋值从整数生成指针而不使用强制转换[enabled by default],我确实声明了函数char*get_sessionid;在包含在调用文件中的头文件中。我是不是应该投出一个指针?或者有更好的方法吗?您应该声明extern char*get_sessionidvoid;在标题中。空白是必要的;如果你没有包含它,你没有给函数一个原型,它是一个声明,但不是一个原型声明;该函数接受未知但固定数量的参数。外部环境是不必要的;很多人忽略了它,但我更喜欢包含它,因为它与必须用extern声明的少数全局变量是对称的。您应该在两个源文件中都包含该头文件。头允许编译器检查用法是否与定义匹配
我已经按照您的建议声明并包含了标题。我甚至在最后打字。但错误依然存在。但是我有很多以前没有注意过的编译器警告:我想我需要先尝试解决我遇到的其他编译器警告,然后再试一次。在收割台上有收割台护罩吗?你有正确的头部防护装置吗?您可以显示代码吗:您可能至少有不到10行的头,1行,第二个文件中的C可能不到10行,包括include header.h和char*report_sessionidvoid{return get_sessionid;}等函数。在编译代码时,还应该包含来自编译器的错误消息,并标识运行该代码的编译器和平台。有了这些,我们应该可以看到问题出在哪里了。太好了!我已经附加了头文件和编译器警告。更重要的是,我注意到我包含了错误的头文件!问题是我没有包含所需的头文件,而是在编译时链接了包含函数定义的库。是的!我在文件和调用上述函数的行中注意到了编译器的警告:警告:赋值从整数生成指针而不使用强制转换[enabled by default],我确实声明了函数char*get_sessionid;在包含在调用文件中的头文件中。我是不是应该投出一个指针?或者有更好的方法吗?您应该声明extern char*get_sessionidvoid;在标题中。空白是必要的;如果你没有包含它,你没有给函数一个原型,它是一个声明,但不是一个原型声明;该函数接受未知但固定数量的参数。外部环境是不必要的;很多人忽略了它,但我更喜欢包含它,因为它与必须用extern声明的少数全局变量是对称的。您应该在两个源文件中都包含该头文件。头让编译器检查用法是否与定义匹配。我已经按照您的建议声明并包含了头。我甚至在最后打字。但错误依然存在。但是我有很多以前没有注意过的编译器警告:我想我需要先尝试解决我遇到的其他编译器警告,然后再试一次。在收割台上有收割台护罩吗?你有正确的头部防护装置吗?您可以显示代码吗:您可能至少有不到10行的头,1行,第二个文件中的C可能不到10行,包括include header.h和char*report_sessionidvoid{return get_sessionid;}等函数。在编译代码时,还应该包含来自编译器的错误消息,并标识运行该代码的编译器和平台。有了这些,我们应该可以看到问题出在哪里了。太好了!我已经附加了头文件和编译器警告。更重要的是,我注意到我包含了错误的头文件!问题是我没有包含所需的头文件,而是在编译时链接了包含函数定义的库。我实际上用互斥锁包围了get_sessionid中的关键部分。我删除了这一部分,希望这不是问题所在。实际上,我在get_sessionid中的关键部分使用了互斥锁。我删除了这一部分,希望这不是问题所在。我不知道这是否是您的问题的一个因素,但标题的“经验法则”是:对您编写的标题或项目的一部分使用include header.h,对项目外部提供的标题使用include。如果您的项目实际上是一个库,那么您可以使用,或者更可能使用,从您的项目中包含公共头,并使用header.h包含私有头。哦,好的。我错误地认为header.h仅用于当前工作目录中的标题和其他所有内容。我不知道这是否是您的问题的一个因素,但标题的“经验法则”是:使用include header.h用于您编写的标题或是您项目的一部分,并将include用于项目外部提供的标题。如果您的项目实际上是一个库,那么您可以使用,或者更可能使用,从您的项目中包含公共头,并使用header.h包含私有头。哦,好的。我错误地认为header.h仅用于当前工作目录中的头以及其他所有内容。
#include <header.h>

login_sessionid = (char*)get_sessionid();
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]