没有循环的C程序意外地表现得像一个循环

Min*_*mal 2 c gcc loops

我对这种行为感到困惑和兴奋,我从我的C代码中获取.我不明白这是怎么发生的!在进一步之前,我希望展示代码 -

#include <stdio.h>

int main(){

    char string[2];

    printf("Enter your string here: ");
    gets(string);
    printf("%s \n", string);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

很明显 - 这里没什么特别的.实际上,这是我的计算机,数据和网络安全课程的一项任务,我想在那里演示BufferOverflow.这是我可以创建的最简单的.

当我输入13个字符时,它工作得很好; 15个或更多章程导致所需的BufferOverflow.当我输入14个字符时就会发生灾难.代码开始表现得像一个循环!这就像是main一次又一次地调用这个功能 -

屏幕截图的控制台

我正在使用CodeBlocks-16.01GNU GCC编译器.我也用命令运行它,得到了相同的结果.我还在TutorialsPoint上执行了代码,但没有在那里遇到这个问题.

我不知道发生了什么.这是gcc的问题吗?

Cra*_*tey 7

您的代码生成缓冲区溢出-一个真正的一个.超过结束string可以覆盖[在堆栈上] main应该返回到完成时的返回地址.

如果选择正确,它可以循环回main或跳到内存中的任何位置.实际上它取决于编译器,链接器,加载器,程序加载的地址.

并且,输入的字符串的值(即)某些字符串将崩溃,其他字符串可能会循环,某些字符串可能会产生愚蠢的结果,但不会产生循环.一个字符串可能在给定环境中执行X行为,在另一个环境中执行Y行为.不同的字符串可能会反转这些结果.

你真正想做的是演示(即模拟)缓冲区溢出,而不做任何会导致程序崩溃的事情.

这是一种安全的方法:

#include <stdio.h>

#define SEED     0xFF                   // sentinel value

// NOTE: using a struct guarantees that over will appear directly after string
// (i.e.) over is higher in memory than string
struct buffer {
    char string[4];                     // buffer that can overflow
    unsigned char over[80];             // safe place for the overflow
};

int
main(void)
{
    struct buffer buf;
    int idx;
    int over;

    // prefill the "overflow detection buffer" with a sentinel value (e.g. one
    // that can't be input via fgets [under normal circumstances])
    for (idx = 0;  idx < sizeof(buf.over);  ++idx)
        buf.over[idx] = SEED;

    printf("Enter your string here: ");
    fflush(stdout);

    // NOTE: this fgets will never _really_ cause any harm -- the "10" slop
    // factor guarantees this
    fgets(buf.string,sizeof(buf) - 10,stdin);

    // overflow is anything that ran past string into over
    over = 0;
    for (idx = 0;  idx < sizeof(buf.over);  ++idx) {
        if (buf.over[idx] != SEED) {
            over = 1;
            break;
        }
    }

    if (over)
        printf("buffer overflowed\n");
    else
        printf("buffer did not overflow\n");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

更新:

你应该特别劝告不要使用 gets

通常,我会.由于这个问题的特殊性,我对此持怀疑态度.

(即使他想要一个缓冲区溢出,你应该添加为什么他可能很好地得到一个他不想使用删除的gets函数)

IMO,这在我的示例代码中使用暗示fgets,但可能没有特别推断.所以,够公平的......

在我的示例代码中,使用gets(buf.string)而不是fgetscan /将产生相同的[期望]效果.但是,这仍然不安全的,因为读取的长度仍然没有限制.它可能会超过总结构长度sizeof(string) + sizeof(over) 并产生真正的缓冲区溢出,就像之前一样.

由于您试图导致缓冲区溢出,因此编写代码更容易gets,但您会得到不希望的行为.

[正如其他人所指出的] gets因为这个原因而被弃用.如果您只是想要正常使用,请更换gets(string)fgets(string,sizeof(string),stdin)So,永远不要使用gets并始终使用fgets.

  • 很好的答案,但你应该特别告诫使用`gets`(即使他想要一个缓冲区溢出,你应该添加为什么他很可能得到一个他不想使用删除的`gets`函数).(我看到Lefler在他的评论中涵盖了它 - 没关系) (2认同)