当未对齐的写入越过页面边界并触发错误时会发生啥?

Posted

技术标签:

【中文标题】当未对齐的写入越过页面边界并触发错误时会发生啥?【英文标题】:What happens when an unligned write crosses a page boundary and a fault is triggered?当未对齐的写入越过页面边界并触发错误时会发生什么? 【发布时间】:2018-03-26 09:16:49 【问题描述】:

假设一个 32 位值被写入一个跨越 2 页的内存位置。为了论证的缘故,我们假设第一页中有 2 个字节,第二页中有 2 个字节。第一页是可写的,但第二页是未映射的。整个执行指令会触发页面错误,这很好。

我的问题是:在值的前 2 个字节写入内存之前或之后会触发页面错误吗?换句话说,故障后​​运行的代码(例如故障处理程序)是否能够观察到部分写入?

让我们假设一个 X86 环境,因为我怀疑行为可能是体系结构甚至是模型特定的。

【问题讨论】:

IIRC,整个写入因故障而中止。如果您想仔细检查,英特尔的 x86 手册应该详细记录这一点。对此不太确定,但 IIRC AVX512 屏蔽存储 可能 在发生故障之前实际上存储了一些(非故障)元素。我刚刚检查了 ISA 参考手册中的分散指令,他们没有这么说:分散按指定顺序检查故障。 (但是对于散点图的单个元素,如果它有故障,它根本不会完成。) 如果有任何架构可以让部分存储到非故障页面通过,我会感到惊讶。顺便说一句,the x86 tag wiki 中指向英特尔 x86 手册的链接。 @PeterCordes - 我没有检查 AVX-512 商店,但毫无疑问它就是这样工作的。甚至 AVX2 收集也是这样操作的:它们在每次收集操作后更新掩码寄存器(原则上无论如何),因此它们可以被中断(我认为),因此如果抛出异常,则部分负载可能已经完成,并且掩码寄存器将反映这一点(因此可能会修复问题并重新启动负载)。毫无疑问,AVX-512 聚集的工作原理是一样的,如果分散不同就会很奇怪。 【参考方案1】:

来自英特尔架构手册第 3A 卷:

对跨缓存行和拆分的可缓存内存的访问 英特尔酷睿 2 不保证页面边界是原子的 双核、英特尔® 凌动™、英特尔酷睿双核、奔腾 M、奔腾 4、英特尔至强、 P6 系列、奔腾和 Intel486 处理器。

IMO 不是原子的意味着您描述的场景可能会发生。写入前 2 个字节后可以产生中断。

【讨论】:

但是必须在页面拆分的两个部分变得全局可见之前完成对页面拆分的两个部分的权限检查,除非我对它的工作方式有误。 我看不出有什么不同。非原子意味着其他部分(其他核心或总线)可以观察部分写入,为什么当中断发生时同一个核心不能观察部分写入?我不认为发生页面错误时部分写入会回滚。它使问题变得更加复杂,却一无所获.. 将取决于总线传输是什么样子的,如果核心将它分成两个传输,或者它是一个未对齐的传输......当然更简单的答案是尝试它是吗? @Zang:所有这些微架构都已经因推测执行而出现故障。他们必须能够在从存储缓冲区提交到 L1D 缓存并成为全局可见之前取消已经执行的存储。在商店退出之前不允许发生这种情况(即发现所有先前的指令都已完成,没有异常或其他错误推测检测,并且对于 this 指令的所有部分都是相同的。最常见的一种错误推测是分支预测是错误的,但它也包括这个和早期的加载/存储没有错误。) @PeterCordes 我明白了。由于英特尔没有定义行为,因此行为未定义,部分写入可能发生也可能不发生。至少非原子意味着不能保证不会发生部分写入。但是为了避免错误,我们总是预计最坏的情况会发生。我认为这可能发生在我的工作中。

以上是关于当未对齐的写入越过页面边界并触发错误时会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

c++ 当在一个线程中写入并在第二个线程中读取同一个对象时会发生啥? (它安全吗?)[重复]

当 JDBC AutoCommit 为 False 且未设置显式事务边界时会发生啥

当 Impala 中的客户端触发查询时会发生啥?

当所有数据节点在hadoop中失败时会发生啥?

当不同的 CPU 内核在没有同步的情况下写入同一个 RAM 地址时会发生啥?

当我们刷新网页时会发生啥?