Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
IsBadReadPtr的最有效替代品? 我有一些VisualC++代码,它接收一个缓冲区的指针,这些数据需要用我的代码和缓冲区的长度来处理。由于我无法控制的错误,有时此指针未初始化或不适合读取而进入我的代码(即,当我尝试访问缓冲区中的数据时,它会导致崩溃)_C++_Windows_Visual C++_Memory - Fatal编程技术网

IsBadReadPtr的最有效替代品? 我有一些VisualC++代码,它接收一个缓冲区的指针,这些数据需要用我的代码和缓冲区的长度来处理。由于我无法控制的错误,有时此指针未初始化或不适合读取而进入我的代码(即,当我尝试访问缓冲区中的数据时,它会导致崩溃)

IsBadReadPtr的最有效替代品? 我有一些VisualC++代码,它接收一个缓冲区的指针,这些数据需要用我的代码和缓冲区的长度来处理。由于我无法控制的错误,有时此指针未初始化或不适合读取而进入我的代码(即,当我尝试访问缓冲区中的数据时,它会导致崩溃),c++,windows,visual-c++,memory,C++,Windows,Visual C++,Memory,所以,我需要在使用它之前验证这个指针。我不想使用IsBadReadPtr或IsBadWritePtr,因为每个人都认为它们有缺陷。(以谷歌为例)它们也不是线程安全的——在本例中,这可能不是一个问题,尽管线程安全的解决方案会很好 我在网上看到过一些建议,可以通过使用VirtualQuery或在异常处理程序中执行memcpy来实现这一点。但是,需要执行此检查的代码是时间敏感的,因此我需要最有效的检查,也就是100%有效的检查。任何想法都将不胜感激 我只想说清楚:我知道最好的做法是读取坏指针,让它引发

所以,我需要在使用它之前验证这个指针。我不想使用IsBadReadPtr或IsBadWritePtr,因为每个人都认为它们有缺陷。(以谷歌为例)它们也不是线程安全的——在本例中,这可能不是一个问题,尽管线程安全的解决方案会很好

我在网上看到过一些建议,可以通过使用VirtualQuery或在异常处理程序中执行memcpy来实现这一点。但是,需要执行此检查的代码是时间敏感的,因此我需要最有效的检查,也就是100%有效的检查。任何想法都将不胜感激

我只想说清楚:我知道最好的做法是读取坏指针,让它引发异常,然后将其追溯到源代码并修复实际问题。但是,在这种情况下,错误指针来自我无法控制的Microsoft代码,因此我必须验证它们


还要注意的是,我并不关心所指向的数据是否有效。我的代码正在寻找特定的数据模式,如果找不到,就会忽略这些数据。我只是试图防止在这个数据上运行memcpy时发生崩溃,在尝试memcpy时处理异常需要在遗留代码中更改十几个位置(但是如果我调用了类似IsBadReadPtr的东西,我只需要在一个位置更改代码).

恐怕您运气不好-无法可靠地检查指针的有效性。什么Microsoft代码给了你错误的指针

线程安全的解决方案会很好

我猜只有IsBadWritePtr不是线程安全的

只是在异常处理程序中执行memcpy

这就是IsBadReadPtr正在做的事情。。。如果您在代码中这样做,那么您的代码将与IsBadReadPtr实现有相同的bug:

--编辑:-

我读过的关于IsBadReadPtr的唯一问题是,错误的指针可能指向(因此您可能会意外地触摸)堆栈的保护页。也许您可以通过以下方式避免此问题(并因此安全地使用IsBadReadPtr):

  • 了解进程中正在运行的线程
  • 知道线程的堆栈在哪里,以及它们有多大
  • 在开始调用isBadReadPtr之前,遍历每个堆栈,深入地触摸堆栈的每个页面至少一次

此外,与上述URL相关的一些注释也建议使用VirtualQuery。

这些函数不好用的原因是无法可靠地解决问题

如果您正在调用的函数返回一个指向已分配内存的指针,因此它看起来有效,但它指向其他不相关的数据,并且如果您使用它将损坏您的应用程序,该怎么办

最有可能的是,您正在调用的函数实际上运行正常,并且您正在误用它。(不能保证,但通常情况就是这样。)


它是哪个函数?

为什么不能调用api


AfxIsValidAddress((p),sizeof(type),FALSE))

如果您使用的是VC++,那么我建议您使用microsoft特定的关键字\uuuu try\uu
要捕获硬件异常

任何检查内存有效性的实现都要遵守使IsBadReadPtr失败的相同条件。您能否发布一个示例callstack,说明您希望在何处检查从Windows传递给您的指针的内存有效性?这可能会帮助其他人(包括我)首先诊断您为什么需要这样做。

我能想到的最快解决方案是咨询虚拟内存管理器,查看给定地址是否有可读页面,并缓存结果(但是任何缓存都会降低检查的准确性)

bool IsBadReadPtr(void* p)
{
    MEMORY_BASIC_INFORMATION mbi = {0};
    if (::VirtualQuery(p, &mbi, sizeof(mbi)))
    {
        DWORD mask = (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY);
        bool b = !(mbi.Protect & mask);
        // check the page is not a guard page
        if (mbi.Protect & (PAGE_GUARD|PAGE_NOACCESS)) b = true;

        return b;
    }
    return true;
}
示例(不带缓存):


如果变量未初始化,则使用软管。迟早它会成为你不想玩的东西的地址(比如你自己的堆栈)


如果您认为您需要这个,并且(uintpttr_t)var<65536还不够(Windows不允许分配底部64k),那么就没有真正的解决方案。VirtualQuery等看起来“有效”,但迟早会烧死你。

如果你不得不求助于检查数据中的模式,以下是一些提示:

  • 如果您提到使用IsBadReadPtr,您可能是在为Windows x86或x64开发

  • 您可以对指针进行范围检查。指向对象的指针将与单词对齐。在32位窗口中,用户空间指针的范围为0x00401000-0x7FFFFFFF,对于大型地址感知应用程序,则改为0x00401000-0xBFFFFFFF(对于64位窗口上的32位程序,编辑:0x00401000-0xFFFF0000)。上面的2GB/1GB是为内核空间指针保留的

  • 对象本身将位于不可执行的读/写内存中。它可能存在于堆中,也可能是一个全局变量。如果它是一个全局变量,您可以验证它是否位于正确的模块中

  • 如果您的对象有一个VTable,并且您没有使用其他类,请将其VTable指针与已知良好对象的另一个VTable指针进行比较

  • 范围检查变量,看它们是否可能有效。例如,布尔值只能是1或0,因此如果您看到一个值为242,那么这显然是错误的。指针也可以进行范围检查和对齐检查

  • 如果其中包含对象,请检查它们的vTable和数据

  • 如果有指向其他对象的指针,可以检查该对象是否存在于内存中
    BOOL CanRead(LPVOID p)
    {
      MEMORY_BASIC_INFORMATION mbi;
      mbi.Protect = 0;
      ::VirtualQuery(((LPCSTR)p) + len - 1, &mbi, sizeof(mbi));
      return ((mbi.Protect & 0xE6) != 0 && (mbi.Protect & PAGE_GUARD) == 0);
    }
    
    // Check memory address access
    const DWORD dwForbiddenArea = PAGE_GUARD | PAGE_NOACCESS;
    const DWORD dwReadRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
    const DWORD dwWriteRights = PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
    
    template<DWORD dwAccessRights>
    bool CheckAccess(void* pAddress, size_t nSize)
    {
        if (!pAddress || !nSize)
        {
            return false;
        }
    
        MEMORY_BASIC_INFORMATION sMBI;
        bool bRet = false;
    
        UINT_PTR pCurrentAddress = UINT_PTR(pAddress);
        UINT_PTR pEndAdress = pCurrentAddress + (nSize - 1);
    
        do
        {
            ZeroMemory(&sMBI, sizeof(sMBI));
            VirtualQuery(LPCVOID(pCurrentAddress), &sMBI, sizeof(sMBI));
    
            bRet = (sMBI.State & MEM_COMMIT) // memory allocated and
                && !(sMBI.Protect & dwForbiddenArea) // access to page allowed and
                && (sMBI.Protect & dwAccessRights); // the required rights
    
            pCurrentAddress = (UINT_PTR(sMBI.BaseAddress) + sMBI.RegionSize);
        } while (bRet && pCurrentAddress <= pEndAdress);
    
        return bRet;
    }
    
    #define IsBadWritePtr(p,n) (!CheckAccess<dwWriteRights>(p,n))
    #define IsBadReadPtr(p,n) (!CheckAccess<dwReadRights>(p,n))
    #define IsBadStringPtrW(p,n) (!CheckAccess<dwReadRights>(p,n*2))
    
    __try
    {
      memcpy(dest, src, size);
    }__except(1){}