文章目录

  • 前言
  • 崩溃问题
  • std::uniform_real_distribution<> 的bug
  • bug 重现方法
  • 总结

前言

近日发生一次线上游戏服务器宕机问题,通过日志和core文件信息定位到崩溃的函数,但是崩溃的位置却是一段很长时间都没有改动过的代码,起初怀疑是配置数据的问题,但仔细查看之后均正常,然后又怀疑是玩家旧数据异常导致,但是分析代码逻辑后也没发现问题,最后是一个同事发现生成随机数的代码有bug,导致数组越界了,还真是个意想不到的原因。

崩溃问题

崩溃出现在从数组中随机一个数的逻辑中,其中用到了 std::uniform_real_distribution 这个模板类,示例代码如下:

vector<int> v{1, 3, 5, 6};std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> dis(0, 1.0f);int n = static_cast<int>(dis(gen) * v.size());return v[n];

之前也了解过 std::uniform_real_distribution<float> dis(0, 1.0f); 这个用法,他应该返回的范围是 [0, 1.0) 内左闭右开的浮点数,所以最终计算出的 n 的值应该为 [0, n-1] 范围内的整数,所以这段代码不应该有问题,但是问题却恰恰出现在 std::uniform_real_distribution 的身上。

std::uniform_real_distribution<> 的bug

std::uniform_real_distribution 这个模板类定义在头文件 <random> 中,是C++11新加的内容,定义如下:

template< class RealType = double >
class uniform_real_distribution;

可产生均匀分布在区间 [a, b) 上的随机浮点值 x。

但是这个函数有个bug,它有时候会返回边界值b,也就是说实际范围变成了 [a, b]。 可以通过 cppreference.com - uniform_real_distribution查到,具体描如下:

It is difficult to create a distribution over the closed interval [a,b] from this distribution. Using std::nextafter(b, std::numeric_limits::max()) as the second parameter does not always work due to rounding error.

Most existing implementations have a bug where they may occasionally return b (GCC #63176 LLVM #18767 MSVC STL #1074). This was originally only thought to happen when RealType is float and when LWG issue 2524 is present, but it has since been shown that neither is required to trigger the bug.

关于这个bug还可以看一下这个帖子的讨论:

  • Is 1.0 a valid output from std::generate_canonical?

看得时候注意一下这段描述

This problem can also occur with std::uniform_real_distribution; the solution is the same, to specialize the distribution on double and round the result towards negative infinity in float.

bug 重现方法

这个bug有多种变体,其中一个就是说它和 generate_canonical 产生随机数有关

#include <iostream>
#include <limits>
#include <random>int main()
{std::mt19937 rng;std::seed_seq sequence{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};rng.seed(sequence);rng.discard(12 * 629143 + 6);float random = std::generate_canonical<float,std::numeric_limits<float>::digits>(rng);if (random == 1.0f){std::cout << "Bug!\n";}return 0;
}

此段代码在编译器 g++ 5.4.0 上编译执行时能重现,但是在 g++ 10.0.3 上已经被修复无法重现了,再看下面这段代码:

#include <iostream>
#include <random>int main()
{std::random_device rd;std::mt19937 gen(rd());std::uniform_real_distribution<> dis(0, 1.0f);while (true){float f = dis(gen);if (f >= 1.0){std::cout << "BUG\n";break;}}return 0;
}

这段代码无论是 g++ 5.4.0 版本还是 g++ 10.0.3 都能重现打印出 BUG,这个问题在于模板默认是 double 类型,最后转化成 float 来使用,我按照建议之前帖子中的建议,都改成 double 来使用,之后一直运行了10来天再没出现过随机到边界值的问题。

总结

  • 标准库中的内容很权威,但是不保证一定是正确的,可以持有怀疑态度
  • std::uniform_real_distribution的历史版本是有bug,几乎各个编译器都出现过随机到边界值的情况
  • 这个bug其实在文档中已经指出了,所以大家看文档时还是要仔细一点,往往使用不规范也容易造成bug

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==


适当的放松是生活的调味剂,有时候真的需要肆意挥霍一下,一张一弛,生活之道~

std::uniform_real_distribution的一个bug引发的服务器崩溃相关推荐

  1. 查看redis缓存大小_一个 bug 引发了服务器崩溃,对应 redis 的 key 回收原理你清楚了吗?...

    1 背景 项目中使用了 redis 做旁路缓存.读请求到来时,有以下操作:1.检查缓存,有则返回2.没有则读取数据库,将结果回写到缓存中. 写请求到来时,有以下操作:1.更新数据库 2.更新缓存(实际 ...

  2. 『转』度百死去飞秋一个BUG引发的血案

    作了一篇文章度百死去飞秋一个BUG引发的血案,昨天,度百死去的美国客户发邮件给我,说我的软件出问题了,我查来查去,发现居然是服务器上一个目录无法删除,一删除就报 cannot read from th ...

  3. 一个bug引发的人生感悟

    文章目录 问题现象 原因分析 节目id和节目路径映射关系 uuid数据 流程分析 发包机 解决办法 感悟 问题现象 发包机 结果csv文件,不同progid指向同一视频路径问题 原因分析 节目id和节 ...

  4. 一个bug引发的血案(大爆炸)

    据传,在冷战时期,CIA曾成功向前苏联"输出"一个有设计缺陷的控制软件,该软件用来控制天然气主管道.(KGB从一家加拿大公司窃取该软件.)那个植入的Bug最终引发了1982年的西伯 ...

  5. mysql 5.6 bug_MySQL 5.6的一个bug引发的故障

    突然收到告警,提示mysql宕机了,该服务器是从库.于是尝试登录服务器看看能否登录,发现可以登录,查看mysql进程也存在,尝试登录提示 ERROR 1040 (HY000): Too many co ...

  6. 一个BUG引发的灾难:ORA-00600 [kjmchkiseq:!seq]

    对于打工人可能最痛苦的就是被告知的故障,数据库有监控.告警.每天巡检,自己做了一系列数据库的"安保"工作,本以为可以万无一失,中午在安心的睡觉中,被人告知数据库crash了.当时的 ...

  7. 3-4:一个简单的HTTP服务器

    文章目录 HTTP服务器 HTTP服务器 我们使用浏览器请求某一个网页时,浏览器会向相应的服务器发送请求,服务器得到请求后会将报文传送回来,然后浏览器解析,就形成了我们所看见到的网页 这里我们可以写一 ...

  8. 一个Bug能有多大影响:亏损30亿、致6人死亡、甚至差点毁灭世界...

    欢迎关注方志朋的博客,回复"666"获面试宝典 作者:博雯   来源:量子位(QbitAI) 一个Bug就地蒸发5亿美元: 软件设计层面出Bug致6人死亡: DeBug不成功直接世 ...

  9. 从一个Bug开始,重新认识一个强大的 Gson

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 作者:Mafly, 地址:www.cnblogs.com/mafly/p/gson.html 从 ...

最新文章

  1. c语言 char转int_C语言关键字及进制的转换你都知道吗?
  2. 莫博士:Facebook别再推诿,请承担打击假新闻责任
  3. json的键为变量而不是字符串时,怎么写?
  4. 判断不为空和不为空串的方法java
  5. Vue3 --- axios 简单封装APi
  6. HarmonyOS分布式软总线研究,【钟洪发老师公开课】实战学习HarmonyOS重点之分布式软总线...
  7. Win7系统屏保也可以当桌面壁纸
  8. 远控免杀从入门到实践(2)工具总结篇
  9. 【mock】数据模板定义规范DTD 数据占位符定义规范DPD
  10. 从苏宁电器到卡巴斯基第17篇:曲折考研路(上)
  11. 计算机老师教育感言,66句震撼人心的老师教育感言
  12. python是高级语言还是低级语言_机械语言/汇编语言/低级语言/高级语言各是指的什么...
  13. Android中的短信收不到问题,手机收不到短信怎么回事?怎么恢复
  14. [附源码]计算机毕业设计校园运动会管理系统Springboot程序
  15. 今天完成了股票自动化交易软件1.2版本了
  16. Flutter -- Element生命周期
  17. B BL BLX BX详解
  18. (vue)vue导出excel文件打不开,或者文件内容为object object
  19. 网站浏览计数器html,Web浏览计数器的设计应用
  20. 平安金融云为互联网金融行业注入发展新动能

热门文章

  1. 牛逼了!菜鸟也能用Python演奏一段钢琴曲
  2. 2023年完美解决:windows 11/win 11使用经典右键菜单(win10版右键菜单)
  3. 动态规划:矩阵连乘问题
  4. 用Python实现全国二手房数据抓取+地图展示
  5. 文件服务器 上传 下载
  6. 苹果xsmax电池容量_两大旗舰对比,xsmax对比11promax,究竟谁孰强孰弱?
  7. java中草药美白淡斑紧肤膏_中药美白淡斑的方法
  8. html5 指纹识别,Http指纹识别技术
  9. ## C51单片机2种方法让8个流水灯依次亮灭
  10. JWT登录过期自动刷新方案与token泄漏解决方案