- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
今天本来想写一篇 非托管泄露 的生产事故分析,但想着昨天就上了一篇非托管文章,连着写也没什么意思,换个口味吧,刚好前些天有位朋友也找到我,说他们的拍摄监控软件卡死了,让我帮忙分析下为什么会卡死,听到这种软件,让我不禁想起了前些天 在程序员桌子上安装监控 的新闻,参考如下:
我在想我这不是尼玛作恶吗... 😂😂😂 和朋友确认了下还好不是干这个事的.
因为这种监控软件是窗体程序,所以它的卡死理应看主线程的调用栈即可, 在windbg中有一个 k 命令.
0:000:x86> kb 8
# ChildEBP RetAddr Args to Child
00 00dbedc0 77835329 0fd54c08 00000000 0fd54c08 ntdll_777d0000!NtWaitForAlertByThreadId+0xc
01 00dbedc0 7783505c 00000000 00000000 0fd54c08 ntdll_777d0000!RtlpWaitOnAddressWithTimeout+0x64
02 00dbee60 77813fd8 0fd543f0 0fd54c04 0000000c ntdll_777d0000!RtlpWaitOnCriticalSection+0x1ac
03 00dbeea8 77813d99 00000000 00dbef04 09d72f87 ntdll_777d0000!RtlpEnterCriticalSectionContended+0x228
04 00dbeeb4 09d72f87 0fd54c04 09d38131 ee66de6e ntdll_777d0000!RtlEnterCriticalSection+0x49
WARNING: Stack unwind information not available. Following frames may be wrong.
05 00dbef04 09d38036 ee66de46 000001fd 00000111 scvncctrl!DllUnregisterServer+0x4ed7
06 00dbef2c 09d3304d 00000111 000001fd 00000111 scvncctrl+0x48036
07 00dbef50 09d341f3 00000111 000001fd 00000001 scvncctrl+0x4304d
从卦象来看,程序在 scvncctrl!DllUnregisterServer+0x4ed7 方法中等待 临界区锁 ,即 RtlEnterCriticalSection 处.
可能有些朋友有疑问,为什么 scvncctrl 后面的偏移值那么大,这是因为 scvncctrl 没有提供公有和私有符号,所以无法对应函数名,windbg 只能以 module 为参考点设置偏移,这对 dump 分析产生了很大的阻碍! 。
接下来继续看,既然主线程在等待锁,那必然有人在持有锁,那到底是谁在持有呢?
要想找到持有者,可以提取 RtlEnterCriticalSection 方法中的第一个参数 0fd54c04 ,我们使用 dt _RTL_CRITICAL_SECTION 命令即可.
0:000:x86> dt _RTL_CRITICAL_SECTION 0fd54c04
ntdll_777d0000!_RTL_CRITICAL_SECTION
+0x000 DebugInfo : 0x07ba4428 _RTL_CRITICAL_SECTION_DEBUG
+0x004 LockCount : 0n-6
+0x008 RecursionCount : 0n1
+0x00c OwningThread : 0x0000621c Void
+0x010 LockSemaphore : 0xffffffff Void
+0x014 SpinCount : 0x200064a
上面的 OwningThread 就是当前的持有线程,找到了之后切过去看下它的线程栈,它到底在干嘛?
0:005:x86> ~~[0x0000621c]s
ntdll_777d0000!NtWaitForSingleObject+0xc:
7784619c c20c00 ret 0Ch
0:005:x86> kb
CvRegToMachine(x86) conversion failure for 0x14f
X86MachineInfo::SetVal: unknown register 0 requested
# ChildEBP RetAddr Args to Child
00 0a8cf1ac 747ccfd5 00000924 00000001 00000000 ntdll_777d0000!NtWaitForSingleObject+0xc
01 0a8cf1ac 747ddb12 00000002 00000006 ae23e128 mswsock!SockWaitForSingleObject+0x125
02 0a8cf220 75c05fe5 000007e8 0a8cf258 00000001 mswsock!WSPRecv+0x232
03 0a8cf26c 09ddd32f 000007e8 011a5a30 00002000 ws2_32!recv+0x95
WARNING: Stack unwind information not available. Following frames may be wrong.
04 0a8cf3b4 09ddd0a6 011a5a30 00002000 00000003 scvncctrl!DllUnregisterServer+0x6f27f
05 0a8cf4d4 09ddd625 00000001 00000001 07ac4ae0 scvncctrl!DllUnregisterServer+0x6eff6
06 0a8cf5f0 09ddd72f 0fd1f350 07ac4ae0 00000000 scvncctrl!DllUnregisterServer+0x6f575
07 0a8cf708 09d70626 00000003 00000001 0fd543f0 scvncctrl!DllUnregisterServer+0x6f67f
08 0a8cf958 09d71b56 00000075 000001f7 0000070b scvncctrl!DllUnregisterServer+0x2576
09 0a8cf9a4 09d3140c 00000075 000001f7 0000070b scvncctrl!DllUnregisterServer+0x3aa6
0a 0a8cfa18 09d35b89 e431cbea 0fd5fbf0 0fd543f0 scvncctrl+0x4140c
0b 0a8cfa80 09d73189 00000000 09d73120 0a8cfacc scvncctrl+0x45b89
0c 0a8cfa90 09e09434 0fd543f0 e431cba6 09e093dd scvncctrl!DllUnregisterServer+0x50d9
0d 0a8cfacc 75c77ba9 0fd5fbf0 75c77b90 0a8cfb34 scvncctrl!DllUnregisterServer+0x9b384
0e 0a8cfadc 7783b79b 0fd5fbf0 c738a5e9 00000000 kernel32!BaseThreadInitThunk+0x19
0f 0a8cfb34 7783b71f ffffffff 778689f7 00000000 ntdll_777d0000!__RtlUserThreadStart+0x2b
卦中的 ws2_32!recv 是一个win32体系内的方法,用于 接收客户端发送数据 ,可能有些朋友对 recv 方法不是很清楚,方法签名大概如下:
int recv(
SOCKET s,
char *buf,
int len,
int flags
);
因为是主控端,我在网上找了一段 win32 实现的 server 版的 recv 完整代码.
#define _WINSOCK_DEPRECATED_NO_WARNINGS
//1.头文件
#include <stdio.h>
#include <Winsock2.h>
#pragma comment (lib,"ws2_32.lib")
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("请求版本失败!\n");
return -1;
}
printf("请求版本成功!\n");
SOCKET serverScoket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == serverScoket)
{
printf("创建套接字失败!\n");
WSACleanup();
return -1;
}
printf("创建套接字成功!\n");
SOCKADDR_IN serverAddr = { 0 };
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8888);
serverAddr.sin_addr.S_un.S_addr = inet_addr("192.168.0.107");
if (SOCKET_ERROR == bind(serverScoket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)))
{
printf("绑定失败!\n");
closesocket(serverScoket);
WSACleanup();
return -1;
}
printf("绑定成功!\n");
if (SOCKET_ERROR == listen(serverScoket, 10))
{
printf("监听失败!\n");
closesocket(serverScoket);
WSACleanup();
return -1;
}
printf("监听成功!\n");
SOCKADDR_IN clientAddr = { 0 };
int len = sizeof(clientAddr);
SOCKET clientSocket = accept(serverScoket, (sockaddr*)&clientAddr, &len);
if (INVALID_SOCKET == clientSocket)
{
printf("接受链接失败!\n");
closesocket(serverScoket);
WSACleanup();
return -1;
}
printf("接受客户链接成功!\n");
printf("客户ip为:%s", inet_ntoa(clientAddr.sin_addr));
//8.开始通讯
char recvbuff[1024] = {};
char sendbuff[1024] = {};
//参数一:代表客户端的socket,表示从客户端进行收取数据
//参数二:接受的数据存放地址
//参数三:接受数据的长度
//参数四:表示收发方式,0表示默认,一次收完
while (true)
{
//保存数据清空
memset(recvbuff, 0, sizeof(recvbuff));
//从客户端接受数据
if (recv(clientSocket, recvbuff, sizeof(recvbuff) - 1, 0) > 0)
{
printf("客户说:%s\n", recvbuff);
}
else
{
break;
}
memset(sendbuff, 0, sizeof(sendbuff));
printf("我说:");
scanf_s("%s", sendbuff, sizeof(sendbuff) - 1);
//发送数据给客户端
send(clientSocket, sendbuff, strlen(sendbuff), 0);
}
//9.关闭链接
closesocket(clientSocket);//关闭客户端socket
closesocket(serverScoket);//关闭服务端socket
WSACleanup(); //关闭套接字请求
return 0;
}
结合上面的完整代码,业务逻辑应该是 while (true) 里的 send 和 recv 区间内的某句代码持有了锁,但因为某种 异常 导致持有的 临界区锁 没有释放,出现了一种 锁污染 的情况.
朋友提供的信息也进一步佐证了这种说法.
这些情况组合在一起导致了 send 和 recv 之间的某处代码异常污染了 临界区锁 .
本来想提取下 recv 中的 socket 信息,结果发现是一个 网络句柄号 ,真正的socket信息在内核层,没法提出来只能作罢,截图如下:
也即线程栈上的 000007e8 字段.
0a8cf26c 09ddd32f 000007e8 011a5a30 00002000 ws2_32!recv+0x95
那这个问题怎么解决呢? 通篇分析下来应该就是 scvncctrl 的 bug,能做的就是升级到最新版本,毕竟程序里还是 2020 年的.
0:005:x86> lmvm scvncctrl
Browse full module list
start end module name
09cf0000 09f06000 scvncctrl (export symbols) scvncctrl.dll
Loaded symbol image file: scvncctrl.dll
Image name: scvncctrl.dll
Browse all global symbols functions data
Timestamp: Sat Oct 10 15:14:33 2020 (5F815F59)
CheckSum: 001CA728
ImageSize: 00216000
File version: 3.9.2.0
Product version: 3.9.2.0
File flags: 0 (Mask 3F)
File OS: 4 Unknown Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0409.04b0
Information from resource tables:
CompanyName: SmartCode Pte. Ltd.
ProductName: SmartCode VNC Viewer ActiveX
OriginalFilename: scvncctrl.dll
ProductVersion: 3.9.2.0
FileVersion: 3.9.2.0
FileDescription: SmartCode VNC Viewer ActiveX
LegalCopyright: Copyright (c) 2003-2020 SmartCode Pte. Ltd. All rights reserved.
Comments: https://www.s-code.com
这次卡死事故还是挺有教育意义的,告诉我们第三方插件尽量 应升尽升 ,同时也考察了对 临界区锁 和 socket 的基础知识.
最后此篇关于记一次.NET某拍摄监控软件卡死分析的文章就讲到这里了,如果你想了解更多关于记一次.NET某拍摄监控软件卡死分析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
前言 在进行Maven开发时,往往需要下载大量jar包,而由于网络不稳定等其他因素可能导致jar未下载完毕,然后保留了lastUpdated文件,导致无法更新失效的jar包。 本文分享 bat脚本,自
按字母顺序排序并不是我们花太多时间担心的事情。我们在很小的时候就学习了字母表,现在我们知道它(拉丁文)以 A 开头,然后是 B,然后是 C 等等,一直到 Z。 但是这个订单究竟存储在计算机系统中的什么
我尝试使用可分离为 2 个一维向量的二维矩阵来证明二维傅里叶变换的信号属性的可分离性。地点: f(x,y) = f(x)*f(y) 那么 F(u,v) = F(u)*F(v) 使用以下代码: % Se
我需要为几个小型sqlite数据库编写文档。想描述数据的使用方式,包括表和行说明以及示例数据。 是否可以使用MySQL Workbench?如果没有其他选择,或者我可以使用任何模板? TIA! 最佳答
我正在尝试使用旧版本(例如:1.4.5)安装 memcached,但我不知道该怎么做。 brew install memcached安装最新的。 我也试过 brew install memecache
背景 多年来,我一直使用自己的类似贝叶斯方法,根据大型且不断更新的训练数据集对来自外部来源的新项目进行分类。 每个项目都有三种类型的分类: 30 个类别,其中每个项目必须属于一个类别,且最多属于两个类
嗨,我需要确定 4 个数字是否相等。数字是 size(A,1)、size(B,1)、size(C,1) 和 size(D,1),其中,例如A = [1 2; 3 4], B=[1 2 3, 4 5 6
Wikipedia 中的文章似乎太冗长了。 我将框架理解为一组精心设计的库和工具。 Qt 框架为跨平台 GUI 提供了一组库/工具。 cocoa 框架为 Mac 做了同样的事情。 软件框架的实际定义是
我们的客户最近发现了这个网站: http://mydeco.com/3d-planner/ 它有一个非常非常奇特且组合良好的 3d CAD Web 应用程序,似乎是使用 jQuery 编写的,而不是
我们正在寻找一种独立的(非 cms)日历解决方案来显示在网络上。它可以是开源的或付费服务。 我们主要是在寻找一种在 Web 上显示日历的方法,其中包含事件发生的时间和事件的名称。如果它可以按周、月、年
我想知道与软件相关的“质量保证”和“质量科学”之间的区别。 我在Google上进行了研究,但未找到有关“质量科学”的任何信息。 最佳答案 Based on the link you have prov
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
我有一个由 2 个方程和 2 个未知数组成的系统,我想使用 MATLAB 求解,但不知道如何编程。我得到了一些有关 Gamma 分布的信息(平均值为 1.86,90% 的间隔介于 1.61 和 2.1
给定一个矩阵,其中 1 是当前子集 test = 0 0 0 0 0 0 0 0 0 0 0 0
我在组合 Matlab“数据”变量的重复元素时遇到问题。我可以使用 unique 和 sort 轻松组合这些值。 [sorted,idx] = sort(data); [~,ij] = unique(
我在做的问题中有这么一段代码,如下图。定义部分只是为了向您展示数组的大小。下面我粘贴了矢量化版本 - 它慢了 2 倍以上。为什么会这样?我知道如果矢量化需要大的临时变量,我就会发生,但(看起来)这里不
我有一个 3D 矩阵,我想将它的每个 2D 分量存储在另一个 2D 矩阵的行中,该 2D 矩阵有许多行作为 3D 矩阵的第 3 维。 我该怎么做? 最佳答案 与 permute & reshape -
如果计算机能够使用纯 JavaScript(Google V8)、C++(Windows、Mac OS 和 Linux)运行程序/软件而没有任何性能问题,是否有任何好的方法可以通过要求尽可能少尽可能从
我的团队的任务是将用于播放媒体文件的全屏、信息亭式应用程序从 Windows 迁移到嵌入式 ARM Linux(瘦客户端)。我们需要在 sd/1080p 中支持 mpeg-2 播放以及 HTML、SW
我们有数以千计的具有白色或黑色或渐变背景的产品图片。我们正在寻找可以去除图片背景的软件或服务。我们需要一款能够很好地完成这项工作的智能软件。 最佳答案 在 photoshop 中,您可以记录 Acti
我是一名优秀的程序员,十分优秀!