【问题标题】:Getting Segmentation Fault in C program在 C 程序中获取分段错误
【发布时间】:2012-12-05 10:07:56
【问题描述】:

下面代码的第 8 行出现分段错误。

typedef struct _my_struct {
     int pArr[21];      
     int arr1[8191];
     int arr2[8191];
     int m;
     int cLen;
     int gArr[53];  
     int dArr[8191]; 
     int data[4096];
     int rArr[53]; 
     int eArr[1024];

};

void *populate_data(void *arg) {
1   register int mask =1, iG;
2   struct _my_struct *var ;
3   var = arg;                         // arg is passed as initialized struct variable while creating thread
4   var->m = 13;
5   var->arr2[var->m] = 0;
6   for (iG = 0; iG < var->m; iG++) {
7       var->arr2[iG] = mask;
8       var->arr1[var->arr2[iG]] = iG;
9       if (var->pArr[iG] != 0)         // pArr[]= 1011000000001
10          var->arr2[var->m] ^= mask;
11      mask <<= 1;
12  }
13  var->arr1[var->arr2[var->m]] = var->m;
14  mask >>= 1;
15  for (iG = var->m+ 1; iG < var->cLen; iG++) {
16      if (var->arr2[iG - 1] >= mask)
17          var->arr2[iG] = var->arr2[var->m] ^ ((var->arr2[iG- 1] ^ mask) << 1);
18      else
19          var->arr2[iG] = var->arr2[iG- 1] << 1;
20      var->arr1[var->arr2[iG]] = iG;
21  }
22  var->arr1[0] = -1;
   }

这里是线程函数:

void main() {
        unsigned int tid;

        struct _my_struct  *instance = NULL;
        instance = (struct _my_struct  *)malloc(sizeof(_my_struct ));

        start_thread(&tid , 119312, populate_data, instance );          
}

int 
start_thread(unsigned int *tid, int stack_size, void * (*my_function)(void *), void *arg)
{
        pthread_t ptid = -1;
        pthread_attr_t pattrib;

        pthread_attr_init(&pattrib);

        if(stack_size > 0)
        {
            pthread_attr_setstacksize(&pattrib, stack_size);
        }
        else
        {
            pthread_attr_destroy(&pattrib);
            return -1;
        }

        pthread_create(&ptid, &pattrib, my_function, arg);      
        pthread_attr_destroy(&pattrib);

        return 0;
}

一旦我通过gdb调试它,得到这个错误,

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffdfec80700 (LWP 22985)]
0x0000000000401034 in populate_data (arg=0x7fffffffe5d8) at Queue.c:19
19                     var->arr1[var->arr2[iG]] = iG;

它的回溯是:

#0  0x0000000000401034 in populate_data (arg=0x7fffffffe5d8) at Queue.c:159
#1  0x00007ffff7bc6971 in start_thread () from /lib/libpthread.so.0
#2  0x00007ffff792292d in clone () from /lib/libc.so.6
#3  0x0000000000000000 in ?? ()

但是,我无法更正错误。

非常感谢任何帮助。

【问题讨论】:

  • 在 seg 错误之后显示 iGvar-&gt;arr2[iG] 的值可能会给你一个线索...
  • 第一次迭代失败,即 iG =0
  • 好的 - 但是var-&gt;arr2[0] 的值是多少?
  • var-&gt;arr2[iG] 的值不在arr1 的允许索引范围内,因此是段错误。
  • 第 15 行中的 var-&gt;cLen 是什么?找不到这样的结构成员。

标签: c arrays pthreads segmentation-fault


【解决方案1】:

请在start_thread中显示调用代码。

这似乎是堆栈和/或内存分配错误,结构非常大(假设 32 位 ints 为 8 MB)并且很可能会溢出一些堆栈限制。

更有可能是它超出了范围,这就是必须显示调用步骤的原因。

【讨论】:

  • 添加了问题。请看一下
【解决方案2】:

我不知道您是否更改了 _my_struct 中数组的名称以隐藏它们的用途(可能是公司机密信息?),但如果这实际上是您为数组命名的名称,我只是建议你给它们命名一些对你有意义的东西,当有人必须在 4 年后阅读你的代码时,他们会有一些希望遵循你的初始化循环并理解正在发生的事情。您的循环变量 iG 也是如此。

我的下一个评论/问题是,你为什么要启动一个线程来初始化主线程堆栈上的这个结构?一旦初始化,哪个线程将使用这个结构?或者你打算制作其他线程来使用它?您是否有任何机制(互斥量?信号量?)来确保其他线程在您的初始化线程完成初始化之前不会开始使用数据?哪一种引出了问题,你为什么要费心启动一个单独的线程来初始化它?您可以通过直接从 main() 调用 populate_data() 来初始化它,甚至不必担心同步,因为在完成初始化之前您甚至不会启动任何其他线程。如果您在多核机器上运行,您可能会从启动该单独线程以在 main() 继续进行初始化并执行其他操作时获得一些小好处,但从结构的大小(不是很小,但不是也很大)似乎这种好处非常微不足道。而且,如果您在单核上运行,则根本不会获得并发优势;由于上下文切换开销,您只会浪费时间启动另一个线程来执行此操作;在 unicore 环境中,最好直接从 main() 调用 populate_data()。

下一条评论是,您的 _my_struct 并不大,因此它不会自行破坏您的堆栈。但它也不小。如果您的应用程序总是只需要这个结构的一个副本,也许您应该将其设为全局变量或文件范围变量,这样它就不会占用堆栈空间。

最后,到你的实际错误............

我没有费心尝试破译您的神秘循环代码,但 valgrind 告诉我您有一些条件取决于未初始化的位置:

~/test/so$ valgrind a.out
==27663== Memcheck, a memory error detector
==27663== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==27663== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==27663== Command: a.out
==27663==
==27663== Thread 2:
==27663== Conditional jump or move depends on uninitialised value(s)
==27663==    at 0x8048577: populate_data (so2.c:34)
==27663==    by 0x593851: start_thread (in /lib/libpthread-2.5.so)
==27663==    by 0x4BDA8D: clone (in /lib/libc-2.5.so)
==27663==
==27663== Conditional jump or move depends on uninitialised value(s)
==27663==    at 0x804868A: populate_data (so2.c:40)
==27663==    by 0x593851: start_thread (in /lib/libpthread-2.5.so)
==27663==    by 0x4BDA8D: clone (in /lib/libc-2.5.so)

我的 so2.c 第 34 行对应于您上面发布的代码中的第 9 行。 我的 so2.c 第 40 行与您上面发布的代码中的第 15 行相对应。

如果我在 populate_data() 的顶部添加以下内容,这些 valgrind 错误就会消失:

memset(arg,0,sizeof(_my_struct_t));

(我修改了你的结构定义如下:)

typedef struct _my_struct { int pArr[21]; ......... } _my_struct_t;

现在仅仅因为添加 memset() 调用使错误消失并不一定意味着你的循环逻辑是正确的,它只是意味着现在这些位置被 valgrind 视为“初始化”。如果在初始化循环开始时在这些位置有全零是您的逻辑所需要的,那么应该可以解决它。但是您需要自己验证这确实是正确的解决方案。

顺便说一句...有人建议使用 calloc() 来获得归零分配(而不是使用脏堆栈空间)...这也可以,但是如果您希望 populate_data() 万无一失,您将将其中的内存归零而不是调用者的内存,因为(假设您喜欢初始化逻辑),populate_data() 是取决于它被归零的东西,main() 不必关心它是否是或不。无论哪种方式都不是什么大问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    • 2018-11-18
    • 2011-05-23
    • 2021-12-02
    相关资源
    最近更新 更多