C语言 什么是堆栈粉碎,我该如何解决?



该程序的目的是通过测试其与前 11 个素整数的可除性来确定 1 到 1000 之间的数字是否为素数。该程序在大多数输入下正常运行。但是,当我输入诸如 468 之类的整数时,会检测到堆栈粉碎。什么是堆栈粉碎,如何解决问题?

我尝试过研究堆栈粉碎,但我找不到与我的程序相关的具体示例。我不知道我可以尝试修改程序的替代方法,因为我对使用 C 编程相对较新。

char divStatement[] = " is divisible by ";
if ((userInput % 31) == 0) {
div31 = true;
strcat(divStatement, "31, ");
}
if (div2 || div3 || div5 || div7 || div11 || div13 || div17 || div19 || div23 || div29 || div31) {
divStatement[strlen(divStatement) - 2] = '.';
divStatement[strlen(divStatement) - 1] = 'n';
printf("%d%s", userInput, divStatement);
printf("%d is not prime.n", userInput);
}
else {
printf("%d is prime.n", userInput);
}

输出实际上工作正常。但是,在程序结束时,终端输出:

***stack smashing detected ***: ./a.out terminated 
Aborted
char divStatement[] = " is divisible by ";
if ((userInput % 31) == 0) {
div31 = true;
strcat(divStatement, "31, ");
}

divStatement是一个恰好足够大的字符数组,可以容纳" is divisible by "和一个终止符。您无法向其追加"31, ",因为它没有任何额外的松弛空间。

一个简单的解决方法是给数组一个明确的长度,该长度足够大,可以处理程序可能追加的任何内容。

char divStatement[1000] = " is divisible by ";

由于编译器使用的内存保护机制,返回堆栈粉碎错误。您可以禁用此功能,但这会导致所谓的堆栈缓冲区溢出攻击利用的漏洞(请参阅youtube上的此计算机文件的视频(。

您不是使用特定大小声明字符数组,但由于您使用字符串文本对其进行初始化,因此divStatement字符数组的大小设置为 18 字节(17 表示" is divisible by "中的字符,1 表示"",即用于字符串终止的所谓空字符(。来自 C99 标准 6.4.5/5"字符串文字 - 语义"(如对此问题的回答中所引用(:

然后,使用多字节字符序列初始化静态存储持续时间和长度刚好足以包含该序列的数组。

粗略地说,编译器知道内存中应该只有 18 个字节保留给这个特定的字符数组,因此写入数组不应该修改超过其第 18 个字节的数据(出于安全原因(。当您连接字符串时,您实际上是在尝试写入超过 18 个字节,这会触发安全机制,进而导致错误。

由于您只测试 1 到 1000 之间的数字,并且只测试前 11 个质数,因此您知道质数最多为 3 个字符。加上", ",这将添加额外的 5 个字符,因此总共 18 + 5 = 23 个字符。因此,通过将divStatement显式声明为大小为23的字符数组,即divStatement[23] = " is divisible by "来轻松解决您的问题。至于获得关于你的代码的更一般的反馈,你应该看看代码审查社区。

这不是你问题的答案,而是你应该问的问题的部分答案。我厌倦了想出一个适当的解释。但是你需要在代码中的某个地方这样的东西:

if ((userInput % n) == 0)
{
printf("%d is divisible by %dn", userInput, n);
is_prime == 0;
}

拥有所有 11 个前素数的数组可能也是一个好主意:

const int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};

我不会通过告诉您如何将其包装在一个循环中以及如何声明/初始化nis_prime来破坏所有 7 个乐趣。享受家庭作业的乐趣。我希望截止日期不会太早:-(

Stack Smashing的定义,发表于:https://www.techopedia.com/definition/16157/stack-smashing

定义 - 堆栈粉碎是什么意思?

*堆栈粉碎是一种漏洞形式,其中计算机应用程序或操作系统的堆栈被迫溢出。这可能会导致破坏程序/系统并使其崩溃。

堆栈,即先进后出电路,是一种缓冲器形式,其中包含操作的中间结果。为了简化起见,堆栈粉碎将更多的数据放入堆栈中,而不是其容纳容量。熟练的黑客可以故意将过多的数据引入堆栈。过多的数据可能存储在其他堆栈变量中,包括函数返回地址。当函数返回时,它会跳转到堆栈上的恶意代码,这可能会损坏整个系统。堆栈上的相邻数据受到影响,并迫使程序崩溃。

关于:

char divStatement[] = " is divisible by ";

strcat(divStatement, "31, ");

strcat()的调用试图将字符串 "31, " 附加到仅足以容纳字符串的数组中:"可被 "整除。 结果是数组溢出。 这种溢出是未定义的行为。 在这种情况下,它损坏了堆栈,可能就在某个堆栈帧或其他链接所在的位置

相关内容

  • 没有找到相关文章

最新更新