c++ 未定义的行为是否可以擦除硬盘?

lztngnrs  于 2023-05-24  发布在  其他
关注(0)|答案(8)|浏览(158)

《Effective C++ 3rd edition》作者:Scott Meyers
为了强调未定义行为的结果是不可预测的,并且可能非常不愉快,有经验的C程序员经常说,具有未定义行为的程序可以擦除您的硬盘驱动器。
在什么情况下会发生这种情况?
例如,访问和写入数组范围之外的位置是否会损坏不属于此C
程序或线程的内存?

mgdq6dx1

mgdq6dx11#

是吗?当然。事实上,我也是。
我写了代码来删除一个临时目录。这涉及到创建recursive delete <temp directory>\*.*命令。由于一个bug,<temp directory>字段并不总是被填充。我们的文件系统代码愉快地执行了recursive delete \*.*命令。
我的同事们注意到他们桌面上的图标突然消失了。干掉了两台机器。

db2dz4w8

db2dz4w82#

如果考虑到UB不仅对用户模式代码可用,而且对系统程序员也可用。换句话说,如果你用UB(或其他bug!)中,您可能最终会写入一段内存,该内存稍后将作为“整个磁盘数据结构的根”写回。
我确实有一个错误的驱动程序,我的工作,导致磁盘损坏,因为驱动程序使用陈旧的指针(指针使用后自由)。如果您运气不好,未使用的内存恰好是文件系统拥有的块,因此它会将一些随机垃圾写回磁盘。幸运的是,确定问题所在并不太困难,我只需要在测试系统上重新格式化磁盘一次(在处理驱动程序时,通常使用两台计算机,一台用于构建代码,另一台用于测试代码-测试机器通常具有最小的安装集,并且经常相对频繁地重新格式化和重新配置)。
我不认为Scott的提到一定意味着这种情况,但如果你有足够野生的代码,它完全有可能导致几乎任何事情发生。包括查找安全系统中的漏洞(参见所有成功的堆栈粉碎漏洞)。你可能要非常不幸才能实现这一点,但人们也不时地赢得那些超级彩票,所以如果你能实现的东西,有数百万的机会一周一次或一个月一次,那么一台计算机,可以执行数百万次的操作每秒可以实现不太可能的事情。

hujrc8aj

hujrc8aj3#

来自 *C++11标准 *(实际上来自草案N3337),在第1.3节术语和定义[intro.defs](强调我的):

未定义行为

本国际标准规定的行为无要求
[ * 注:* 当本国际标准省略了任何明确的行为定义或当程序使用错误的结构或错误的数据时,可能会出现未定义的行为。允许的未定义行为包括完全忽略情况并产生不可预测的结果,在翻译或程序执行期间以环境特征的记录方式行为(有或没有发出诊断消息),终止翻译或执行(发出诊断消息)。许多错误的程序构造不会产生未定义的行为;他们需要被诊断。- * 结束注解 * ]
从“无需求”+“不可预测的结果”中,我们可以得出结论(理论上)* 任何事情都可能发生
现在,没有一个“合理的”编译器会故意发出代码来擦除硬盘驱动器,例如,除以0,但是如果你弄乱了文件系统,或者确实,正如你所说,如果你破坏了内存(
编辑:* 见MSalters对他们自己的答案的评论),这可能会发生。
这里的重点是:* 始终要小心永远不要调用未定义的行为 *。“这里有龙”
(In在实践中,很难确定你的程序是定义良好的。给你点建议。熟悉你的语言,远离尘土飞扬的角落。如果一段代码看起来可疑或过于复杂,请尝试重写它,使其更简单,更清晰。始终使用最高级别的警告进行编译,并且不要忽略它们。还有像-fcatch-undefined-behavior这样的编译器标志和像lint这样的工具可以提供帮助。当然还有测试,但有点晚了。)

q8l4jmvw

q8l4jmvw4#

内存冲突理论上会导致程序执行错误的代码。如果你非常不走运,它可能是删除硬盘上内容的代码。我怀疑它不太可能走那么远,除非您自己处理低级磁盘操作。
我认为这句话的意思是,你需要非常认真地对待未定义的行为,并采取一切实际措施来防范它(即。防御性编程)。我见过太多糟糕的程序员天真地依赖于一些未定义的行为,认为它会一直工作。在实践中,它是不可预测的,有时结果可能是灾难性的。

djp7away

djp7away5#

一个简单的例子是,您碰巧损坏了要写入的块号或要删除的文件名。

mkshixfv

mkshixfv6#

是的
考虑一个处理外部输入的应用程序(例如Web应用程序的组件),它具有缓冲区溢出,这是一种相当常见的未定义行为类型。
攻击者会注意到这一点,并故意制作删除所有数据的输入。(大多数攻击者实际上不会这样做:他们想要做的是检索您的数据,或在您的网站上植入内容。但偶尔有些人确实想删除您的文件。)
破坏的最大程度取决于攻击者能够绕过哪些安全层。如果服务器未进行安全配置,或者存在攻击者能够利用的其他漏洞,则攻击者可能能够获得该机器上的管理员权限,或者将其用作攻击其他机器的中继。所有这一切都来自一个单一的缓冲区溢出。
从这一点中得到的教训是,未定义的行为不仅仅是关于可能发生的事情。不仅会发生你意想不到的事情(一些编译器非常擅长挑选奇怪的优化,只有当变量在序列点之间没有被修改两次时才是正确的,否则会做一些非常令人惊讶的事情),而且会发生数学上极不可能的事情,因为有人故意让它们发生。

nwlls2ji

nwlls2ji7#

Linux中,当您是root用户时,任何操作都有效。甚至破坏你的根文件系统。rm -rf /
当你是root时,每一个代码段(有bug)都会被愉快地执行。所有UB都假定具有sudo权限。

w41d8nur

w41d8nur8#

呃,无意冒犯,但根据我的经验,其他几个答案是错误的,或者至少是误导性的。
C标准不限制未定义的行为。然而,操作系统通常会限制它。原因:行为是未定义的 * 相对于C。*
...始终要小心,永远不要调用未定义的行为。
胡说,经验证明这个建议是错误的。C程序员经常在测试过程中不经意地调用未定义的行为。有时候我是故意的,只是想看看会发生什么。
现在,我意识到有人认为我在这里炫耀鲁莽,但实际上,你的笔记本电脑几乎没有更容易着火的未定义比定义的行为。C
中的未定义行为发出具有 defined 行为的汇编代码。想想吧部件行为保持定义状态。只是C标准不再理解机制。
有时候你想引发未定义的行为,只是为了看看堆栈上发生了什么。
如果你所处的环境中有可能编写一个 defined 的C
程序,让你的笔记本电脑着火,那么无论如何你都要小心;但是在这种情况下的主要问题是缺乏基于硬件和/或内核的保护。
总之,不要让C++标准迷惑你。它只是告诉你它自己的能力极限是什么。

相关问题