调试实战 | 调试另外一个由于全局变量初始化顺序导致的 dll 加载失败问题(上)...

缘起

最近又遇到了一个程序功能不正常的问题,深入调查后发现与全局变量初始化顺序有非常大的关系,只不过这次更加隐蔽。

之前总结了两篇与全局变量初始化顺序有关的文章,感兴趣的小伙伴儿可以参考《调试实战 | dll 加载失败之全局变量初始化篇》 和《调试实战 | 全局变量初始化顺序探究》。

在排查错误之前先简单介绍一下相关代码。

示例程序

示例程序一共包含4 个工程:LoadDlls, dll1, dll2, dll3

  • 主程序LoadDlls.exe 会加载dll1.dll

  • dll1.dll 隐式依赖了dll2.dll,所以dll1.dll 加载的时候会自动加载dll2.dll

  • dll2.dll 中的全局变量s_culprit 的构造函数会加载dll3.dll

  • dll3.dll 加载的时候会自动调用dll2.dll 的导出函数RegisterInitCallback() 和RegisterCallback()

下面是每个工程的关键代码

  • src/common/autorunner.h

    该文件是公共头文件,实现了自动注册逻辑

    // autorunner.h
    
    #pragma once
    
    class AutoRunner
    {
    public:
        AutoRunner(void (*func)())
        {
            func();
        }
    };
    
    #define STR_CAT(s1, s2) s1 ## s2
    #define NAME_WITH_LINE(name, line) STR_CAT(name, line)
    
    #define BEGIN_AUTO_RUN static AutoRunner NAME_WITH_LINE(s_auto_runner_, __LINE__) ([](){
    #define END_AUTO_RUN  });
  • LoadDlls

    该工程只有一个源文件,用来模拟加载各种插件。对应的源码如下:

    // LoadDlls.cpp
    
    #include "windows.h"
    #include <iostream>
    #include <map>
    #include <vector>
    
    typedef void (*PFN_Init)();
    
    std::map<std::string, HMODULE> LoadPlugins(const char* plugins[])
    {
        std::map<std::string, HMODULE> result;
        for (int idx = 0; ; ++idx)
        {
            constchar* plugin = plugins[idx];
            if (plugin == nullptr)
            {
                break;
            }
    
            HMODULE module = LoadLibraryA(plugin);
            if (module == nullptr)
            {
                DWORD lastError = GetLastError();
                std::cout << "[+] load [" << plugin << "] failed with error " << lastError << std::endl;
            }
            else
            {
                result[plugin] = module;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值