64位程序崩溃-访问越界

事件起因

最近在做一个32位程序编译成64位的工作,遇到一个很奇葩的问题,程序在32位下运行非常正常,可编译64位以后总是莫名崩溃,崩溃的的报错是这样的。

经过分析发现原来是以前的代码用DWORD来存储指针导致的地址越界错误。

现场模拟

先看一段代码

#include <stdio.h>
#include <windows.h>

void func_a(){
    printf("func_a output");
}

typedef void funca();

int main()
{

    DWORD ptr_func_a = (DWORD)&func_a;
    printf("%p\n",&func_a);

    funca* p_func=(funca*)ptr_func_a;
    printf("%p\n", p_func);
    p_func();
    return 0;
}

这段代码在32位下能正常运行,改成64位就会出现越界异常

32位运行截图

原因分析

DWORD不论在32位还是64位下都是4字节32位长,因此在64位下保存函数地址的时候就会发生截断,只保存了前32位,后32地址丢失了,进而访问函数地址的时候就会出现一个不存在的地址。

从打印的地址可以看出函数地址的高位已经丢失了

如何避免这种问题发生

不要用DWORD存储指针,可以改用DWORD_PTR,DWORD_PTR定义的时候针对64位和32位分别做了不同的定义

typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
//...省略一万字

#if defined(_WIN64)
    typedef __int64 INT_PTR, *PINT_PTR;
    typedef unsigned __int64 UINT_PTR, *PUINT_PTR;

    typedef __int64 LONG_PTR, *PLONG_PTR;
    typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;

    #define __int3264   __int64

#else
    typedef _W64 int INT_PTR, *PINT_PTR;
    typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;

    typedef _W64 long LONG_PTR, *PLONG_PTR;
    typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;

    #define __int3264   __int32

#endif

修改后的运行结果

posted @ 2025-04-02 00:49  DarrenHe  阅读(29)  评论(0)    收藏  举报