在srandom_r的Segfault

时间:2013-09-02 09:13:41

标签: c linux random reentrancy

我的智慧结束了。这个简单的代码给了我Segfault,可能有什么问题?

struct  random_data *qq;

qq = calloc(50, sizeof(struct random_data));
srandom_r(time(NULL), qq);

现在,如果我像这样改变它,它可以工作:

struct  random_data qq;

srandom_r(time(NULL), &qq);

我一定是个白痴,但我无法理解。请帮忙。

更新:calloc返回一个有效的指针

(uint64_t) 1aa5010

然而,& qq代表指针

(uint64_t) 7fffbb428090

这就是区别,但不清楚为什么srandom_r无法执行。 我尝试在Linux 2.6.32-44-server#98-Ubuntu

3 个答案:

答案 0 :(得分:5)

似乎大多数答案从未真正尝试过运行代码。 这是一个非常简约的程序,确实展现了你的问题:

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

int main() {
 int seed = time(NULL);
 struct random_data *qq = NULL;

 qq = calloc(1, sizeof(struct random_data));
 if(qq) {
   srandom_r(seed, qq); /* segfault! */
 } else {
   printf("failed to allocate `qq`\n");
 }
 return 0;
}
除了非法的内存访问外,valgrind并没有显示出太多的内容:

  

== 22907 ==写入大小4无效   == 22907 ==在0x409CE8D:srandom_r(random_r.c:182)   == 22907 == by 0x80484A1:main(srand_ko.c:10)   == 22907 ==地址0x0未堆叠,malloc'd或(最近)免费

现在查看random_data结构时,您会发现它包含指向状态缓冲区的指针:

struct random_data
  {
    int32_t *fptr;              /* Front pointer.  */
    int32_t *rptr;              /* Rear pointer.  */
    int32_t *state;             /* Array of state values.  */
    int rand_type;              /* Type of random number generator.  */
    int rand_deg;               /* Degree of random number generator.  */
    int rand_sep;               /* Distance between front and rear.  */
    int32_t *end_ptr;           /* Pointer behind state table.  */
  };

如果你使用calloc()进行分配,那么所有这些指针显然都是NULL,srandom_r并不是那么喜欢。 您可以帮助它手动分配状态值数组,并使用random_data将其分配给initstate_r结构。 由于initstate_r已经需要seed,因此您无需再调用srandom_r(但如果您愿意,也可以):

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

#define STATESIZE 64
int main() {
 int seed = time(NULL);
 char*buf = (char*)calloc(STATESIZE, sizeof(char));
 struct random_data *qq = NULL;

 qq = calloc(1, sizeof(struct random_data));
 initstate_r(seed, buf, STATESIZE, qq);
 /* generate some random numbers */
 /* ... */

 srandom_r(seed, qq);
 /* generate the same random numbers again */
 /* ... */

 /* cleanup */
 free(buf);
 free(qq);
 return 0;
}

答案 1 :(得分:1)

您可能希望添加测试calloc()是否成功,因为传递NULL最可能会引发细分违规。

#include <stdlib.h>

...

  struct random_data * qq = calloc(50, sizeof(*qq));
  if (NULL == qq)
    perror("malloc() failed");
  else
    srandom_r(time(NULL), qq);

答案 2 :(得分:1)

'random_data'不包含保存随机数生成器状态的内存-它保存状态为...的状态。

使用random_r的“正确方法”是:

struct random_data rstate;
char random_bin[256];
initstate_r(MY_SEED,random_bin,256,&rstate);

现在您可以调用srandom_r和random_r。

不需要进行任何malloc或calloc的操作,这样做会减慢您的速度,因为每次您生成随机数时都会遇到高速缓存未命中的情况。