前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >句柄泄露问题追踪

句柄泄露问题追踪

作者头像
河边一枝柳
发布2021-08-06 14:57:55
1.3K0
发布2021-08-06 14:57:55
举报

无论是在编写Windows程序还是Linux程序,都可能存在句柄泄露的问题。在Linux中一般来说一个进程的fd使用是有上限的,可以使用ulimit命令进行上限查看,当出现fd泄露的时候,可能会出现socket创建失败,文件打不开等问题。Windows类似,本文主要阐述了对Windows中的句柄泄露的追踪方法。

Windows句柄泄露

在Windows开发中,当调用Windows API,比如CreateFile, CreateEvent, CreateThread 等API的时候,都会返回一个句柄Handle。当相应的资源使用完后,如果没有调用CloseHandle去关闭Handle,则会出现句柄泄露的问题。当这个问题发生的时候,当前进程再调用比如CreateThread会返回Windows Error 1450, 表示Insufficient system resources exist to complete the requested service.,导致程序运行问题。Windows的总句柄数,也是有限制的,此时甚至会影响其他进程的运行。那么接下来让我们来看看如何定位句柄泄露问题吧。

Process Explorer定位句柄泄露

在任务管理器中可以查看一个进程的句柄数量,在Process Explorer中也可以。我们可以这样去定位句柄泄露问题:

1. 可以在Process Explorer中显示Handles一列,如果进程有句柄泄露问题,那么这个进程的Handles一列的数值会持续的增长

2. 选中相应的进程,可以观察本进程的句柄详细信息。比如这个句柄,关联的是线程、文件、Event等等。

3. 当出现句柄泄露的时候,那么会有大量的相似的类型的句柄出现在其中。

如果因为CreateThread的句柄没有释放,导致句柄泄露,那么则可以在句柄详细信息的条目中看到很多Thread类型的。然后查找可能调用CreateThread的代码。

如果因为CreateFile的句柄没有释放,则可以在Process Explorer中查看文件的路径,根据文件的路径来查找可能引起句柄泄露的代码。

这种方式可以解决一部分句柄泄露问题,但是有时候可能碰到一些场景不能解决:

  1. 一个产品可能依赖于多个第三方模块,当句柄泄露的问题是第三方模块引起的,可能看到泄露句柄类型和名字也难以定位到具体的模块。
  2. Process Explorer不能够显示所有的句柄,比如无名的Event,这样也无法查找。

Windbg定位句柄泄露问题

除了上一章末讲的两个问题,那么有没有一种方法可以定位到这个泄露的句柄申请的地方吗?Windbg就可以做到。 先上一段测试的Sample, 每隔一秒钟创建一个Event,但并没有调用CloseHandle, 会导致Handle Leak。

代码语言:javascript
复制
#include <windows.h>
#include <iostream>
#include <thread>

void HandleLeak()
{ 
  int iCount = 0;
  while(true)
  {
    iCount++;
    HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    DWORD dwError = GetLastError();
    std::this_thread::sleep_for(std::chrono::seconds(1));
    if (!hEvent || dwError != ERROR_SUCCESS)
    {
      std::cerr << "Number: " << iCount << " Error: "<< dwError << std::endl;
      return;
    }
  }
}

int main()
{
  HandleLeak();
  return 0;
}

第一步 用Windbg attach到你要测试进程 第二步 Windbg中调用命令!htrace -enable: 开启句柄追踪,并且保存当前所有的Handle的快照(Snapshot)

代码语言:javascript
复制
0:006> !htrace -enable
Handle tracing enabled.
Handle tracing information snapshot successfully taken.

第三步 Windobg中调用命令g, 让程序运行一段时间 第四步 菜单Debug->break进入调试,Windbg中运行!htrace -diff: 将进程当前的所有的句柄和之前快照的句柄进行对比,找出这段时间内多出来的句柄。

代码语言:javascript
复制
0:006> !htrace -diff
Handle tracing information snapshot successfully taken.
0x31 new stack traces since the previous snapshot.
Ignoring handles that were already closed...
Outstanding handles opened since the previous snapshot:
--------------------------------------
Handle = 0x0000000000000290 - OPEN
Thread ID = 0x0000000000001ca0, Process ID = 0x0000000000004360

0x00007ffca4dcb2a4: ntdll!NtCreateEvent+0x0000000000000014
0x00007ffca1ebb623: KERNELBASE!CreateEventA+0x0000000000000083
0x00007ff7ea001e94: HandleLeak!HandleLeak+0x0000000000000034
0x00007ff7ea002099: HandleLeak!main+0x0000000000000009
0x00007ff7ea0023d4: HandleLeak!__scrt_common_main_seh+0x000000000000010c
0x00007ffca23f4034: KERNEL32!BaseThreadInitThunk+0x0000000000000014
0x00007ffca4da3691: ntdll!RtlUserThreadStart+0x0000000000000021
--------------------------------------
Handle = 0x0000000000000280 - OPEN
Thread ID = 0x0000000000001ca0, Process ID = 0x0000000000004360

0x00007ffca4dcb2a4: ntdll!NtCreateEvent+0x0000000000000014
0x00007ffca1ebb623: KERNELBASE!CreateEventA+0x0000000000000083
0x00007ff7ea001e94: HandleLeak!HandleLeak+0x0000000000000034
0x00007ff7ea002099: HandleLeak!main+0x0000000000000009
0x00007ff7ea0023d4: HandleLeak!__scrt_common_main_seh+0x000000000000010c
0x00007ffca23f4034: KERNEL32!BaseThreadInitThunk+0x0000000000000014
0x00007ffca4da3691: ntdll!RtlUserThreadStart+0x0000000000000021

第五步 通过上述的Handle调用栈,就很容易能够知道导致句柄泄露的代码了。

以上方法可以比较完美的解决句柄泄露问题,但是如果问题本地难以重现,需要到客户环境中查找句柄泄露问题,那么一般不太建议Symbols拷贝到客户的环境中,以免造成Symbols泄露。那么上述第四步中就无法查看到明确的函数调用栈,可以从客户环境中拷贝出来第四步!htrace -diff的信息,然后再自己本地Load Symbols后通过ln HandleLeak+0x....查看相应的函数调用栈,从而定位问题。

除了以上方法,还有一些可以在Windbg中直接查看Handle的方式来查找句柄泄露:

  1. 通过!handle命令查看当前进程的所有句柄
  2. 通过对比两个时间点的!handle命令的结果,找出句柄泄露的类型
  3. 找出两个时间点差异化的句柄的索引,再使用!handle <handle index> f查看句柄的详细信息。
  4. 通过泄露的句柄的类型,详细信息(比如名称)来辅助定位可能的句柄泄露位置
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一个程序员的修炼之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Windows句柄泄露
  • Process Explorer定位句柄泄露
  • Windbg定位句柄泄露问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档