- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
考虑以下简单程序:
#include <cstring>
#include <cstdio>
#include <cstdlib>
void replace(char *str, size_t len) {
for (size_t i = 0; i < len; i++) {
if (str[i] == '/') {
str[i] = '_';
}
}
}
const char *global_str = "the quick brown fox jumps over the lazy dog";
int main(int argc, char **argv) {
const char *str = argc > 1 ? argv[1] : global_str;
replace(const_cast<char *>(str), std::strlen(str));
puts(str);
return EXIT_SUCCESS;
}
/
替换
_
字符。此替换功能由
c_repl
函数1实现。例如,
a.out foo/bar
打印:
foo_bar
/
字符,因此不会进行任何替换。
const char[]
,所以我需要先删除常量性-这就是您看到的
const_cast
。由于从未真正修改过字符串,因此给我留下了
this is legal的印象。
icc -xcore-avx2 char_replace.cpp && ./a.out
Segmentation fault (core dumped)
c_repl
的主循环,如下所示:
400c0c: vmovdqu ymm2,YMMWORD PTR [rsi]
400c10: add rbx,0x20
400c14: vpcmpeqb ymm3,ymm0,ymm2
400c18: vpblendvb ymm4,ymm2,ymm1,ymm3
400c1e: vmovdqu YMMWORD PTR [rsi],ymm4
400c22: add rsi,0x20
400c26: cmp rbx,rcx
400c29: jb 400c0c <main+0xfc>
/
字符进行比较,形成一个掩码值,并为每个匹配的字节设置一个字节,然后将现有字符串与包含32个
_
字符的 vector 混合,仅有效地替换
/
字符。最后,使用
vmovdqu YMMWORD PTR [rsi],ymm4
指令将更新后的寄存器写回到字符串中。
.rodata
节中分配,所以该最终存储崩溃了,该二进制文件使用只读页面加载。当然,存储是逻辑上的“禁止操作”,写回与读取的字符相同的字符,但是CPU不在乎!
std::replace
上的
std::string
而非我的“C样”代码上,但是我想尽可能简化分析并使之完全独立。
最佳答案
据我所知,您的程序格式正确,没有不确定的行为。 C++抽象机从不实际分配给const
对象。 如果不执行,则未采用的if()
足以“隐藏”/“保护”将成为UB的内容。 唯一无法通过if(false)
拯救您的是an ill-formed程序,例如语法错误或尝试使用此编译器或目标arch上不存在的扩展名。
通常不允许编译器通过if转换为无分支代码来进行写操作。
抛弃const
是合法的,只要您实际上没有通过它分配即可。例如用于将指针传递给非const正确的函数,并使用带有非const
指针的只读输入。您在Is it allowed to cast away const on a const-defined object as long as it is not actually modified?上链接的答案是正确的。
ICC的行为在ISO C++或C中不是UB的证据。我认为您的推理是正确的,并且定义明确。您已找到ICC错误。如果有人在意,请在其论坛上报告:https://software.intel.com/en-us/forums/intel-c-compiler。开发者e.g. this one已接受其论坛中该部分中的现有错误报告。
We可以构造一个示例,在其中它以相同的方式自动矢量化(无条件和非原子读取/可能修改/重写),在显然是非法的,因为读取/重写发生在C语言的第二个字符串上抽象机甚至不读。
因此,我们不能相信ICC的代码生成器可以告诉我们什么时候造成UB的任何信息,因为即使在显然合法的情况下,它也会使崩溃的代码成为现实。
Godbolt:ICC19.0.1 -O2 -march=skylake
(较旧的ICC仅理解-xcore-avx2
之类的选项,但现代ICC理解与GCC/clang相同的-march
。)
#include <stddef.h>
void replace(const char *str1, char *str2, size_t len) {
for (size_t i = 0; i < len; i++) {
if (str1[i] == '/') {
str2[i] = '_';
}
}
}
str1[0..len-1]
和
str2[0..len-1]
之间的重叠,但是对于足够大的
len
且没有重叠,它将使用以下内部循环:
..B1.15: # Preds ..B1.15 ..B1.14 //do{
vmovdqu ymm2, YMMWORD PTR [rsi+r8] #6.13 // load from str2
vpcmpeqb ymm3, ymm0, YMMWORD PTR [rdi+r8] #5.24 // compare vs. str1
vpblendvb ymm4, ymm2, ymm1, ymm3 #6.13 // blend
vmovdqu YMMWORD PTR [r8+rsi], ymm4 #6.13 // store to str2
add r8, 32 #4.5 // i+=32
cmp r8, rax #4.5
jb ..B1.15 # Prob 82% #4.5 // }while(i<len);
str2
,因此无法使关于数据争用UB的单字符串版本的任何参数都无效,因为在读取另一个表的同时已读
str
已经是UB了。甚至
C++20 std::atomic_ref
也不会改变它,因为我们正在读取非原子指针。
str2
可以是nullptr
。 或指向对象的末尾(恰好存储在页面末尾附近),
str1
包含字符,因此
str2
末尾不会写入任何内容/页面将发生。我们甚至可以只将最后一个字节(
str2[len-1]
)安排在新页面中,以便它是有效对象的最后一位。构造这样的指针甚至是合法的(只要您不取消引用)。但是传递
str2=nullptr
是合法的;不能运行的
if()
后面的代码不会导致UB。
str2
的不同元素。 未经修改的值的非原子加载/存储将基于来自另一个线程的修改后的值。根据C++ 11内存模型,绝对允许不同的线程同时触摸同一数组的不同元素。
C++ memory model and race conditions on char arrays。 (这就是为什么
char
必须与目标计算机在没有非原子RMW的情况下可以写入的最小内存单元一样大的原因。但是
internal atomic RMW for a byte stores into cache is fine并不会阻止字节存储指令的使用。)
atomic<>
Weapons: The C++ Memory Model and Modern Hardware第2部分:
中所提到的那样,对编译器和硬件的限制(包括常见的错误); x86/x64,IA64,POWER,ARM等上的代码生成和性能;松弛原子; volatile :在C++ 11标准化之后,淘汰非原子RMW代码源一直是编译器面临的问题。我们已经走了很多路,但是像ICC这样的高度进取和不那么主流的编译器显然仍然存在错误。
nullptr
之外,您还可以将指针传递给
std::atomic<T>
(一个数组)或一个互斥体,在该互斥体中非原子的读/写会通过发明写操作破坏事物。 (
char*
可以为任何别名)。
str2
指向您为动态分配而划分的缓冲区,并且
str1
的早期部分将有一些匹配项,但是
str1
的后半部分将没有任何匹配项,并且
str2
的那部分正在被其他线程使用。 (由于某种原因,您不能轻易地计算出使循环变短的长度)。
str2[i] = x ? replacement : str2[i];
,之类的源代码,该源代码始终将字符串写入C++抽象机中。 IIRC,让gcc/clang在进行不安全的if-conversion转换后可以矢量化ICC的方式。
cmov
,PowerPC
isel
或AArch64
csel
这样的ALU选择操作,则如果谓词为false,ARM32谓词指令在结构上就是NOP)。
vpcmpeqb k1, zmm0, [rdi] ; compare from memory into mask
vmovdqu8 [rsi]{k1}, zmm1 ; masked store that only writes elements where the mask is true
-march=skylake-avx512
做到这一点(但使用索引寻址模式)。但是对于ymm vector ,因为除非在Skylake Xeons上整个程序都大量使用AVX512,否则512位降低max turbo值实在不值得。
vpcmpuq
和
kshift
/
kor
进行更复杂的操作,零掩码加载以及将掩码比较与另一个掩码reg。
vmaskmovps/pd
),但在AVX512BW之前,没有比32位窄的粒度。 AVX2整数版本仅在dword/qword粒度
vpmaskmovd/q
中可用。
关于c++ - icc : can the compiler invent writes where none existed in the abstract machine?崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54524947/
我在运行 compile test:compile it:compile经常并且...希望将击键次数减少到类似 *:compile 的数量。 .不过,它似乎不起作用。 $ sbt *:compile
有人可以给我这个问题的提示(或整个解决方案!): 在 Clojurescript 项目中,如何自动将编译日期/时间硬编码在符号中,以便在使用应用程序时显示? 谢谢。 最佳答案 有多种解决方案: 使用l
我是 ember.js 框架的新手,使用 ruby on rails 和 ember.debug.js -v 1.10.1(最新版本)。我一直在网上看到 ember 更改了这个最新的补丁,但我不知
我不是 Fortran 程序员(只是短暂的经验),但我需要编译一个部分用 F77 编写的程序。在我之前有人用 Absoft 编译器编译过它,但现在我需要在另一台机器上用 g77 重复这个过程。对于 A
我运行命令 mvn clean package 我得到了上面的错误我的 pom 是: http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0
我有以下问题。 我想在测试编译阶段排除一些.java文件(** / jsfunit / *。java),另一方面,我想在编译阶段包括它们(id我使用tomcat启动tomcat:运行目标) ) 我的p
符合 wikipedia A compiler is a computer program (or set of programs) that transforms source code writt
我想构建项目,但出现如下错误: 无法执行目标 org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile
当我通过右键单击项目名称进行 Maven 安装时,出现以下错误: [INFO] Scanning for projects... [WARNING] [WARNING] Some proble
我是 Maven 的新手,我想将我的应用程序导入到 Maven。和以前一样,我想将我的 ejb 项目中的类引用到我的 war 项目中。我在类中没有错误,但是如果我在我的父项目上安装 maven,那么我
当我将 ASP.NET Web 应用程序部署到生产环境时,我使用配置转换来删除 debug="true"来自 .但是,就在今天,我注意到 web.config 中的另一个部分如下所示:
This question already has answers here: Maven Compilation Error: (use -source 7 or higher to enable
我正在使用 Maven 3.0.5 和 Spring Tool Source 3.2 并安装了 Maven 插件。当我尝试执行“运行方式---> Maven 安装”时,出现以下错误: [INFO] S
我试图用 AngularJS 创建我自己的递归指令,它调用自己以漂亮的 JSON 格式转换 View 中的对象。好吧,首先我使用 ng-include 调用带有模板的脚本,在其中使用 ng-if 验证
可以通过 @suppress annotation使用Google的Closure Compiler在每个文件的基础上禁止显示警告。但是,似乎无法同时抑制多个警告-例如globalThis和check
假设一个拥有 10 到 20 年经验的熟练开发人员从未构建过编译器或模拟器,哪一个会更具挑战性? 你能比较一下会成为障碍的问题吗? 谢谢。 最佳答案 仿真和编译是完全不同的,但由于两者都被认为是“低级
最近发现Vim中有一个命令叫compiler。您可以使用任何常见的编译器(例如,:compiler gcc、:compiler php 等)来调用它,但它似乎没有任何立竿见影的效果。 我在联机帮助页上
我试图从 spring.io 指南中部署最简单的应用程序 Guide 但是我有一些麻烦.. 我做了什么: 创建的项目。 (来自 spring.io 教程) 下载 heroku CLI 在 Intell
每当进行 Maven Build..>clean install 时,我都会遇到此错误。我尝试过使用不同版本的插件并添加 testFailureIgnore 属性,但问题仍然存在。请找到下面的 POM
我有一个 web 应用程序,我尝试使用 maven 进行编译,不幸的是,在执行 mvn clean package 时它不起作用。 stackoverflow 上有很多问题看起来都一样,但没有解决了我
我是一名优秀的程序员,十分优秀!