之前几篇文章主要介绍和分析了为什么会在DllMain做出一些不当操作导致死锁的原因。本文将总结以前文章的结论,并介绍些DllMain中还有哪些操作会导致死锁等问题。(转载请指明出于breaksoftware的csdn博客)
        DllMain的相关特性

首先列出《DllMain中不当操作导致死锁问题的分析--进程对DllMain函数的调用规律的研究和分析》中论证的11个特性:

  1. Dll的加载不会导致之前创建的线程调用其DllMain函数。
  2. 线程创建后会调用已经加载了的DLL的DllMain,且调用原因是DLL_THREAD_ATTACH。(DisableThreadLibraryCalls会导致该过程不被调用)
  3. TerminateThread方式终止线程是不会让该线程去调用该进程中加载的Dll的DllMain。
  4. 线程正常退出时,会调用进程中还没卸载的DLL的DllMain,且调用原因是DLL_THREAD_DETACH。
  5. 进程正常退出时,会调用(不一定是主线程)该进程中还没卸载的DLL的DllMain,且调用原因是DLL_PROCESS_DETACH。
  6. 加载DLL进入进程空间时(和哪个线程LoadLibrary无关),加载它的线程会调用DllMain,且调用原因是DLL_PROCESS_ATTACH。
  7. DLL从进程空间中卸载出去前,会被卸载其的线程调用其DllMain,且调用原因是DLL_PROCESS_DETACH。
  8. TerminateProcess 将导致线程和进程在退出时不对未卸载的DLL进行DllMain调用。
  9. ExitProcess将导致主线程意外退出,子线程对未卸载的DLL进行了DllMain调用,且调用原因是DLL_PROCESS_DETACH。
  10. ExitThread是最和平的退出方式,它会让线程退出前对未卸载的DLL调用DllMain。
  11. 线程的创建和退出不会对调用了DisableThreadLibraryCalls的DLL调用DllMain。

不要在DllMain中做的事情

  • A 直接或者间接调用LoadLibrary(Ex)

假如我们在A.dll中的DllMain收到DLL_PROCESS_ATTACH时,加载了B.dll;而B.dll中的DllMain在收到DLL_PROCESS_ATTACH时又去加载A.dll。则产生了循环依赖。但是注意不要想当然认为这个过程是A.dll的DllMain调用了B.dll的DllMain,B.dll的DllMain再调用了A.dll的DllMain这样的死循环。即使不出现循环依赖,如果出现《DllMain中不当操作导致死锁问题的分析——线程中调用GetModuleFileName、GetModuleHandle等导致死锁》中第三个例子的情况,也会死锁的。

  • B 使用CoInitializeEx

在CoInitializeEx底层会调用LoadLibraryEx,原因同A。

  • C 使用CreateProcess

CreateProcess在底层执行了加载DLL的操作。我用IDA查看Kernel32中的CreateProcess可以发现其底层调用的CreateProcessInternalW中有

  • D 使用User32或Gdi32中的函数

User32和Gdi32中部分函数在调用的底层会加载其他DLL。

  • E 使用托管代码

运行托管代码需要加载其他DLL。

  • F 与其他线程同步执行

由《DllMain中不当操作导致死锁问题的分析--加载卸载DLL与DllMain死锁的关系》、《DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子》和《DllMain中不当操作导致死锁问题的分析--线程退出时产生了死锁》可知,进程创建和销毁以及DLL的加载都要进入PEB的LoadLock临界区。如果占用了LoaderLock临界区的线程在等待一个需要经过临界区才能结束的线程时,就发生了死锁。以上3篇博文中均有案例。

  • G 同步对象

如果该同步对象的释放需要获得PEB中的LoaderLock,而占用该临界区的线程又要去等待这个同步对象,则会死锁。其实F中的线程也算是个同步对象。案例详见《DllMain中不当操作导致死锁问题的分析——线程中调用GetModuleFileName、GetModuleHandle等导致死锁》中例子。

  • H 使用CreateThread

理由同F。

  • I 使用ExitThread

理由同F。

  • J 寄希望于DisableThreadLibraryCalls解决死锁问题

由《DllMain中不当操作导致死锁问题的分析--DisableThreadLibraryCalls对DllMain中死锁的影响》可知。DisableThreadLibraryCalls的实现逻辑是:找到PEB结构中用于保存加载器信息的结构体对象Ldr。

Ldr对象的InMemoryOrderModuleList用户保存已经加载的DLL的链表。

它遍历这个链表,找到调用DisableThreadLibraryCalls的DLL的信息,将该信息中的Flags字段设置或上0x40000。

而创建线程在底层将调用LdrpInitializeThread(详见《DllMain中不当操作导致死锁问题的分析--DisableThreadLibraryCalls对DllMain中死锁的影响》)。该函数一开始便进入了PEB中LoaderLock临界区,在该临界区中根据PEB中LDR的InMemoryOrderModuleList遍历加载的DLL,然后判断该DLL信息的Flags字段是否或上了0x40000。如果或上了,就不调用DllMain。如果没或上,就调用DllMain。这说明DisableThreadLibraryCalls对创建线程时是否进入临界区无关。

在退出线程时底层将调用LdrShutdownThread(详见《DllMain中不当操作导致死锁问题的分析--线程退出时产生了死锁》)。该函数逻辑和LdrpInitializeThread相似,只是在调用DllMain时传的是DLL_THREAD_DETACH。所以DisableThreadLibraryCalls对LdrShutdownThread是否进入临界区也是没有影响的。

最后附上实验中的例子和《Best Practices for Creating DLLs》

DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结篇)相关推荐

  1. DllMain中不当操作导致死锁问题的分析——线程中调用GetModuleFileName、GetModuleHandle等导致死锁

    之前的几篇文章已经讲解了在DllMain中创建并等待线程导致的死锁的原因.是否还记得,我们分析了半天汇编才知道在线程中的死锁位置.如果对于缺乏调试经验的同学来说,可能发现这个位置有点麻烦.那么本文就介 ...

  2. DllMain中不当操作导致死锁问题的分析--加载卸载DLL与DllMain死锁的关系

    前几篇文章一直没有在源码级证明:DllMain在收到DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH时会进入临界区.这个论证非常重要,因为它是使其他线程不能进入临界区从而导致 ...

  3. DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子2

    本文介绍使用Windbg去验证<DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子>中的结论,调试对象是文中刚开始那个例子.(转载请指明出于breakso ...

  4. DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子

    有了前面两节的基础,我们现在切入正题:研究下DllMain为什么会因为不当操作导致死锁的问题.首先我们看一段比较经典的"DllMain中死锁"代码.(转载请指明出于breaksof ...

  5. DllMain中不当操作导致死锁问题的分析--死锁介绍

    最近在网上看到一些关于在DllMain中不当操作导致死锁的问题,也没找到比较确切的解答,这极大吸引了我研究这个问题的兴趣.我花了一点时间研究了下,正好也趁机研究了下进程对DllMain的调用规律.因为 ...

  6. DllMain中不当操作导致死锁问题的分析--进程对DllMain函数的调用规律的研究和分析

    不知道大家是否思考过一个过程:系统试图运行我们写的程序,它是怎么知道程序起始位置的?很多同学想到,我们在编写程序时有个函数,类似Main这样的名字.是的!这就是系统给我们提供的控制程序最开始的地方(注 ...

  7. MySQL Innodb表导致死锁日志情况分析与归纳

    案例描述 在定时脚本运行过程中,发现当备份表格的sql语句与删除该表部分数据的sql语句同时运行时,mysql会检测出死锁,并打印出日志. 两个sql语句如下: (1)insert into back ...

  8. mysql 表死锁_MySQL Innodb表导致死锁日志情况分析与归纳

    案例描述在定时脚本运行过程中,发现当备份表格的sql语句与删除该表部分数据的sql语句同时运行时,mysql会检测出死锁,并打印出日志. 两个sql语句如下:(1)insert into backup ...

  9. mysql left join 索引失效_MySQL索引列上做操作导致索引失效案例分析

    索引列上做操作导致索引失效 通常我们认为只要建立索引就可以万事大吉,以为只要建立就一定会使用到,可其实在索引列上的计算.函数.类型转换都可能导致索引失效,所以我们不仅要会创建索引,更重要的是如何正确的 ...

最新文章

  1. html中图片只是一个小图标,如何用css显示一个图片中多个小图标?
  2. Mongodb aggregation 基本操作示例
  3. 积木赛尔号机器人_赛尔号11年,圣灵谱尼从章鱼变花臂少年,最终成为了老父亲...
  4. 【VM单机模拟系列】VMware P2V简单实现
  5. 机器学习笔记(七)贝叶斯分类器
  6. python连接mysql_Python连接MySQL
  7. 多个输出用java怎么写_请问用java写程序怎么输出这两个图形
  8. 使用Azure Pipelines从GitHub发布NuGet包
  9. Ajax.BeginForm无法调用 ajaxOptions的js函数
  10. sql 视图嵌套视图_SQL视图
  11. Linux上Libevent的安装
  12. PNChart,简洁高效有动画效果的iOS图表库
  13. 【*项目调研+论文阅读】SVM-BILSTM-CRF模型SVM-BILSTM-CRF模型 | day7
  14. poi导入excel日期处理_poi解析excel读取日期为数字的问题
  15. 在 Linux 命令行中使用和执行 PHP 代码(一)
  16. linux install nginx
  17. 记一次非典型MySQL排错
  18. 阿里巴巴confont项目的使用
  19. 线元法输入曲线要素_Origin入门教程(三):Origin中曲线怎么平移?
  20. indexOf用法小结

热门文章

  1. 力扣(LeetCode)刷题,简单题(第5期)
  2. YOLO-v5训练自己的数据+TensorRT推理部署(1)
  3. 温控自动烘焙系统的研究与实现
  4. 【图像分类案例】(1) ResNeXt 交通标志四分类,附Tensorflow完整代码
  5. 《中国式方案秘籍(上部)》
  6. UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
  7. 使用libevent多线程验证Linux上的服务器惊群现象
  8. 3D广告建模-C4D Octane渲染视频教程
  9. Blender三维插图设计视频教程 3D Characters and Illustrations in Blender 2.9
  10. Rocksdb 与 TitanDb 原理分析 及 性能对比测试