是否有可能以某种方式使该程序崩溃?

Posted

技术标签:

【中文标题】是否有可能以某种方式使该程序崩溃?【英文标题】:Is it possible to crash this program somehow? 【发布时间】:2020-09-24 15:11:56 【问题描述】:

我目前正在大学的一门课程中学习 C。现在我们有一个任务要解决,我不知道该怎么做。

任务如下所示: “是否有可能让这个程序因用户输入而崩溃?如果是,请解释这种情况。”

我们得到的程序很简单,看起来像这样:

#include <stdio.h>  // Include to use printf, scanf

int main()

    // Define buffers to store user name and password
    char username[16];
    char password[16];

    // Read username and password from user input
    printf("Enter your name: ");
    scanf("%s", username);
    printf("Enter your password: ");
    scanf("%s", password);
    printf("[SHOUTING OUT LOUD] Hello, %s!\n", username);

    return 0;
   

我已经发现,如果您使用的用户名超过 15 个字符,您可以让程序打印出密码。但这显然不是崩溃。 所以我还没有找到使程序崩溃的方法,但不知何故,我很确定,有办法做到这一点。 有人知道吗?

谢谢:)

【问题讨论】:

ctrl+c 算不算? 问你这个问题的人可能是在掩饰细节或不完全理解 C。看起来你的意图是让你溢出缓冲区。但这并不能保证崩溃。请参阅已发布的有关未定义行为的答案。 "但这显然不是崩溃。" - 分段错误运行时错误在您看来不是崩溃吗? 好吧,从理论上讲,崩溃“可能”发生。但是写入足够长的用户名以覆盖堆栈区域,尤其是返回地址会导致崩溃。 我已经绑定输入超过 15 个字符,在我的情况下没有错误或崩溃。打印的结果不正确,但我已经预料到了。所以我接下来尝试的是输入大量字符,现在在某个时候我的程序停止工作并告诉我*** stack smashing detected ***: &lt;unknown&gt; terminated Aborted...这更有可能是我想要的。但是有没有一个原因,为什么它发生在特定数量的字符上,这些字符也更高,然后是我的数组的 15+15 个字符? 【参考方案1】:

输入超过 15 个字符的用户名或密码可能使程序崩溃,但不能保证这样做。

当你写超出数组的边界时,你调用undefined behavior。粗略地说,这意味着你不能对你的程序会做什么做出任何假设。它可能会崩溃,它可能会输出奇怪的结果,或者它可能看起来工作正常。

仅仅因为程序可能崩溃并不一定意味着它


话虽如此,鉴于您可能遇到的大多数编译器的工作方式,您输入的字符串越长,就越有可能崩溃。

局部变量通常分配在彼此相邻的堆栈上。例如,假设username 在堆栈上紧接在password 之前。如果您为用户名输入 20 个字符的名称,它会将 username 之后的内容写入 password,而 username 将不包含空终止字节。当您输入密码时,它将覆盖用户名前 16 个字符之后的任何字符。然后当您打印 username 时,您将看到您输入的前 16 个字符和密码。

现在假设您输入 100 个字符作为用户名。这将写过去username 和过去password,并且很可能会覆盖main 的返回地址。然后当main 尝试返回时读取了一个虚假地址,并尝试跳转到该地址是导致崩溃的原因。

但同样,这都是系统特定的,并且可能会根据您放置变量的类型/顺序、您调用的函数以及您用于编译的优化设置等而有所不同。

【讨论】:

超出缓冲区边界的写入操作是否总是在运行时导致分段错误错误? @RobertSsupportsMonicaCellio,不,不会。在可以写入的数组之后可能有未使用的内存。虽然是非法的,但在这种情况下它不会使程序崩溃。 @PaulOgilvie 我对此不太确定。 AFAIK 错误已经出现在 attempt 越界写入。 -> ***.com/a/2346816/12139179 @RobertSsupportsMonicaCellio 不,请参阅我的编辑以了解可能发生的情况。 @RobertSsupportsMonicaCellio OP 说“我已经发现,如果您使用超过 15 个字符的用户名,您可以让程序打印出密码”。这是一个明显的例子,即使缓冲区溢出也不会崩溃。【参考方案2】:

如果您在每个环境中输入超过 15 个字符,它不一定会崩溃。这取决于它是否使用了系统上无法访问的内存。

未定义的行为

如果分配给内存之后的连续内存区域 您的字符串为空或当前未被任何其他人使用/无人认领 在您运行程序时处理,然后写给他们 不会显示任何效果。

但是当您在其他时间运行它时,分配区域之后的内存位置可能被其他进程/程序占用/使用,这可能会导致您的程序崩溃。 p>

由于这种行为是不可预测的,因此被称为未定义行为

请记住,C 不会进行内存边界检查,这就是它运行良好的原因。但是当您输入 > 15 个字符时,您的程序可能随时崩溃。在其他编程语言中,通过严格的检查,在这种情况下您可能会遇到异常。

希望这会有所帮助!

注意:在 Windows 上,如果您愿意将此视为崩溃,则 ctrl+C 是您的最佳选择。一直休息,如果您的程序会崩溃,那将是不确定

【讨论】:

“被其他进程/程序占用/使用”:这在现代架构上是不可能的,因为每个程序/进程都将获得自己的(虚拟)内存。 如果您定义类似 -char username[16] 的内容,用户名将在您的存储空间中分配 16 字节的内存。但是当我们输入超过 16 个字符时,它会在分配的内存结束后立即写入内存。该内存可能已使用/未使用,并且取决于此,程序将运行或异常终止。这就是我一直以来的想法。如果我在任何地方错了,请纠正我 您应该更清楚地说明第二个项目符号。如所写,这是我评论为不正确的。它可能正在被程序的另一部分使用,但未被其他程序使用。 我不清楚。在任何情况下它都没有可能成为其他程序的一部分吗? “C 不做内存边界检查”可能会误导。 C 可以进行内存溢出检查——这不是必需的。【参考方案3】:

但这显然不是崩溃。所以我还没有找到崩溃的方法 该程序,但不知何故,我很确定,有办法做 这。有人知道吗?

好吧,如果你真的需要“完全崩溃”试试:

MyProg < SomeLargeFile

【讨论】:

以上是关于是否有可能以某种方式使该程序崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

检测我的Mac应用程序是否崩溃,然后继续正常崩溃

监控程序崩溃

故意崩溃的代码[重复]

如何知道android应用程序上次是不是崩溃

程序崩溃后是否可以执行代码?

如何以编程方式使 Android 应用程序崩溃?