4

对于我缺乏关于 C 中堆栈粉碎的知识,我提前道歉。我正在使用 Code::Blocks 进行 ubuntu 12.04 编辑。我编写了一个简单的 C 程序,它会导致堆栈粉碎,但互联网搜索几乎没有找到关于为什么会发生这种情况的有用建议。

示例 C 代码:

#include<stdio.h>

struct point3
    {float x, y, z;};

struct quadPolygon
    {struct point3 vert1, vert2, vert3, vert4;};

int writeLine(const char * objString)
    {FILE *file; file = fopen("aPlane.obj","a+"); fprintf(file,"%s",objString); fclose(file); return 0;};

int writeOBJ(struct quadPolygon myPoly)
    {
    char objString[] = "# plane def\n";  writeLine(objString);

    snprintf(objString, 128, "v %f %f %f \n", myPoly.vert1.x, myPoly.vert1.y, myPoly.vert1.z);  writeLine(objString);
    snprintf(objString, 128, "v %f %f %f \n", myPoly.vert2.x, myPoly.vert2.y, myPoly.vert2.z);  writeLine(objString);
    snprintf(objString, 128, "v %f %f %f \n", myPoly.vert3.x, myPoly.vert3.y, myPoly.vert3.z);  writeLine(objString);
    snprintf(objString, 128, "v %f %f %f \n", myPoly.vert4.x, myPoly.vert4.y, myPoly.vert4.z);  writeLine(objString);

    char objStringSmooth[] = "s off\n";  writeLine(objStringSmooth);
    char objStringFace[] = "f 1 2 3 4\n";  writeLine(objStringFace);
    return 0;
    };

int main()
{
    struct quadPolygon myPoly1 =
    {
    .vert1.x=1.0, .vert1.y=-1.0, .vert1.z=0.0,
    .vert2.x=1.0, .vert2.y=1.0, .vert2.z=0.0,
    .vert3.x=-1.0, .vert3.y=1.0, .vert3.z=0.0,
    .vert4.x=-1.0, .vert4.y=-1.0, .vert4.z=0.0
    };
    writeOBJ(myPoly1);
    return 0;
};

为什么堆栈粉碎,我该如何更改我的代码以避免这种情况?这与在上面的代码中错误地使用指针有关吗?正如您可能知道的那样,我对 C 有点陌生,但对其他语言有一些编程经验。

我读过“堆栈粉碎实际上是 gcc 用于检测缓冲区溢出攻击的一种保护机制”和“这意味着您以非法方式写入堆栈上的某些变量,很可能是缓冲区溢出的结果”。

感谢您的任何回复/回答。

更新 - 根据 Evan 的评论,这里是修改后的代码。也许这可能对其他人有所帮助。

#include<stdio.h>

struct point3
    {float x, y, z;};

struct quadPolygon
    {struct point3 vert1, vert2, vert3, vert4;};

int writeOBJ(struct quadPolygon myPoly)
    {
    FILE *file; file = fopen("aPlane.obj","a+");
    fprintf(file,"%s","# plane def\n");
    char objString[128];
    snprintf(objString, sizeof(objString), "v %f %f %f \n", myPoly.vert1.x, myPoly.vert1.y, myPoly.vert1.z);
        fprintf(file,"%s",objString);
    snprintf(objString, sizeof(objString), "v %f %f %f \n", myPoly.vert2.x, myPoly.vert2.y, myPoly.vert2.z);
        fprintf(file,"%s",objString);
    snprintf(objString, sizeof(objString), "v %f %f %f \n", myPoly.vert3.x, myPoly.vert3.y, myPoly.vert3.z);
        fprintf(file,"%s",objString);
    snprintf(objString, sizeof(objString), "v %f %f %f \n", myPoly.vert4.x, myPoly.vert4.y, myPoly.vert4.z);
        fprintf(file,"%s",objString);
    char objStringSmooth[] = "s off\n";
        fprintf(file,"%s",objStringSmooth);
    char objStringFace[] = "f 1 2 3 4\n";
        fprintf(file,"%s",objStringFace);
    fclose(file);
    return 0;
    };

int main()
    {
    struct quadPolygon myPoly1 =
        {
        .vert1.x=1.0, .vert1.y=-1.0, .vert1.z=0.0,
        .vert2.x=1.0, .vert2.y=1.0, .vert2.z=0.0,
        .vert3.x=-1.0, .vert3.y=1.0, .vert3.z=0.0,
        .vert4.x=-1.0, .vert4.y=-1.0, .vert4.z=0.0
        };

    writeOBJ(myPoly1);
    return 0;
    };

再次感谢大家。

4

4 回答 4

6

这是您的问题所在:

char objString[] = "# plane def\n";  writeLine(objString);

snprintf(objString, 128, "v %f %f %f \n", myPoly.vert1.x, myPoly.vert1.y, myPoly.vert1.z);  writeLine(objString);
snprintf(objString, 128, "v %f %f %f \n", myPoly.vert2.x, myPoly.vert2.y, myPoly.vert2.z);  writeLine(objString);
snprintf(objString, 128, "v %f %f %f \n", myPoly.vert3.x, myPoly.vert3.y, myPoly.vert3.z);  writeLine(objString);
snprintf(objString, 128, "v %f %f %f \n", myPoly.vert4.x, myPoly.vert4.y, myPoly.vert4.z);  writeLine(objString);

objStringstrlen("# plane def\n") + 1是一个包含空格字符的数组。然后你使用snprintf那​​个缓冲区传递128(它太大了)。

我会这样重写它:

writeLine("# plane def\n");

char objString[128]
snprintf(objString, sizeof(objString), "v %f %f %f \n", myPoly.vert1.x, myPoly.vert1.y, myPoly.vert1.z);  writeLine(objString);
snprintf(objString, sizeof(objString), "v %f %f %f \n", myPoly.vert2.x, myPoly.vert2.y, myPoly.vert2.z);  writeLine(objString);
snprintf(objString, sizeof(objString), "v %f %f %f \n", myPoly.vert3.x, myPoly.vert3.y, myPoly.vert3.z);  writeLine(objString);
snprintf(objString, sizeof(objString), "v %f %f %f \n", myPoly.vert4.x, myPoly.vert4.y, myPoly.vert4.z);  writeLine(objString);

侧点:

你为什么要为每一行打开和关闭文件?真是太低效了……

最好在程序启动时打开文件一次,写下所有行,然后在完成后关闭它。这也将使代码更简单。

于 2012-05-25T00:26:04.203 回答
0

正如 Evan Teran 已经回答的那样。但我想提出几种检测此类问题的方法:

  • 尝试编译 usinggcc -fno-stack-protector stack.c并检查它是否仍然为您提供stack smash detected.
  • 为 gnu 调试器使用-g标志。作为gcc -g stack.c然后gdb a.out-> run。它将在出现问题的地方停止执行。然后你可以输入wheregdb 来查看哪一行代码是问题的根源。
于 2012-05-25T00:34:27.627 回答
0

FILE*您可以通过fopen.. 确认您获得了有效的

通过显式检查NULL指针。

于 2012-05-25T00:30:02.463 回答
0

问题出在以下行:

char objString[] = "# plane def\n";

这只会为字符串“# plane def\n”分配足够的空间,然后,您将更长的字符串写入其中(使用 snprintf)。

既然您已经在使用常量值 128,那么如何:

char objString[128];
strcpy(objString, "# plane def\n");
writeLine(objString);
/* continue as before */

请注意, strcpy 也可以破坏堆栈,因此请确保目标有足够的空间用于您要复制的任何内容。

于 2012-05-25T00:30:53.403 回答