Fre*_*ios 7 lifetime undefined-behavior rust
Rust不允许使用这种代码,因为它不安全:
fn main() {
let mut i = 42;
let ref_to_i_1 = unsafe { &mut *(&mut i as *mut i32) };
let ref_to_i_2 = unsafe { &mut *(&mut i as *mut i32) };
*ref_to_i_1 = 1;
*ref_to_i_2 = 2;
}
Run Code Online (Sandbox Code Playgroud)
如何通过对同一事物的多个可变引用来做一些不好的事情(例如,分段错误,未定义的行为等)?
我能看到的唯一可能的问题来自数据的生命周期.在这里,如果i是活着的,每个可变引用都应该没问题.
我可以看到引入线程时可能会出现什么问题,但是为什么即使我在一个线程中执行所有操作也会阻止它?
Dan*_*lme 12
在C++程序中,甚至在Java程序中,一个非常常见的陷阱是在迭代它时修改集合,如下所示:
for (it: collection) {
if (predicate(*it)) {
collection.remove(it);
}
}
Run Code Online (Sandbox Code Playgroud)
对于C++标准库集合,这会导致未定义的行为.也许迭代将一直有效,直到你到达最后一个条目,但最后一个条目将取消引用悬空指针或读取数组的末尾.也许集合中的整个数组将被重新定位,并且它将立即失败.也许它大部分时间都有效,但如果在错误的时间重新分配则会失败.在大多数Java标准集合中,根据语言规范,它也是未定义的行为,但是集合往往会抛出ConcurrentModificationException- 即使代码正确也会导致运行时成本的检查.这两种语言都不能在编译期间检测到错误.
这是由并发引起的数据竞争的常见示例,即使在单线程环境中也是如此.并发不仅仅意味着并行:它还可以意味着嵌套计算.在Rust中,在编译期间检测到这种错误,因为迭代器具有对集合的不可变借位,因此在迭代器处于活动状态时不能改变集合.
当您将多个指针(或引用)传递给函数时,更容易理解但不太常见的示例是指针别名.一个具体的例子是将重叠的内存范围传递给memcpy而不是memmove.实际上,Rust也是memcpy等价的unsafe,但这是因为它需要指针而不是引用.链接页面显示了如何使用可变引用永远不会别名的保证来创建安全交换函数.
一个更人为的参考别名示例是这样的:
int f(int *x, int *y) { return (*x)++ + (*y)++; }
int i = 3;
f(&i, &i); // result is undefined
Run Code Online (Sandbox Code Playgroud)
你不能像在Rust中那样编写一个函数调用,因为你必须对同一个变量进行两次可变的借用.
我怎么能用对同一事物的多个可变引用做一些不好的事情(例如分段错误、未定义的行为等)?
我相信,虽然您通过这样做触发了“未定义行为”,但从技术上讲,noaliasRust 编译器不会使用该标志作为&mut引用,所以实际上,现在,您可能无法以这种方式实际触发未定义行为。您触发的是“特定于实现的行为”,即“根据 LLVM 的行为类似于 C++”。
请参阅为什么假设两个可变引用不能别名,Rust 编译器不优化代码?想要查询更多的信息。
我可以看到引入线程时可能会出现什么问题,但是为什么即使我在一个线程中完成所有操作也会阻止它?
在我看来,竞争条件(如迭代器)并不是你所谈论的一个很好的例子。在单线程环境中,如果你小心的话,你可以避免这种问题。这与创建一个指向无效内存的任意指针并写入它没有什么不同。只是不要这样做。你并不比使用 C 更糟。
要理解这里的问题,请考虑在发布模式下编译时编译器可能会或可能不会在执行优化时重新排序语句;这意味着尽管您的代码可能以线性顺序运行:
a; b; c;
Run Code Online (Sandbox Code Playgroud)
不能保证编译器在运行时会按该顺序执行它们,如果(根据编译器所知道的),没有逻辑上的理由必须以特定的原子顺序执行这些语句。我在上面链接的博客的第 3 部分演示了这如何导致未定义的行为。
tl;dr:基本上,编译器可能会执行各种优化;当且仅当您的程序不会触发未定义的行为时,这些保证会继续使您的程序以确定性方式运行。
据我所知,Rust 编译器目前没有使用许多可能导致这种失败的“高级优化”,但不能保证将来不会。引入新的编译器优化并不是一个“重大变化”。
所以......实际上你现在不太可能仅仅通过可变别名触发实际的未定义行为;但限制允许未来性能优化的可能性。
相关引述:
C FAQ 定义了这样的“未定义行为”:
任何事情都可能发生;该标准没有强加任何要求。程序可能无法编译,或者可能不正确地执行(崩溃或静默地生成不正确的结果),或者它可能恰好按照程序员的意图执行。
| 归档时间: |
|
| 查看次数: |
532 次 |
| 最近记录: |