问题排查:C++ exception with description “getrandom“ thrown in the test body

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。

文章目录

Motivation

最近在做一个复杂系统集成到 Bazel 的工作。

在编译链接通过后为了能后确保外部系统的每个编译单元都没有动态链接的问题,需要多写一些测试代码,把这些代码都执行到。

在执行其中一个测试时,在众多的错误中报出了一个没有明确指向原因的错误:

unknown file: Failure

C++ exception with description "getrandom" thrown in the test body.

问题是代码中并没有直接调用到getrandom系统调用,其次也不知道为什么会报错。

Process

首先执行如下代码,开始gdb单元测试:

  1. bazel build --compilation_mode=dbg --test_timeout=60 xxxx/xxxxx/xxxxxx:test_xxx
  2. gdb xxxx/xxxxx/xxxxxx/test_xxx

从不多的错误信息可以看出时抛异常了,在GDB中执行如下指令拿到异常栈帧:

  1. catch throw
  2. r
  3. bt

这里可以看到原来是在boost库抛异常了,对应的boost库代码如下:

cpp 复制代码
class random_provider_base
{
public:
    //! Obtain entropy and place it into a memory location
    //! \param[in]  buf  the location to write entropy
    //! \param[in]  siz  the number of bytes to acquire
    void get_random_bytes(void *buf, std::size_t siz)
    {
        std::size_t offset = 0;
        while (offset < siz)
        {
            ssize_t sz = get_random(static_cast< char* >(buf) + offset, siz - offset, 0u);

            if (BOOST_UNLIKELY(sz < 0))
            {
                int err = errno;
                if (err == EINTR)
                    continue;
                BOOST_THROW_EXCEPTION(entropy_error(err, "getrandom"));
            }

            offset += sz;
        }
    }

private:
    static ssize_t get_random(void *buf, std::size_t size, unsigned int flags)
    {
#if defined(BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_IMPL_GETRANDOM)
        return BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_IMPL_GETRANDOM(buf, size, flags);
#elif defined(BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_HAS_LIBC_WRAPPER)
        return ::getrandom(buf, size, flags);
#else
        return ::syscall(SYS_getrandom, buf, size, flags);
#endif
    }
};

我这个时候其实并不敏感。

从现有信息看已经基本确定是getrandom的问题了。

从[1]可以看到 getrandom 是在glibc 2.25 支持的

执行ldd --version发现我的glibc版本是2.28,原则上是支持的。

写个demo:

cpp 复制代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/random.h>
#include <unistd.h>

int main() {
    size_t num_bytes = 16;
    unsigned char buffer[16];

    ssize_t result = getrandom(buffer, num_bytes, 0);
    
    if (result == -1) {
        perror("getrandom failed");
        std::cerr << errno << " :" <<  std::strerror(err) << std::endl;
        return EXIT_FAILURE;
    }

    printf("Random bytes: ");
    for (size_t i = 0; i < num_bytes; i++) {
        printf("%02x ", buffer[i]);
    }
    printf("\n");

    return EXIT_SUCCESS;
}

执行起来果然报错,输出为:

执行ldd a.out看看动态库依赖

此时怀疑glibc.so有问题,或者内核版本有问题

执行rpm -qf /lib64/libc.so.6 ,是RHEL的官方包,那基本有问题的概率不大。

执行nm libc.so.6 |c++filt|grep random

确实看到了glibcgetrandom符号,Text Section,且是有效的

执行strace -ff -o strace.log ./a.out,检查下可执行文件调用了哪些系统调用,确定是glibc的问题还是内核的问题。

原来原始的报错信息是Function not implemented,经过了几层异常后已经看不出来原始报错了,重新看了一遍文档getrandom系统调用3.17才支持,我的开发机只有3.10,是使用docker构造编译环境的。

docker只是经过Namespaces隔离,Cgroups隔离,Security隔离的特殊进程,和宿主机共享内核,自然系统调用就失败了。

所以确定就是内核版本问题。

参考:

  1. man getrandom
相关推荐
跟德姆(dom)一起学AI10 分钟前
0基础跟德姆(dom)一起学AI 深度学习01-深度学习介绍
开发语言·人工智能·python·深度学习·机器学习
神奇夜光杯19 分钟前
Python酷库之旅-第三方库Pandas(200)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
API快乐传递者21 分钟前
利用Python 的爬虫技术淘宝天猫销量和库存
开发语言·爬虫·python
毕业设计制作和分享33 分钟前
ssm好例文共享平台的设计与实现+jsp
java·开发语言·vue.js·spring boot·毕业设计·mybatis
丶Darling.40 分钟前
代码随想录 | Day38 | 动态规划 :01背包应用 目标和&&一和零
c++·算法·动态规划·记忆化搜索·回溯·递推·01背包
TANGLONG22241 分钟前
【初阶数据与算法】线性表之顺序表的定义与实现
java·c语言·数据结构·c++·python·算法·面试
东成202243 分钟前
从配置anaconda到配置pycharm
开发语言·python·conda
C++忠实粉丝43 分钟前
计算机网络socket编程(1)_UDP网络编程实现echo server
linux·服务器·网络·c++·网络协议·计算机网络·udp
API_technology1 小时前
java 串口 驱动
java·大数据·开发语言·数据库
小马哥编程1 小时前
在Ubuntu 上实现 JAR 包的自启动
开发语言