• 著名程序员刘涛涛WinMount程序BUG


    /**************************************
    /* 作者:半斤八兩
    /* 博客:http://cnblogs.com/bjblcracked
    /* 日期:2013-08-12  22:44
    /**************************************



    只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!



    同事说win也有mount工具,好奇心驱使就搜了一下.
    发现国内的著名程序员刘涛涛写了一款免费的win mount工具.
    于是下载了一份就开始玩起来了.安装后发现winmount程序的界面非常漂亮友好,而且广告也很少.
    甚是喜欢.图1

    0x1 bug
    只可惜我在使用的过程中,程序会占用100%CPU  :(

    0x2 BUG重现(如何产生).
    首先弄个压缩软件,我当前用的是 7z 加密压缩任意一个文件.(不加密文件名).
    然后用mount工具双击打开.这个时候就可以看到mount创建了一个新窗口.(输入密码框)
    此时我无意中点到父窗口,发现程父窗口也是活动窗口. (原来是非模态窗口,有点意思)图2

    知道是非模态窗口后,我就下意识的关闭了父窗口,有意思的事情发生了,CPU就跟打了鸡血一样,一个劲猛彪~图3

    一开始我不相信自己的眼睛,我在心里想,肯定是系统或者其他什么软件出了问题了.
    不可能是mount自身的问题.为了搞清楚到底是什么原因导致的CPU占用100,我决定分析它.

    OD载入后,自己能想到的所有断点,都试了一遍,都没有断下来.
    在一阵狂试都没有断下后,终于放弃下断点的方法了.

    找了几首经典歌曲,边听边想思路.

    mount占CPU的时候,操作系统虽然有点卡,但并没有卡死.
    说明至少不是 

    for(true){;} 
    while(true){;}

    这一类的死循环导致的卡死.

    所有自己已知的如等待类函数也都下断点测试过了.
    最后想就从线程下手吧.
    打开线程窗口,可以看到有四个线程在拼命工作,(为了方便查看,我们可以点一下user time)图4

    现在终于知道了,是这四个线程导致的,那么从entry处分析就行了.
    最终分析得知导致卡死的是  kernel32.GetQueuedCompletionStatus 这个函数.

    我们来看一下函数原型和介绍.

     1 GetQueuedCompletionStatus
     2 The GetQueuedCompletionStatus function attempts to dequeue an I/O completion packet from a specified I/O completion port. If there is no completion packet queued, the function waits for a pending I/O operation associated with the completion port to complete. 
     3 
     4 BOOL GetQueuedCompletionStatus(
     5   HANDLE CompletionPort,       // handle to completion port
     6   LPDWORD lpNumberOfBytes,     // bytes transferred
     7   PULONG_PTR lpCompletionKey,  // file completion key
     8   LPOVERLAPPED *lpOverlapped,  // buffer
     9   DWORD dwMilliseconds         // optional timeout value
    10 );
     1 6B1192E0          $  55            push ebp
     2 6B1192E1          .  8BEC          mov ebp, esp
     3 6B1192E3          .  83EC 0C       sub esp, 0C
     4 6B1192E6          .  56            push esi
     5 6B1192E7          .  8B35 4870126B mov esi, dword ptr ds:[<&KERNEL32.GetQue>;  kernel32.GetQueuedCompletionStatus
     6 6B1192ED          .  8D49 00       lea ecx, dword ptr ds:[ecx]
     7 6B1192F0          >  6A FF         push -1
     8 6B1192F2          .  8D45 FC       lea eax, dword ptr ss:[ebp-4]
     9 6B1192F5          .  50            push eax
    10 6B1192F6          .  8B47 08       mov eax, dword ptr ds:[edi+8]
    11 6B1192F9          .  8D4D F4       lea ecx, dword ptr ss:[ebp-C]
    12 6B1192FC          .  51            push ecx
    13 6B1192FD          .  8D55 F8       lea edx, dword ptr ss:[ebp-8]
    14 6B119300          .  52            push edx
    15 6B119301          .  50            push eax
    16 6B119302          .  FFD6          call near esi
    17 6B119304          .  8B45 FC       mov eax, dword ptr ss:[ebp-4]
    18 6B119307          .  85C0          test eax, eax
    19 6B119309          .^ 74 E5         je short WMCore.6B1192F0                 ;  // 这里导致死循环了~
    20 6B11930B          .  8B55 F8       mov edx, dword ptr ss:[ebp-8]
    21 6B11930E          .  8B40 14       mov eax, dword ptr ds:[eax+14]
    22 6B119311          .  E8 EAF7FFFF   call WMCore.6B118B00
    23 6B119316          .^ EB D8         jmp short WMCore.6B1192F0

    通过帮助文档介绍我们知道 kernel32.GetQueuedCompletionStatus 这个函数
    的意思是从指定的IOCP获取CP,当CP队列为空时.对此函数的调用将被阻塞.
    阻塞?没错,阻塞就不会占用CPU100%,但是他的IO句柄是父窗口创建的 父窗口关闭了,也把句柄析构了.
    他的逻辑写的是"死循环",所以句柄不存在了,就会不停的重复调用.也就会CPU占用100%了.



    0x3 修复方案
    1) 那个窗口改成模态窗口
    2) 父窗口关闭时,应该先提前关闭非模态窗口.



    这个应该也不能算是BUG吧,只能算是我误操作.  
    而且一般人应该也不会像我那样操作.直接关闭父窗口的  

    --==mount英文官方==--
    --==mount中文官方==--
    --==mount官方招聘==--

    才发现,英文版的是PAGE是2011更新的.
    中文版的PAGE是2010更新的  

  • 相关阅读:
    Linux下的”锁“事儿
    拿得起,放得下,想得开
    关于TCP协议握手的那些事儿

    C++中的RTTI机制解析
    C/C++中产生随机数
    数据库-事务和锁
    JS 数组Array常用方法
    C# 压缩 SharpZipLib
    正则表达式学习3-负向零宽断言
  • 原文地址:https://www.cnblogs.com/BjblCracked/p/3269132.html
Copyright © 2020-2023  润新知