简体   繁体   English

C - Function 调用本身导致递归调用中的段错误

[英]C - Function call itself causes segfault in recursive calls

Im fighting a segfault error that I can't understand: I have a recursive function that expands on an array representing pixels: starting on an index, it exepands around the index to create groups of pixels by calling the same function left right up and down (aka index -1, index +1...).我正在与我无法理解的段错误作斗争:我有一个递归 function,它在表示像素的数组上展开:从索引开始,它围绕索引展开,通过调用相同的 function 左右上下来创建像素组(又名索引-1,索引+1 ...)。 For debuging purposes, I have a printf call at the very first line of the function, and one just before each of the 4 recursive calls.出于调试目的,我在 function 的第一行有一个 printf 调用,并且在 4 个递归调用中的每一个之前都有一个调用。 What I dont get is, I end up with a segfault during the recursion at the recrusive call itself (I get the print that is just before the call, but not the one at function start).我没有得到的是,在递归调用本身的递归过程中,我最终遇到了段错误(我得到了调用之前的打印,但不是 function 开始时的打印)。

void explore(Pixel * array, int j, Tache * cur_pound, int * it, Pixel previous){
    printf("%d\n", j); // I DONT GET THIS PRINT AT LAST RECURSIVE CALL
    // out of bounds
    if(j > sizeX * sizeY)
        return;

    // allready explored index
    if(array[j].explored == 1){
        return;
    }

   // to big of a color difference between this pixel and the reference one
   if(abs((int)array[j].r - previous.r) > SEUIL || abs((int)array[j].g - previous.g) > SEUIL || abs((int)array[j].b - previous.b) > SEUIL){
      return;
   }

   array[j].explored = 1;
   cur_pound->limits[* it] = j;
   (* it)++;

  // recursion
  if(j +1 < sizeX * sizeY && array[j+1].explored != 1){
        printf("before SF\n); // I GET THIS PRINTF
        explore(array, j + 1, cur_pound, it, previous);
  }
  // 3 other recursive calls removed for simplicity here
}

About my data structures: a Tache * is struct that contains 3 GLubytes and limits , an int * that represents every pixel index that belongs to this group.关于我的数据结构: Tache *是包含 3 GLubytes 和limitsstruct ,一个int *表示属于该组的每个像素索引。 A Pixel contains 3 GLubytes and a char that represents if this pixel has already been visited by the function.一个Pixel包含 3 GLubytes 和一个char ,表示该像素是否已被 function 访问过。 The array given to the function as the first argument is an array of Pixel that represent my image.给 function 作为第一个参数的array是代表我的图像的Pixel数组。 it is an int representing the index in the group so that my function knows where on the array it should add a new index. it是一个表示组中索引的int ,以便我的 function 知道它应该在数组的哪个位置添加新索引。 Limits are initialised at -1 outside this function and are allocated with malloc(size * sizeof(int)) where size is the width of the image multiplied by its height. Limits在此 function 之外初始化为-1 ,并分配有malloc(size * sizeof(int))其中size是图像的宽度乘以它的高度。

This is how the inital call is done:这是完成初始调用的方式:

void taches_de_couleur(Image *i){
    int j, k, y, size, it;
    GLubyte * im;
    Pixel * array;

    sizeX = i->sizeX;
    sizeY = i->sizeY;  
    k = 0;
    size = sizeX * sizeY;
    array = malloc(size * sizeof(Pixel));
    im = i->data;

   /* build the array from image data */
   for(j = 0; j < 3 * size; j+= 3){
       array[k].explored = 0;
       array[k].r = i->data[j];
       array[k].g = i->data[j + 1];
       array[k].b = i->data[j + 2];
       k++;
    }

    Tache * new_pound;
    new_pound = malloc(sizeof(Tache));
    new_pound->limits = malloc(size * sizeof(int));
    int x= 0;
    while(x < size){
        new_pound->limits[x] = -1;
        x++;
    }
    it = 0;
    explore(array, 0, new_pound, &it, array[0]);
}

Note that the program does not produce any SF when working with small images (biggest i could do was 512x384px).请注意,该程序在处理小图像时不会产生任何 SF(我能做的最大的是 512x384px)。 This thing has been giving me a headache for a week now, can't figure out what is causing this segfault and thats why im asking you guys if you can see anything obvious here.这件事让我头疼了一个星期,无法弄清楚是什么导致了这个段错误,这就是为什么我问你们是否可以在这里看到任何明显的东西。 I can add the second function that calls explore if need be, but this part seems to be good.如果需要,我可以添加调用 explore 的第二个 function,但这部分似乎很好。

EDIT: this is the output gdb gives me when I run it with a image too big:编辑:这是 output gdb 当我用太大的图像运行它时给我的:

Thread 1 "palette" received signal SIGSEGV, Segmentation fault.
0x00007ffff7b730be in __GI___libc_write (fd=1, buf=0x555555592770, 
nbytes=7)
at ../sysdeps/unix/sysv/linux/write.c:26
26  ../sysdeps/unix/sysv/linux/write.c: No such file or directory.

EDIT: Since im failing to provide enough ressources, see https://github.com/BruhP8/TachesDeCouleur for the full project Thanks in advance编辑:由于我未能提供足够的资源,请参阅https://github.com/BruhP8/TachesDeCouleur获取完整项目提前致谢

What I dont get is, I end up with a segfault during the recursion at the recrusive call itself (I get the print that is just before the call, but not the one at function start).我没有得到的是,在递归调用本身的递归过程中,我最终遇到了段错误(我得到了调用之前的打印,但不是 function 开始时的打印)。

That is an almost sure sign of stack exhaustion.这几乎肯定是堆栈耗尽的迹象。

Run your program under debugger, and examine the instruction which causes segfault.在调试器下运行您的程序,并检查导致段错误的指令 Chances are, it will be one of stack manipulation instructions ( CALL , PUSH ), or a stack dereference instruction that follows stack decrement.很有可能,它将是堆栈操作指令( CALLPUSH )之一,或堆栈减量之后的堆栈取消引用指令。 You can also look at the value of $SP register, and compare it to the bounds of stack segment (from /proc/$pid/maps if you are on Linux).您还可以查看$SP寄存器的值,并将其与堆栈段的边界进行比较(如果您在 Linux 上,则来自/proc/$pid/maps )。

The code you've shown does not appear to allocate any stack, so the problem is likely in the code you omitted.您显示的代码似乎没有分配任何堆栈,因此问题可能出在您省略的代码中。

Note that the program does not produce any SF when working with small images请注意,该程序在处理小图像时不会产生任何 SF

That is another sign: you are probably allocating a new image on the stack, and the larger the image, the fewer levels of recursion you can achieve.这是另一个迹象:您可能正在堆栈上分配一个新图像,并且图像越大,您可以实现的递归级别越少。

PS On Linux, default stack size is often 8MiB. PS 在 Linux 上,默认堆栈大小通常为 8MiB。 Try ulimit -s unlimited -- if that allows the program to recur deeper, that would be a sure sign that my guess is correct.试试ulimit -s unlimited ——如果这能让程序更深入地重现,那肯定表明我的猜测是正确的。 But don't use ulimit -s unlimited as a fix (it's not).但是不要使用ulimit -s unlimited作为修复(不是)。

Update:更新:

With the full source code, I was able to build the palette program.使用完整的源代码,我能够构建palette程序。 Each recursive call to explore only takes 48 bytes of stack (which isn't much).每次递归调用explore只需要 48 个字节的堆栈(不多)。

But with default 8MiB stack, that limits the total recursion to (8 << 20) / 48 == 174762 levels deep.但是使用默认的 8MiB 堆栈,这将总递归限制为(8 << 20) / 48 == 174762层深。

TL;DR: if your recursive procedure requires one level of recursion per pixel , then you would not be able to process large images. TL;DR:如果您的递归过程需要每像素一级递归,那么您将无法处理大图像。 You must rewrite the procedure to be iterative instead.您必须将过程重写为迭代。

It seems the first boundary check in your code should be:您的代码中的第一个边界检查似乎应该是:

if( j >= sizeX * sizeY )

and not并不是

if( j > sizeX * sizeY )

(As the last element of your array is array[size - 1] and not array[size]) (因为数组的最后一个元素是数组 [size - 1] 而不是数组 [size])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM