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

C Program with No Loop Is Unexpectedly Behaving Like a Loop

我对从我的 C 代码中获得的这种行为感到既困惑又兴奋。我不明白这到底是怎么回事!在进一步讨论之前,让我们看一下代码-

#include <stdio.h>

int main(){

    char string[2];

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

    return 0;
}

很明显-这里没有什么特别的。实际上,这是我的计算机、数据和网络安全课程的作业,我应该在其中演示 BufferOverflow。

直到13个字符都可以正常工作; 15 个或更多章程会导致所需的 BufferOverflow。 当我正好输入 14 个字符时,灾难发生了:代码开始表现得像一个循环! 就像 main 函数被一次又一次地调用-

我正在使用 CodeBlocks-16.01GNU GCC 编译器。我也在 TutorialsPoint 上执行了代码,但没有在那里遇到这个问题。

您的代码产生缓冲区溢出——真实。越过 string 的末尾可以覆盖 return 地址 [在堆栈上],main 应该 return 到完成时。

如果选择正确,它可以循环回到 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;
}

更新:

you should specifically admonish against the use of gets

通常情况下,我会的。由于这个问题的特殊性,我对此持观望态度。

(even though he wants a buffer overflow, you should add why he may very well get one he doesn't want using the removed gets function)

IMO,这是通过在我的示例代码中使用 fgets 暗示,但可能没有具体 推断.所以,很公平......

在我的示例代码中,使用 gets(buf.string) 而不是 fgets could/would 会产生相同的 [desired] 效果。但是,这 stillunsafe 因为读取的长度仍然没有限制。它可以 运行 超过总结构长度 sizeof(string) + sizeof(over) 并像以前一样产生 真正的 缓冲区溢出。

由于您试图导致缓冲区溢出,使用gets编码更容易,但您得到了不希望的行为。

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