GCC-O2优化致无副作用循环变无限循环的合法性疑问
GCC -O2优化引发无限循环的未定义行为分析
使用GCC 8.4.3并添加-O2编译选项构建程序时,以下循环被编译为无限循环的汇编代码:
for(int i=0; i < PCU_MAX; i++) { auto loc = getApp()->Loc[i + 1 + PCU_LOCATION]; if (loc.isUpdated() ) loc.setUpdated ( false ); }
最初程序挂起时误以为是死锁,未检查汇编代码;最终在GDB中尝试打印变量i时,发现该变量已被优化掉。对应的汇编代码如下:
0x782f20 <MainWindow::updateInfo(int)+352> mov 0xc31899(%rip),%rsi 0x782f27 <MainWindow::updateInfo(int)+359> mov $0x882700,%edi 0x782f2c <MainWindow::updateInfo(int)+364> callq 0x42da40 <_ZNK11QMetaObject4castEP7QObject@plt> 0x782f31 <MainWindow::updateInfo(int)+369> jmp 0x782f20 <MainWindow::updateInfo(int)+352>
已知的两个核心错误
getApp()->Loc是数组,代码中使用auto loc =会进行值拷贝,正确写法应为auto& loc =;- 循环无可见副作用,GCC优化掉变量
i后,循环终止条件消失,进而形成无限循环。
核心疑问
- 这种优化是否属于合法的未定义行为(UB)?
- 循环存在数组越界问题——最后一次迭代会访问数组末尾的下一个元素,虽该区域为同类型“安全区域”,但访问数组末尾后一个元素是否属于UB?
相关论点
- 论点1:获取数组末尾后一个元素的地址不属于UB,但访问或修改该元素属于UB;
- 论点2:
isUpdated()和setUpdated()虽看似与Loc元素相关,但实际无对应副作用;不过调用非静态成员函数时,即使this指针指向正确对象,是否仍属于UB?
补充现象
移除上述两个错误因素中的任意一个,循环均可正常运行;但仅移除if (loc.isUpdated() ) loc.setUpdated ( false );并改为auto& loc时,仍会出现无限循环。这似乎是GCC先优化掉i,再以“无限循环无可见副作用”为由判定为UB。
内容的提问来源于stack exchange,提问作者Swift - Friday Pie
相关产品推荐
相关产品推荐

