我调过的最难调的Bug

每个程序员都有些不畏死亡决战猛兽的英雄事迹。以下这些是我的。

内存冲突

毕业不到半年,拿着刚到手的文凭,我在Lexmark公司的一个嵌入式Linux固件开发团队中负责追踪一个内存冲突的问题。因为内存冲突的原因和问题表象总是相差非常大,所以这类问题很难调。有可能是因为缓存溢出,也有可能是指针未初始化,或是指针被多次free,亦或是某处的DMA错误,但是你所见的却是一堆神秘的问题:挂起、指令未定义、打印错误,以及未处理的内核错误。这些都非常频繁,内存冲突看上去似乎是随机出现又很难重现。

要调试这种问题,第一步是可重现问题。在我们奇迹般地找到这样一个场景之后,故事开始变得好玩起来。

当时,我们发现在运行时因内存冲突而产生的程序崩溃每几百小时就会出现一次。之后有一天有人发现一个特别的打印任务会产生内存冲突从而在几分钟之内就使程序崩溃。我从来不知道为什么这个打印任务会产生这个问题。现在,我们就可以进一步做些什么了。

调试

这个问题可重现之后,我就开始寻找崩溃中出现的模式。最引人注意的是未定义指令和内核错误,它们差不多三分之一的时间就会发生一次。未定义指令的地址是一个合理的内核代码地址,但是CPU读到的这个指令却不是我们期望出现的。这就很简单了,可能是有人不小心写了这些指令。把这些未定义指令的句柄打印出来之后,我可以看到这些错误的指令所在位置的周边内存的状态。

在做了大量失败的将更多的代码排除出崩溃的尝试之后,一个特殊的崩溃渐渐显现。

崩溃之王

这个崩溃解开了所有秘密。当时我们用了一个双核CPU。在这个特殊的崩溃里,首先CPU1在有效的模块地址范围内收到了一个未处理的内核错误,而此时它正在尝试执行模块代码,这段代码可能是一个冲突的页表或是一个无效TLB。而正在处理这个错误时,CPU0在内核地址空间内收到了一个非法的指令陷阱。

以下是从修改后的未定义指令句柄中打印出来的数据(已转为物理地址,括号中是出错地址)


1

2

3

4

5

6

7

undefined instruction: pc=0018abc4

0018aba0: e7d031a2 e1b03003 1a00000e e2822008

0018abb0: e1520001 3afffff9 e1a00001 e1a0f00e

0018abc0: 0bd841e6 (ceb3401c) 00000004 00000001

0018abd0: 0d066010 5439541b 49fa30e7 c0049ab8

0018abe0: e2822001 eafffff1 e2630000 e0033000

0018abf0: e16f3f13 e263301f e0820003 e1510000

以下是内存域应该显示的数据:


1

2

3

4

5

6

0018aba0: e7d031a2 e1b03003 1a00000e e2822008

0018abb0: e1520001 3afffff9 e1a00001 e1a0f00e

0018abc0: e3310000 (0afffffb) e212c007 0afffff3

0018abd0: e7d031a2 e1b03c33 1a000002 e3822007

0018abe0: e2822001 eafffff1 e2630000 e0033000

0018abf0: e16f3f13 e263301f e0820003 e1510000

确切地来说,只有一行缓存(中间那32byte)是有冲突的。一个同事指出冲突行中0x49fa30e7这个字是一个魔术cookie,它标记了系统中一个特殊环形缓冲区的入口。入口值的最后一个字永远是一个时间戳,所以0x5439541b是上一个入口的时间戳。我决定去读取这个环形缓冲的内容,但它现在挂在一个不可执行的KGDB提示那了。机器现在跟死了一样。

冷启动攻击

为获取环形缓冲区的数据,我进行了一次冷启动攻击。我为正在使用的主板搞到了一份概要拷贝,然后发现CPU的复位线上连了一块不受欢迎的板子。我把它短路了,重置CPU而不妨碍DRAM的完整性。然后,我把Boot挂载在引导程序上。

在引导程序里,我dump到了问题中环形缓冲区的内容。谢天谢地,这个缓存总是在一个固定的物理地址上被定位到,所以找到它不是问题了。

通过分析错误时间戳周边的环形缓冲区,我们发现了两个老的cache line。这两个cache line里有有效数据,但是在这两个cache line里的时间戳却是环形缓冲区里之前的时间。

导致CPU0上未定义指令的cache line与环形缓冲区里那两个老cache line之一相当契合,但是这并不说明其他可能的地方也是这样。我发现一个决定性的证据。假设,另一个消失的cache line是导致CPU1上未处理内核错误的元凶。

错置的cache line

cache line应该被写入0x0ebd2bc0(环形缓冲区里的cache line),但是事实上却写入了0x0018abc0(冲突的内核码)。这些地址在我们CPU上属于相同的缓存,它们的位[14:5]的值是相同的。不知为何它们有别名。


1

2

3

4

                    bit   28   24   20   16   12    8    4    0

                           |    |    |    |    |    |    |    |

0x0ebd2bc0 in binary is 0000 1110 1011 1101 0010 1011 1100 0000

0x0018abc0 in binary is 0000 0000 0001 1000 1010 1011 1100 0000

一个地址的低5位是cache line(32字节cache line)里的索引。后10位,即位[14:5],表示缓存集。剩下的17位,即位[31:15],用来表示缓存里当前存的是哪个cache line.

我向我们的CPU供应商提交了一个bug报告,之后他们制定了一个解决方案,并在下一版本CPU里修复了这个bug。

我期望听到更多牛掰的此类故事,也期望我自己可以再攒点这样的。

信息来源:我调过的最难调的Bug

时间: 2024-10-13 22:08:48

我调过的最难调的Bug的相关文章

LAMP 系统性能调优之网络文件系统调优

LAMP 系统性能调优之网络文件系统调优 2011-03-21 09:35 Sean A. Walberg 网络转载 字号:T | T 使用LAMP系统的用户,都想把自己LAMP性能提高运行的速度提高,那它有一点可以调优: 网络文件系统 ,我们知道网络文件系统是网络共享磁盘的一个系统,我们来进行调优下! AD:2014WOT全球软件技术峰会北京站 课程视频发布 图-LAMP LAMP网络文件系统调优 网络文件系统(NFS)是一种通过网络共享磁盘的方法.NFS 可以帮助确保每个主机具有相同数据的拷

关于那些难改的bug

多年的测试经验中,经常发现有这么一种现象:总有些提了的bug不能顺利的被修复.这些bug往往有4个走向: 1.在被发现的版本中最终被解决,但中途花费较多周折. 2.有计划的在后续的版本中被解决. 3.决定永远不修复,却变成潜在的炸弹,在后续版本中被迫修复. 4.决定永远不修复,至今为止也一直没有被修复. 近期对我们做过的项目做过一次较大的统计,统计严重程度中等及以上的缺陷,这四种走向第一种占到了50%左右,第二.三种各占20%,最后一种约占了10%. 这些没有被修改的bug带来的负面影响有: 1

第三篇、调优之路 Apache调优

1.  简介 在第一篇中整合了apache + tomcat ,利用了apache解析静态文件为tomcat解压.但是在测试机上发现两者性能不足,不能充分利用服务器的性能,该篇中将对apache进行性能上调优 . 这里的调优针对的是window 平台下 ,linux下apache的调优后续再说. 2. apache调优 2.1 移除不用的模块 apache的功能相当强大,但不是在每个项目中都能用到其所有的功能,其中加载了一些我们通常用不到的模块,这其实是没有必要的 . 去除不用的模块方法很简单,

jvm原理及性能调优系列(jvm调优)

个人认为jvm调优主要通过以下方法解决 1.设置合适的最大堆内存(新生代和老生代的最大和值)和最小堆内存(jvm启动时占用的操作系统内存大小),及设置好堆的比例分配. 2.设置合适的新生代 因为对其对系统性能和GC回收有一定的影响. 3.设置合适的持久代 因为其直接决定系统可以支持多少个类定义和多少个常亮. 4.设置合适的线程栈 否则系统可能因为线程所需资源和空间不够而异常退出.

SQL Server调优基础系列 - 性能调优介绍

前言 关于SQL Server调优系列是一个庞大的内容体系,非一言两语能够分析清楚,本篇先就在SQL 调优中所最常用的查询计划进行解析,力图做好基础的掌握,夯实基本功!而后再谈谈整体的语句调优. 通过本篇了解如何阅读和理解查询计划.并且列举一系列最常用的查询执行运算符. 技术准备 基于SQL Server2008R2版本,利用微软的一个更简洁的案例库(Northwind)进行解析. 一.区别不同的运算符 在所有T-SQL语句在执行的时候,都会将语句分解为一些基本的结构单元,这些结构单元统称为:运

七、Hadoop学习笔记————调优之Hadoop参数调优

dfs.datanode.handler.count默认为3,大集群可以调整为10 传统MapReduce和yarn对比 如果服务器物理内存128G,则容器内存建议为100比较合理 配置总量时考虑系统调优块,双路四核2*4*2=16g,则总量设置为10到12比较合适,需要预留空间给其他服务器 需要给master分配足够资源,并且分配受限于yarn hadoop调优需要不断尝试,没有固定的套路

【Spark篇】---Spark调优之代码调优,数据本地化调优,内存调优,SparkShuffle调优,Executor的堆外内存调优

一.前述 Spark中调优大致分为以下几种 ,代码调优,数据本地化,内存调优,SparkShuffle调优,调节Executor的堆外内存. 二.具体    1.代码调优 1.避免创建重复的RDD,尽量使用同一个RDD 2.对多次使用的RDD进行持久化 如何选择一种最合适的持久化策略? 默认情况下,性能最高的当然是MEMORY_ONLY,但前提是你的内存必须足够足够大,可以绰绰有余地存放下整个RDD的所有数据.因为不进行序列化与反序列化操作,就避免了这部分的性能开销:对这个RDD的后续算子操作,

Spark学习之路 (九)SparkCore的调优之数据倾斜调优

摘抄自:https://tech.meituan.com/spark-tuning-pro.html 数据倾斜调优 调优概述 有的时候,我们可能会遇到大数据计算中一个最棘手的问题——数据倾斜,此时Spark作业的性能会比期望差很多.数据倾斜调优,就是使用各种技术方案解决不同类型的数据倾斜问题,以保证Spark作业的性能. 数据倾斜发生时的现象 绝大多数task执行得都非常快,但个别task执行极慢.比如,总共有1000个task,997个task都在1分钟之内执行完了,但是剩余两三个task却要

最近调的一个关于视频播放的小bug

上星期接到一个CQ,问题是这样的:下载官方的爱奇艺或者搜狐视频apk在板子上安装之后,无法正常播放在线视频,点击视频播放之后总是弹出对话框“XXX has stopped”,或者整个视频APP闪退. 于是我首先下载了一个爱奇艺的apk开始复现这个问题,然后从log进行分析,在kernel log发现线索: [ 392.674685] android: (01-02 01:17:32) process pid: 3352, tid: 4326 crash![ 392.682842] c0 4326