最有效的替代IsBadReadPtr?

我有一些Visual C ++代码接收指向缓冲区的指针,数据需要由我的代码和缓冲区的长度来处理。 由于我的控制之外的错误,有时这个指针进入我的代码未初始化或不适合读取(即,当我尝试访问缓冲区中的数据时,它会导致崩溃)。

所以,我需要validation这个指针之前,我使用它。 我不想使用IsBadReadPtr或IsBadWritePtr,因为每个人都同意他们是越野车。 (谷歌他们的例子。)他们也不是线程安全的 – 这可能不是一个问题在这种情况下,虽然线程安全的解决scheme会很好。

我已经看到了使用VirtualQuery来完成这个任务的build议,或者只是在exception处理程序中做一个memcpy。 然而,这个检查需要做的代码是时间敏感的,所以我需要最有效的检查,也是100%有效的。 任何想法,将不胜感激。

只是要清楚:我知道最好的做法是只读错误指针,让它引发exception,然后追溯到源代码并修复实际问题。 然而,在这种情况下,坏指针来自微软的代码,我没有控制,所以我必须validation它们。

另外请注意,我不关心指出的数据是否有效。 我的代码正在寻找特定的数据模式,并会忽略数据,如果没有find它们。 我只是试图防止在这个数据上运行memcpy时发生的崩溃,并在memcpy点试图处理exception将需要改变我的代码中的十几个地方(但如果我有像IsBadReadPtr调用我只会必须在一个地方更改代码)。

Solutions Collecting From Web of "最有效的替代IsBadReadPtr?"

一个线程安全的解决方案将是很好的

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

只是在异常处理程序中做一个memcpy

这实际上就是IsBadReadPtr正在做的事情……如果你在你的代码中做了这个,那么你的代码就会和IsBadReadPtr实现一样: http : //blogs.msdn.com/oldnewthing/archive/2006/09/ 27 / 773741.aspx

– 编辑: –

我读过的IsBadReadPtr唯一的问题是坏的指针可能指向(所以你可能会不小心碰到)堆栈的守护页。 也许你可以避免这个问题(因此安全地使用IsBadReadPtr):

  • 知道你的过程中正在运行的线程
  • 知道线程栈的位置,以及它们的大小
  • 走下每个堆栈,确保触摸堆栈的每个页面至少一次,然后再开始调用isBadReadPtr

此外,与上面的URL相关的一些评论也建议使用VirtualQuery。

这些功能使用不好的原因是问题不能可靠地解决。

如果你正在调用的函数返回一个指向分配的内存的指针,那么它看起来是有效的,但是它指向其他不相关的数据,并且如果你使用它的话会损坏你的应用程序。

你所调用的函数实际上很可能是正确的,而且你正在滥用它。 (不保证,但往往是这种情况。)

它是哪个功能?

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; } 

你为什么不能叫api?

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

任何检查内存有效性的实现都会受到使IsBadReadPtr失败的相同情况的影响。 你可以发表一个示例调用堆栈的位置来检查从Windows传递给你的指针的内存的有效性吗? 这可能有助于其他人(包括我)诊断为什么你需要这样做,摆在首位。

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

示例(无缓存):

 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); } 

如果这个变量是未初始化的,那么你就被弄糟了。 迟早它会成为你不想玩的东西(就像你自己的堆栈)。

如果你认为你需要这个,并且(uintptr_t)var <65536是不够的(Windows不允许分配底部的64k),那么没有真正的解决方案。 VirtualQuery等似乎“工作”,但迟早会烧你。

恐怕你运气不好 – 没有办法可靠地检查一个指针的有效性。 什么微软的代码给你不好的指针?

如果您使用的是VC ++,那么我建议使用Microsoft特有的关键字__try __except来捕捉硬件异常