为什么在这个C代码中发生堆栈粉碎?

时间:2012-05-25 00:21:35

标签: c stack

我提前道歉,因为我对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有点新,但对其他语言有一些编程经验。

我读过“Stack Smashing实际上是gcc用来检测缓冲区溢出攻击的保护机制”和“这意味着你以非法的方式写入堆栈中的一些变量,很可能是因为Buffer的结果溢出”。

感谢您的回复/答案。

更新 - 根据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 个答案:

答案 0 :(得分: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);

objString是一个空格为strlen("# 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);

SIDE POINT:

为什么要为每行行打开和关闭文件?那是非常低效的......

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

答案 1 :(得分:0)

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

通过显式检查NULL指针。

答案 2 :(得分: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也可以粉碎堆栈,因此请确保目标有足够的空间容纳您正在复制的内容。

答案 3 :(得分:0)

Evan Teran已经回答了这个问题。但我想提出几种方法来发现这些问题:

  • 尝试使用gcc -fno-stack-protector stack.c进行编译,并检查它是否仍然为您提供stack smash detected
  • 对gnu-debugger使用-g标志。作为gcc -g stack.c然后gdb a.out - &gt; run。它会在遇到问题时停止执行。然后,您可以在gdb中键入where,以查看哪一行代码是问题的根源。