这可能过于具体,但可以在此处发布,因为它可能会帮助那些尝试在默认SPEC基准测试工具之外编译/运行SPEC 2006基准测试的其他人。 (我们这样做的原因是比较编译策略和代码覆盖率,而SPEC线束仅关注结果代码的性能)。
执行perlbench的ref运行时,基准测试会因分段错误而崩溃:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004f6868 in S_regmatch (prog=0x832144)
at <path-to-spec>/CPU2006/400.perlbench/src/regexec.c:3024
3024 PL_reg_start_tmp[n] = locinput;
(gdb) bt
#0 0x00000000004f6868 in S_regmatch (prog=0x832144)
at <path-to-spec>/CPU2006/400.perlbench/src/regexec.c:3024
#1 0x00000000004f22cf in S_regtry (prog=0x8320c0, startpos=0x831e70 "o")
at <path-to-spec>/CPU2006/400.perlbench/src/regexec.c:2196
#2 0x00000000004eba71 in Perl_regexec_flags (prog=0x8320c0, stringarg=0x831e70 "o", strend=0x831e71 "",
strbeg=0x831e70 "o", minend=0, sv=0x7e2528, data=0x0, flags=3)
at <path-to-spec>/CPU2006/400.perlbench/src/regexec.c:1910
#3 0x00000000004b33bb in Perl_pp_match ()
at <path-to-spec>/CPU2006/400.perlbench/src/pp_hot.c:1340
#4 0x00000000004fcde4 in Perl_runops_standard ()
at <path-to-spec>/CPU2006/400.perlbench/src/run.c:37
#5 0x000000000046bf57 in S_run_body (oldscope=1)
at <path-to-spec>/CPU2006/400.perlbench/src/perl.c:2017
#6 0x000000000046b9f6 in perl_run (my_perl=0x7bf010)
at <path-to-spec>/CPU2006/400.perlbench/src/perl.c:1934
#7 0x000000000047add2 in main (argc=4, argv=0x7fffffffe178, env=0x7fffffffe1a0)
at <path-to-spec>/CPU2006/400.perlbench/src/perlmain.c:98
执行环境是64位Linux,并且使用最新的gcc和clang来观察行为。
导致此次崩溃的原因是什么?
答案 0 :(得分:4)
段错误是由指出行上的变量n
的垃圾值引起的。检查代码显示该值来自类型为
arg1
struct regnode_1 {
U8 flags;
U8 type;
U16 next_off;
U32 arg1;
};
检查对象的内存位置表明它没有打包,即next_off
和arg1
之间有32位填充:
(gdb) x/16xb scan
0x7f4978: 0xde 0x2d 0x02 0x00 0x00 0x00 0x00 0x00
0x7f4980: 0x00 0x11 0x0d 0x00 0x00 0x00 0x00 0x00
(gdb) print/x n
$1 = 0xd1100
这是可疑的。 perlbench
中正在进行指针和类型转换,因此类型大小假设可能在某处失败。使用multilib
进行编译会产生一个工作基准,并检查内存是否验证没有填充。
将结构强制转换为位域可以在执行64位编译时修复崩溃:
struct regnode_1 {
U8 flags : 8;
U8 type : 8;
U16 next_off : 16;
U32 arg1 : 32;
};
答案 1 :(得分:2)
这就是我们的小调查进展:
起初我们认为这是一些填充问题,但正如彼得在Godbolt指出的那样,没有发生这样的事情。因此,结构的包装与否并没有改变任何东西。
然后,我怀疑Perl处理指针的方式(明显扭曲)。大多数演员都违反了标准规定的严格别名。由于分段错误发生在指针强制转换上,即:
struct regnode {
U8 flags;
U8 type;
U16 next_off;
};
到
struct regnode_1 {
U8 flags;
U8 type;
U16 next_off;
U32 arg1;
};
但是,使用-fstrict-aliasing
标志启用它并没有改变任何内容。尽管它有资格作为未定义的行为,但内存中没有重叠,因为当前正在解析的正则表达式的元素/节点在内存中单独布局。
更深入地检查有问题的switch
块的LLVM IR,我在regexec.ll
; truncated
%876 = load %struct.regnode*, %struct.regnode** %scan, align 8, !dbg !8005
%877 = bitcast %struct.regnode* %876 to %struct.regnode_1*, !dbg !8005
%arg11715 = getelementptr inbounds %struct.regnode_1, %struct.regnode_1* %877, i32 0, i32 3, !dbg !8005
%878 = load i64, i64* %arg11715, align 8, !dbg !8005
store i64 %878, i64* %n, align 8, !dbg !8006
; truncated
加载/存储指令使用64位整数,这意味着C中的指针被解释为指向8字节整数(而不是4)。因此,在当前正则表达式节点struct
之外收集2个字节,以计算arg1
的值。该值又用作数组索引,当数据超出数组范围时,最终会导致段错误。
返回跟踪,其中U32
被解释为64位无符号整数。查看文件spec_config.h
,条件编译(至少在我的机器中)指向以
#elif !defined(SPEC_CPU_GOOFY_DATAMODEL)
根据周围区域的代码注释,它应该与ILP32数据模型相对应(另请参阅this)。但是,U32TYPE
被定义为unsigned long
,在我的机器上是64位。
因此,修复方法是将定义更改为
#define U32TYPE uint32_t
,如this中所述,保证完全 32位(如果支持)。
答案 2 :(得分:2)
我想补充其他答案,说我们可以添加-DSPEC_LP64
来解决段错误(在CPU2017中gcc
)。如果SPEC小组将其添加到他们的常见问题解答中会很好。这似乎也适用于cactusADM
,povray
,wrf
和Collecting Django Using cached Django-2.0.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/private/var/folders/tn/d7vg_zcd5pq0cq3sltw0j7pc0000gn/T/pip-build-xIsFov/Django/setup.py", line 32, in <module>
version = __import__('django').get_version()
File "django/__init__.py", line 1, in <module>
from django.utils.version import get_version
File "django/utils/version.py", line 61, in <module>
@functools.lru_cache()
AttributeError: 'module' object has no attribute 'lru_cache'
---------------------------------------- Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/tn/d7vg_zcd5pq0cq3sltw0j7pc0000gn/T/pip-build-xIsFov/Django/
。
我们有一个python脚本为我们生成配置文件,我将与人们交谈,看看我是否可以分享我们目前为止为我们的编译器运行的内容。
编辑:无论如何,似乎都可以从外部访问,所以请转到:spec.py