vc 环境全局变量赋值引发的访问异常和解决过程

昨天写代码时候不注意 在加载时候跳一个如下图的异常:

vc 环境全局变量赋值引发的访问异常和解决过程_第1张图片

 用vc调试运行就出如下错误:

vc 环境全局变量赋值引发的访问异常和解决过程_第2张图片

经过半天的修改测试总算明白我工程中错误了。

为了说明问题和如何解决我在测试工程写了一个代码如:

#include "stdafx.h"
#include 
void initmap();
using namespace std;

class testclass
{
public:
	testclass();
	~testclass();

private:

};

testclass::testclass()
{
	void initmap();
	initmap();
}

testclass::~testclass()
{
}
testclass  g_testobj;
map   g_testmap;
void initmap()
{
	g_testmap[1] = 3;
}
int main()
{
	getchar();
    return 0;
}

初看起来感觉代码没有问题,运行就报如第一个图片上的错误:再看下面一个代码:

#include "stdafx.h"
#include 
void initmap();
using namespace std;

class testclass
{
public:
	testclass();
	~testclass();

private:

};

testclass::testclass()
{
	void initmap();
	initmap();
}

testclass::~testclass()
{
}
map   g_testmap;
testclass  g_testobj;
void initmap()
{
	g_testmap[1] = 3;
}
int main()
{
	getchar();
    return 0;
}

就完全没有问题了。vc范例中很多都是这么干的,直接在全局变量里去初始化而不是在main()函数中实现初始化。变量设置交换一下竟发生错误了。

vc编译好的程序初始化过程会调用__cdecl __scrt_common_main_seh()这个函数

tatic __declspec(noinline) int __cdecl __scrt_common_main_seh() throw()
{
    if (!__scrt_initialize_crt(__scrt_module_type::exe))
        __scrt_fastfail(FAST_FAIL_FATAL_APP_EXIT);

    bool has_cctor = false;
    __try
    {
        bool const is_nested = __scrt_acquire_startup_lock();

        if (__scrt_current_native_startup_state == __scrt_native_startup_state::initializing)
        {
            __scrt_fastfail(FAST_FAIL_FATAL_APP_EXIT);
        }
        else if (__scrt_current_native_startup_state == __scrt_native_startup_state::uninitialized)
        {
            __scrt_current_native_startup_state = __scrt_native_startup_state::initializing;

            if (_initterm_e(__xi_a, __xi_z) != 0)
                return 255;

            _initterm(__xc_a, __xc_z);//关键在这里会调用全局变量相关初始化

            __scrt_current_native_startup_state = __scrt_native_startup_state::initialized;
        }
        else
        {
            has_cctor = true;
        }

        __scrt_release_startup_lock(is_nested);

        // If this module has any dynamically initialized __declspec(thread)
        // variables, then we invoke their initialization for the primary thread
        // used to start the process:
        _tls_callback_type const* const tls_init_callback = __scrt_get_dyn_tls_init_callback();
        if (*tls_init_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_init_callback))
        {
            (*tls_init_callback)(nullptr, DLL_THREAD_ATTACH, nullptr);
        }

        // If this module has any thread-local destructors, register the
        // callback function with the Unified CRT to run on exit.
        _tls_callback_type const * const tls_dtor_callback = __scrt_get_dyn_tls_dtor_callback();
        if (*tls_dtor_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_dtor_callback))
        {
            _register_thread_local_exe_atexit_callback(*tls_dtor_callback);
        }

        //
        // Initialization is complete; invoke main...
        //

        int const main_result = invoke_main();

        //
        // main has returned; exit somehow...
        //

        if (!__scrt_is_managed_app())
            exit(main_result);

        if (!has_cctor)
            _cexit();

        // Finally, we terminate the CRT:
        __scrt_uninitialize_crt(true, false);
        return main_result;
    }
    __except (_seh_filter_exe(GetExceptionCode(), GetExceptionInformation()))
    {
        // Note:  We should never reach this except clause.
        int const main_result = GetExceptionCode();

        if (!__scrt_is_managed_app())
            _exit(main_result);

        if (!has_cctor)
            _c_exit();

        return main_result;
    }
}

函数中通过这个_initterm(__xc_a, __xc_z);//关键在这里会调用全局变量相关初始化

去初始化相关全局变量的如下图下的断点:

vc 环境全局变量赋值引发的访问异常和解决过程_第3张图片

 首先断点停在第一个全局中

看下反汇编里做什么?

vc 环境全局变量赋值引发的访问异常和解决过程_第4张图片

 原来g_testmap初始化都在这里实现了

记录一下两个变量地址吧

 回头看看_initterm函数循环调用有设置的函数数组

extern "C" void __cdecl _initterm(_PVFV* const first, _PVFV* const last)
{
    for (_PVFV* it = first; it != last; ++it)
    {
        if (*it == nullptr)
            continue;

        (**it)();
    }
}

原因在于:windows 程序启动main()之前进行的全局变量初始化这个函数_initterm从头到尾

通过IDA反汇编可以看到看看first和last

vc 环境全局变量赋值引发的访问异常和解决过程_第5张图片

 first的地址

vc 环境全局变量赋值引发的访问异常和解决过程_第6张图片

last的地址

 在first与last代码中间保存着如下图的地址

vc 环境全局变量赋值引发的访问异常和解决过程_第7张图片

 _initterm函数循环后执行自然就先g_testmap的初始化了,而将代码修改后两个全局变量对调位置后可以看到地址相对位置也对调,而在testclass类中我们恰好写了如下代码:

testclass::testclass()
{
    void inidmap();
    inidmap();
}

void inidmap()
{
    g_testmap[1] = 3;
}

g_testmap还没有初始化就使用就会造成我们开头2个图片的错误。至此综于搞清楚问题所在了,全局变量中不要试图使用或初始化别的全局变量,否则会产生不可预测的结果。想要做通过测试可以定义一个指针,自己new一个对象给全局变量再使用也没有问题;

        码字不易,对您有用就随手点个赞!万分感谢!

你可能感兴趣的:(vc,调试逆向,vc++)