一个UT case引入的栈非法访问

笔者上周肝了几天,各方偷取,提炼,封装了点代码,由于UT需要支持跨平台运行,故对write函数作了一点封装,并且UT当中采用mock形式


int System::system_write(int fd, const void* buf, size_t count)
{
    const int ret(::write(fd, buf, count));

    ssize_t ret;
    do
    {
        ret = ::write(fd, buf, count);
    } while ((ret == -1) && (errno == EINTR));

    if(ret == -1)
    {
        throw InternalSystemError("write fail.");
    }
    return ret;

}

信心满满的的case如下


TEST_F(ClientProxyTest, sendCanMsg_OK)
{
    can_frame frame;
    initSemSignal(frame, static_cast<INT16U>(EVENT_NAME::SEMINIT), 2, 0);
    int msgsize_1 = 0;

    int temp_socketfd_ = 0;
    // mock hits in the destructor of eventfd, 
    // and context in sendCanMsg_OK is all invalid that time, so we use global value here
    int gtest_temp_eventfd_ = 0; 
    int gtest_msgsize_2_ = 0; 


    EXPECT_CALL(System_, system_write(_,_, _))
    .Times(2)
    .WillOnce(::testing::DoAll(::testing::SaveArg<0>(&temp_socketfd_), ::testing::SaveArg<2>(&msgsize_1), Return(sizeof(can_frame))))
    .WillRepeatedly(::testing::DoAll(::testing::SaveArg<0>(&gtest_temp_eventfd_), ::testing::SaveArg<2>(&gtest_msgsize_2_), Return(sizeof(can_frame))));

    clientProxy_->sendCanMsg(frame);

    EXPECT_EQ(msgsize_1, sizeof(can_frame));
    EXPECT_EQ(temp_socketfd_, 100);

}

在VC2022环境下运行起来没啥问题(VC打开sanitizer功能后有问题,要求所有依赖的库都打开该功能,只能用于本地测试,而且还存在全局变量和mock本身的全局变量释放顺序非预期后,crash的问题,故平时不会打开了)。

linux(x86)环境,前段时间将sanitizer集成进去,结果运行后发现有非法地址访问,sanitizer给的信息不太一下子能够明白,最后gdb跟踪才大致有点发现,下班跑路后,在公交车上回放了一下,才恍然有误。

UT的本意就是预期write会调用两次,然而第二次调用是在clientProxy_析构流程中,笔者在写case的时候没有特别在意这一点。

走到析构流程,上述本地变量,由于已经退出该上下文,所以存储的地址无效。

    int gtest_temp_eventfd_ = 0; 
    int gtest_msgsize_2_ = 0; 

为了证实该分析,将这两个变量放到全局存储区,结果pass。

教训有点深刻的,类似问题的表现往往更明显,比如lambda捕获局部栈上变量的引用时,也会出现几乎同类型问题,开发时一般都会注意,写UT的时候反而不会有这种sense。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值