因为一些原因,目前工作中使用的 gcc 版本是 7.4。接到一个业务需求,需要对某些特定的用户打开一个 feature flag,且需要在代码里硬编码。代码很快就写完了,自测的时候却发现不太对劲。相关代码简化脱敏后如下所示。逻辑很简单,就是把可以进入灰度的用户 id 放到了一个 allowlist 里,然后检查当前的请求涉及到的所有用户 id 是否都在这个 allowlist 中。奇怪之处在于,在 gcc 7.4 下,如果用了 std::any_of 来找,即便用户不在灰度列表中,列表成员检查也会返回 true,导致意外的灰度进入;简单的 for 循环则没有这个问题。
#include<cstdint>#include<iostream>#include<vector>#include<algorithm>intmain(){// we want to check if all users is in allowlist (something like a feature flag)
constexpruint64_tallowlist[]={1,2,3};std::vector<uint64_t>users;users.push_back(4);boolbasic_found=std::find(std::begin(allowlist),std::end(allowlist),4)!=std::end(allowlist);std::cout<<"outside: basic_found="<<basic_found<<std::endl;// should be false, as expected
boolsome_found_anyof=std::any_of(users.begin(),users.end(),[&](constuint64_tuid){boolfound=std::find(std::begin(allowlist),std::end(allowlist),uid)!=std::end(allowlist);std::cout<<"inside: uid="<<uid<<", found="<<found<<std::endl;returnfound;});std::cout<<"some_found_anyof="<<some_found_anyof<<std::endl;// should be false; however in gcc 7.4 this outputs true
boolsome_found_manual=false;for(constauto&u:users){if(std::find(std::begin(allowlist),std::end(allowlist),u)!=std::end(allowlist)){some_found_manual=true;break;}}std::cout<<"some_found_manual="<<some_found_manual<<std::endl;// should be false, as expected
}
因为需求要的比较着急,就先用 for 循环替换了。后面有空的时候尝试继续简化代码,可以得到如下的最小复现 POC:定义一个 constexpr 数组,创建一个 lambda 表达式,用[&]隐式捕获这个数组,最后在闭包中多次获取其地址;会惊喜的发现,每次获取的地址是不一样的!(可以在 Compiler Explorer 自己试试:https://godbolt.org/z/qdTfP81xn)