一:背景

1. 讲故事

前些天有位朋友在微信上联系到我,说他们的程序在客户那边崩掉了,让我帮忙看下怎么回事,dump也拿到了,那就上手分析吧。

二:WinDbg 分析

1. 哪里的崩溃

既然是程序的崩溃,自然是有原因的,皮裤套棉裤,必定有缘故,不是皮裤太薄就是棉裤没毛,用 !analyze -v 观察下异常信息。


0:107> !analyze -v CONTEXT: (.ecxr)
rax=0000005e0dc7c4a0 rbx=0000005e0dc7c400 rcx=0000005e0dc7c4a0
rdx=0000000000000000 rsi=0000005e0dc7c3f0 rdi=0000005e0dc7c4a0
rip=00007ffb1ecfc223 rsp=0000005e0dc7c3c0 rbp=0000005e0dc7c4c0
r8=00000000000004d0 r9=0000000000000000 r10=0000000000000000
r11=0000005e0dc7c4a0 r12=0000000000000000 r13=000002079d450220
r14=000002079b93aba0 r15=0000000000000000
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000200
coreclr!EEPolicy::HandleFatalError+0x7f:
00007ffb`1ecfc223 488d442440 lea rax,[rsp+40h]
Resetting default scope EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 00007ffb1ec6d70f (coreclr!ProcessCLRException+0x00000000000d9f7f)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000001
NumberParameters: 0

从卦中信息看这是一个经典的 访问违例,但崩溃在 EEPolicy::HandleFatalError 处就有点匪夷所思了,HandleFatalError 方法主要是用来在抛异常之前修整异常上下文的,这个方法固若金汤,一般不会出问题的,但不管怎么样,还是看下 rsp+40h 到底是什么东西。


0:107> dp rsp+40h L1
0000005e`0dc7c400 00000001`c0000005

上面的 c0000005 很显然是访问违例,看样子这里有点混乱,也不是第一崩溃现场,这里就不过多纠结了,那怎么去找真正的崩溃点呢?还有一个方法就是去找 RaiseException 或者 KiUserExceptionDispatch 返回点之前的有用函数,参考如下:


0:107> .ecxr
0:107> k
*** Stack trace for last set context - .thread/.cxr resets it
# Child-SP RetAddr Call Site
00 0000005e`0dc7c3c0 00007ffb`1ec6d72e coreclr!EEPolicy::HandleFatalError+0x7f [D:\a\_work\1\s\src\coreclr\vm\eepolicy.cpp @ 776]
01 0000005e`0dc7c9d0 00007ffb`5235292f coreclr!ProcessCLRException+0xd9f9e [D:\a\_work\1\s\src\coreclr\vm\exceptionhandling.cpp @ 1036]
02 0000005e`0dc7cc00 00007ffb`52302554 ntdll!RtlpExecuteHandlerForException+0xf
03 0000005e`0dc7cc30 00007ffb`5235143e ntdll!RtlDispatchException+0x244
04 0000005e`0dc7d340 00000000`6c942893 ntdll!KiUserExceptionDispatch+0x2e
05 0000005e`0dc7daf0 00007ffa`c066ed7b libxxx_manage!get_clean_xxx
06 0000005e`0dc7db70 00007ffa`c06b73a4 0x00007ffa`c066ed7b
...

从卦中看,程序崩溃在 libxxx_manage!get_clean_xxx 中,看样子是一个 C++ 写的动态链接库,这就有点无语了。。。

2. C++ 库为什么会崩

要想寻找答案,最好的办法就是观察 000000006c942893 处的汇编代码,参考如下:


0:107> ub 00000000`6c942893
libxxx_manage!get_clean_xxx:
00000000`6c942876 55 push rbp
00000000`6c942877 53 push rbx
00000000`6c942878 4883ec68 sub rsp,68h
00000000`6c94287c 488dac2480000000 lea rbp,[rsp+80h]
00000000`6c942884 48894d00 mov qword ptr [rbp],rcx
00000000`6c942888 c745dc00000000 mov dword ptr [rbp-24h],0
00000000`6c94288f 488b4500 mov rax,qword ptr [rbp] 0:107> u 00000000`6c942893
00000000`6c942893 488b00 mov rax,qword ptr [rax] 0:107> dp rbp L1
0000005e`0dc7c4c0 00000000`00000000

从上面的汇编代码来看,这是 get_clean_xxx 方法的序幕代码,问题出在 rbp 的内容为0上,但 rbp 又来自于 rcx,根据 x64调用协定,rcx 即方法的第一个参数,看样子是这个参数为 null 导致的,参考如下:


0:107> !address rcx Usage: Stack
Base Address: 0000005e`0dc78000
End Address: 0000005e`0dc80000
Region Size: 00000000`00008000 ( 32.000 kB)
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE
Allocation Base: 0000005e`0db00000
Allocation Protect: 00000004 PAGE_READWRITE
More info: ~107k 0:107> dp rcx L1
0000005e`0dc7c4a0 00000000`00000000

3. get_clean_xxx 参数为null吗

这个问题比较简单,继续用 !clrstack 观察下 Pinvoke 之上的 C# 代码。


0:107> !clrstack
OS Thread Id: 0x3508 (107)
Child SP IP Call Site
0000005E0DC7DBA0 00007ffac066ed7b [InlinedCallFrame: 0000005e0dc7dba0] xxx_LibPInvoke.xxx_clean_query(IntPtr)
0000005E0DC7DB70 00007ffac066ed7b ILStubClass.IL_STUB_PInvoke(IntPtr)
0000005E0DC7DC30 00007ffac06b73a4 xx+c__DisplayClass11_0.<xxxQueryClean>b__0(IntPtr)
...

接下来就是看下托管层的 C# 代码是如何写的,截图如下:

从图中可以清楚的看到,xxxChannel 传给C++ 的时候没有判断是否为null,导致崩溃的发生,那还有没有其他的佐证呢?其实也是有的,如果符号给力还可以使用 !clrstack -a 去找到 xxxChannel 传下去的值。


0:107> !clrstack -a
OS Thread Id: 0x3508 (107)
Child SP IP Call Site
0000005E0DC7DBA0 00007ffac066ed7b [InlinedCallFrame: 0000005e0dc7dba0] xxx_LibPInvoke.xxx_clean_query(IntPtr)
0000005E0DC7DB70 00007ffac066ed7b ILStubClass.IL_STUB_PInvoke(IntPtr)
PARAMETERS:
<no data> 0000005E0DC7DC30 00007ffac06b73a4 xxx+c__DisplayClass11_0.<xxxQueryClean>b__0(IntPtr)
PARAMETERS:
this (0x0000005E0DC7DC80) = 0x0000020a9d9ca8d8
xxxChannel (0x0000005E0DC7DC88) = 0x0000000000000000
LOCALS:
0x0000005E0DC7DC6C = 0x0000000000000000
0x0000005E0DC7DC68 = 0x0000000000000000

可以清楚的看到确实是 0,到这里就一切真相大白,对参数加一个判断即可,那这东西到底是谁的责任呢?我觉得双方都有问题吧。

  1. 写托管层的人有点飘。
  2. 写非托管层的人未作防御性编程,还是年轻太相信人了。

三:总结

这次生产事故彻底破坏了两个语言团队之间的相互合作的信任度,信任重建可就难了,不怕神一样的对手,就怕猪猪一样的队友,放在这里还是挺合适的,哈哈,开个小玩笑。

记一次 .NET某实验室自动进样系统 崩溃分析的更多相关文章

  1. 记一次 .NET 某企业 ERP网站系统 崩溃分析

    一:背景 1. 讲故事 前段时间收到了一个朋友的求助,说他的ERP网站系统会出现偶发性崩溃,找了好久也没找到是什么原因,让我帮忙看下,其实崩溃好说,用 procdump 自动抓一个就好,拿到 dump ...

  2. 记一次 .NET 某医疗住院系统 崩溃分析

    一:背景 1. 讲故事 最近收到了两起程序崩溃的dump,查了下都是经典的 double free 造成的,蛮有意思,这里就抽一篇出来分享一下经验供后面的学习者避坑吧. 二:WinDbg 分析 1. ...

  3. 惠普M1005打印机无法自动进纸的问题

    惠普M1005打印机无法自动进纸的问题 问题起因 其实我也不太清楚是什么起因,前一天用的好好的惠普M1005打印机,在打印时没有直接打印,会弹出一个提示对话框,同时打印机显示屏上显示“load tra ...

  4. Spring Boot自动装配原理源码分析

    1.环境准备 使用IDEA Spring Initializr快速创建一个Spring Boot项目 添加一个Controller类 @RestController public class Hell ...

  5. [LeetCode] Design Search Autocomplete System 设计搜索自动补全系统

    Design a search autocomplete system for a search engine. Users may input a sentence (at least one wo ...

  6. Cobbler自动部署主机系统

    Cobbler自动部署主机系统 简介: Cobbler由python语言开发,是对PXE和 Kickstart以及DHCP的封装.融合很多特性,提供了CLI和Web的管理形式.更加方便的实行网络安装. ...

  7. SQL 报表 --简易进销系统

    模型图: -- ============================================ -- Author: lifu -- Create Date: 2017-06-18 -- D ...

  8. 基于DRL和TORCS的自动驾驶仿真系统——之环境配置

    基于DRL和TORCS的自动驾驶仿真系统 --之环境配置 玩TORCS和DRL差不多有一整年了,开始的摸爬滚打都是不断碰壁过来的,近来在参与CMU的DRL10703课程学习和翻译志愿者工作,也将自己以 ...

  9. 自动安装 linux 系统

    实现自动安装 centos 6 和 centos 7 实现自动安装 Linux 系统需要在虚拟机上安装三个服务:apache .tftp.dhcp 三个服务放在一台虚拟机上即可 一.DHCP 服务器的 ...

  10. [LeetCode] 642. Design Search Autocomplete System 设计搜索自动补全系统

    Design a search autocomplete system for a search engine. Users may input a sentence (at least one wo ...

随机推荐

  1. Android 7.0 开机时间优化

    原文参考(有删改):https://www.jianshu.com/p/6dba42c022a9 问题描述 开机时间相对参考机过慢,大约慢15s左右.Android 系统7.0. 问题分析 开机问题涉 ...

  2. Linux 时间 与 定时器

    背景 在学习 Linux 信号 有关知识中,提到了 alarm函数. 进程时间 (原文地址:https://www.cnblogs.com/clover-toeic/p/3845210.html) 进 ...

  3. @ConfigurationProperties 还能这样用

    在编写项目代码时,我们要求更灵活的配置,更好的模块化整合.在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或 applicat ...

  4. Vue2 移动端 ui库 MintUI

    MintUI MintUI是饿了么团队开发的基于移动端的vue组件库.用于搭建移动端界面. http://mint-ui.github.io/docs/#/zh-cn2

  5. leetcode简单(数组、字符串):[219, 268, 349, 414, 485, 541, 557, 821, 925, 977]

    目录 219. 存在重复元素 268. 丢失的数字 349. 两个数组的交集 414. 第三大的数 485. 最大连续 1 的个数 541. 反转字符串 II 557. 反转字符串中的单词 III 8 ...

  6. 【2024最新】4000字搞懂sora!一张脑图贯穿!

    话不多说,上图! 下面就是对sora的具体阐释: Sora是OpenAI推出的一款革命性的视频生成模型,能够根据文本指令.静态图像或视频生成长达60秒的完整视频.这一模型基于扩散式模型和自注意力深度学 ...

  7. 音频文件降噪及python示例

    操作系统 :Windows 10_x64 Python版本:3.9.2 noisereduce版本:3.0.2 从事音频相关工作,大概率会碰到降噪问题,今天整理下之前学习音频文件降噪的笔记,并提供Au ...

  8. 学习笔记--Java方法重载

    Java方法重载 感受 以下代码不使用"方法重载",不使用overload,分析程序存在的缺点 public class OverloadTest01 { // 入口 public ...

  9. SUM-2024成信大天梯赛

    查看代码中有仔细的批注 L1-5 yihan的新函数 题解:(字符串)需要用到一个知识,整数与字符串之间的变换"to_string()",字符串变成整数"stoll()& ...

  10. Oracle 序列学习与使用总结

    Oracle序列学习与使用总结 by:授客 QQ:1033553122 简述 序列是oracle提供的用于生成一系列数字的数据库对象,序列会自动生成顺序递增的序列号,可用于提供唯一的自动递增主键.序列 ...