意外生成的无限循环,没有副作用[重复]

问题描述 投票:0回答:1

当使用 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
的值时,它似乎已被优化。该循环的组装:

8x782f29 <MainWindow:: updateInfo(int)+352> mov 8xc31899(%rip),%rsi
8x782f27 <MainWindow:: updateInfo(int)+359> mov $0x882700,%edi
8x782f2c <MainWindow:: updateInfo(int)+364> callq 0x42da40 <_2NK11QMetaObject4castEP7Q0bject@plt>
0x782f31 <MainWindow:: updateInfo(int)+369> jmp 0x782f20 <MainWindow:: updateInfo(int)+352>

显然,这包含了重大错误,

getApp()->Loc
是一个数组,所以它确实应该是
auto& loc=
,循环没有副作用。 GCC 优化了
i
并最终导致无限循环,因为结束条件消失了。为什么要这样做,它是合法的UB吗?

显然这有一个错误 - 最后一次迭代正好超出了数组末尾。但这是一个被相同类型占据的“安全区域”,检查数组末尾后面的一个元素不是 UB...还是现在?

参数 1:获取超出数组末尾的地址不是 UB。检查和改变它是。 参数 2:

isUpdated()
setUpdated()
没有与
Loc
元素的更改相关的副作用,即使它们看起来像。但调用它是一个 UB,因为它是一个非静态函数成员。事实上,
this
可能指向一个正确的物体。

删除这两个因素中的任何一个都会产生正确的循环。删除

if (loc.isUpdated() ) loc.setUpdated ( false );
并设置
auto& loc
仍然会产生无限循环。看起来首先 gcc 优化了
i
,然后“这是一个无限循环,没有明显的副作用,因为我让它无限,它是一个 UB”。

c++ gcc optimization
1个回答
1
投票

“[...]检查数组末尾之后的一个元素不是 UB...还是现在?”

据我所知,访问数组的越界元素(包括超出末尾的元素)始终是未定义的行为

因此,只要不先删除UB,就不能想当然地认为添加缺失的引用是否有效。

© www.soinside.com 2019 - 2024. All rights reserved.