- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图了解 Rust 别名/内存模型到底允许什么。我特别感兴趣的是,当访问超出您引用的范围的内存时(可能被相同或不同线程上的其他代码别名)成为未定义的行为。
以下示例都在通常允许的范围之外访问内存,但如果编译器生成明显的汇编代码,则以安全的方式访问内存。此外,我认为与编译器优化几乎没有冲突,但它们可能仍会违反 Rust 或 LLVM 的严格别名规则,从而构成未定义的行为。
这些操作都是正确对齐的,因此不能跨越缓存线或页面边界。
pub fn read(x: &u8) -> u8 {
let pb = x as *const u8;
let pw = ((pb as usize) & !3) as *const u32;
let w = unsafe { *pw }.to_le();
(w >> ((pb as usize) & 3) * 8) as u8
}
atomic_load
读取 32 位字固有的。pub fn read_vol(x: &u8) -> u8 {
let pb = x as *const u8;
let pw = ((pb as usize) & !3) as *const AtomicU32;
let w = unsafe { (&*pw).load(Ordering::Relaxed) }.to_le();
(w >> ((pb as usize) & 3) * 8) as u8
}
AtomicU32
为简单起见,实际上 AtomicUsize
是有趣的。pub fn write(x: &mut u8, value:u8) {
let pb = x as *const u8;
let atom_w = unsafe { &*(((pb as usize) & !3) as *const AtomicU32) };
let mut old = atom_w.load(Ordering::Relaxed);
loop {
let shift = ((pb as usize) & 3) * 8;
let new = u32::from_le((old.to_le() & 0xFF_u32 <<shift)|((value as u32) << shift));
match atom_w.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
Ok(_) => break,
Err(x) => old = x,
}
}
}
最佳答案
这是一个非常有趣的问题。
这些函数实际上有几个问题,由于各种形式的原因,使它们不健全(即,公开不安全)。
同时,我无法在这些函数和编译器优化之间实际构建有问题的交互。
越界访问
我会说所有这些功能都不健全,因为它们可以访问未分配的内存。我可以用 &*Box::new(0u8)
给他们每个人打电话或 &mut *Box::new(0u8)
,导致越界访问,即超出使用 malloc
分配的访问(或任何分配器)。 C 和 LLVM 都不允许这样的访问。 (我使用堆是因为我发现在那里考虑分配更容易,但同样适用于堆栈,其中每个堆栈变量实际上都是它自己的独立分配。)
当然,LLVM language reference由于访问不在对象内部,因此实际上并未定义负载何时具有未定义的行为。但是,我们可以在 documentation of getlementptr inbounds
中得到一个提示。 ,这说
The in bounds addresses for an allocated object are all the addresses that point into the object, plus the address one byte past the end.
read
的位置旁边.
read
和
read_vol
在
C11 的并发语义下肯定是不健全的.想象
x
是
[u8]
的第一个元素,并且在我们执行
read
的同时另一个线程正在写入第二个元素/
read_vol
.我们对整个 32 位字的读取与另一个线程的写入重叠。这是一个经典的“数据竞争”:两个线程同时访问同一位置,一个访问是写,一个访问不是原子的。在 C11 下,任何数据竞争都是 UB,所以我们出局了。
LLVM稍微宽松一点,所以
read
和
read_val
可能是允许的,但是
right now Rust declares that it uses the C11 model .
volatile
!使用 volatile 而不是原子时,几乎不可能编写正确的并发代码。不幸的是,Java 的
volatile
是关于原子性的,但这是一个非常不同的
volatile
比C中的那个。
write
还引入了另一个线程中原子读取-修改-更新和非原子写入之间的数据竞争,因此在 C11 中也是 UB。这一次它也是 LLVM 中的 UB:另一个线程可能正在读取
write
的额外位置之一。影响,所以打电话
write
会在我们的写入和另一个线程的读取之间引入数据竞争。 LLVM 指定在这种情况下,读取返回
undef
.所以,拨打
write
可以在其他线程中安全访问同一位置返回
undef
,然后触发 UB。
read
和
read_vol
LLVM 的模型修复了并发问题(但与 C11 相比,它还有其他问题),但
write
在 LLVM 中是非法的,因为读写数据竞争使读取返回
undef
-- 在这种情况下,我们知道我们正在写入已经存储在这些其他字节中的相同值! LLVM 不能只是说在这种特殊情况下(写入已经存在的值),读取必须返回该值?可能是的,但这些东西足够微妙,如果这会使一些模糊的优化无效,我也不会感到惊讶。
read
完成。不太可能造成实际麻烦。我想人们可以想象一种返回
undef
的语义。当读取一个越界字节时,该字节保证与入界字节位于同一页面
byte
.但这仍然会离开
write
非法,这真的很难:
write
只有在这些其他位置上的内存完全保持不变时才允许。可能有来自其他分配的任意数据,堆栈帧的一部分,等等。因此,不知何故,正式模型必须让您读取其他字节,不允许您通过检查它们来获得任何东西,而且还要验证您在用 CAS 写回之前没有更改字节。我不知道有任何模型可以让你这样做。但我感谢你让我注意到这些令人讨厌的案例,很高兴知道在内存模型方面还有很多东西需要研究:)
&mut u8
(例如,紧挨着传递给
read
/
read_vol
/
write
的那个),别名规则保证除了您之外的任何人都不会对该字节进行任何访问。所以,你的函数从内存中读取其他人可以持有
&mut u8
已经使它们违反了别名规则。
关于rust - 读取或写入整个 32 位字,即使我们只引用其中的一部分,是否会导致未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50181283/
我想创建一个基于 jQuery 的非常简单的 html 编辑器(不是所见即所得)。 我的问题是如何制作 textarea或 div可能 在上面写一些文字 然后样式即标签(例如 some stuff 将
根据文档 isset 条款“测试此项目中是否已设置给定属性”。我不明白设置属性时 isset 返回 true 还是 false 在下面的代码片段中,当 env.JAVA_HOME 未设置时,java.
我正在尝试取消映射 o这是执行 :only 的默认命令( :help :only ),所以我尝试的第一件事是: nmap o 这种作品,除非我按 ,等待超过timeoutlen ms 然后按 o
我有以下型号: class MetaData(models.Model): created_at = models.DateTimeField(auto_now_add=True, auto_
下面列出了两行代码。两者对日期和时间的期望相同,但只有一个有效。我正在使用 R 3.1。 以下不起作用: DateTime2=strftime("08/13/2010 05:26:24.350", f
我有一个关于 C 代码的问题。 #include void foo(void){ int a; printf("%d\n",a); } void bar(void){
如果文件大小 > 8k,为什么读取的最后一个字节 = 0? private static final int GAP_SIZE = 8 * 1024; public static void main(
我有一个命令 Get-Testdata从不同来源检索测试数据并将这些数据存储到 PSObject以不同的值作为属性。然后将对象总数存储为数组,以便于操作、排序、计算等。 我的问题是我希望能够将这些数据
我正在使用 epoll 将大消息写入使用 HTTP 协议(protocol)的服务器。 fds 都设置为非阻塞,我正在使用边缘触发事件。我知道对于 EPOLLIN,我需要循环读取 fd,直到返回 EA
这对我来说听起来很奇怪: $test_1 = 'string'; $test_2 = '0'; var_dump(intval($test_1)); // Output: int 0 var_dump
这个问题在这里已经有了答案: Java: Integer equals vs. == (7 个回答) 7年前关闭。 请您解释以下行为。 public class EqAndRef { publ
Drupal 的行为到底是什么? 它为模块开发人员提供什么类型的服务层? 它映射到 jQuery.ready 的关系类型是什么? 最佳答案 长版:Drupal.behaviors 不仅仅是 jQuer
以下代码: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ for (int i=0
人们可以将项目添加到数据库中。我让他们选择在此时添加它,或手动选择日期。 因此我得到了这个 HTML 结构。 (请注意,我将日期和时间选择器妥协为只有一行文本) Selec
创建了一个数据框: simpleDF is.na(simpleDF$vals) [1] TRUE TRUE FALSE > is.nan(simpleDF$vals) [1] FALSE TRU
我有一个大的 docker 镜像 A,我创建了一个新的 Dockerfile FROM A RUN rm /big-folder 我尝试使用以下方法构建图像: docker build --squas
我想知道以下情况下 JVM 的行为是什么: JVM 最小堆大小 = 500MB JVM 最大堆大小 = 2GB 操作系统有 1GB 内存 JVM启动后,程序运行一段时间后,使用内存超过1GB。我想知道
我们正在使用 spikeearrest 策略,但我们不了解其工作原理。峰值逮捕配置如下: 5pm 阅读文档,我们了解到,如果我们在一分钟内调用此流超过 5 次,则该策略将在第 5 次之后
我正在使用 cURL 发送 POST 请求: curl http://tarvos.local:8080/partial_Users/2 -d '{currentPage : 1, firstID :
我的表中有 6442670 条记录,我正在使用以下命令获取它们jdbctemplate 使用行号一次 1000000 个。以下是查询 select * from (select rowNum rn
我是一名优秀的程序员,十分优秀!