2

简介:我试图快速修复旧代码并使用 __try MSVC 扩展来检查某些 ptr 是否指向某些合法内存或 *ptr 是否会导致内存冲突(如果是这样,我会放弃对该 ptr 的处理)。所以我写了类似的东西:

bool checkIsPtrPointingToValidAddress(const void *ptr)
{
    __try
    {
        auto cpy = *((int*)ptr); // force mem access...
        if ( (cpy ==42) && ((rand()+rand()+rand()+rand()+ rand()) == 1))
        {
            FILE* pFile = fopen ("tempdata.dat","w"); //... by unlikely but possible action
             fputs (" ",pFile);
             fclose (pFile);
        }
        return true;
    }
    __except(1)
    {
        return false;
    }

}

问题是我强制访问内存的解决方案看起来很奇怪,很难看,而且我不确定它是否正确。另外请不要我不能禁用整个项目的优化,所以这不是一个选项。MSDN 上的编译指示优化文档很糟糕,也就是说,不清楚“”是否禁用了该函数的所有优化。

4

3 回答 3

10

首先,这是一个非常糟糕的主意,因此您可能需要重新考虑整个设计。但是,如果您被迫坚持使用它,那么类似:

volatile auto copy1 = *((char*)ptr);  // using int* here could lead to aliasing violations, so better char in the general case..
volatile auto copy1 = *((char*)ptr);
if (copy1 != copy2) 
   throw std::exception("Cannot happen, but compiler cannot know this");

当然应该做的伎俩。编译器无法消除读取或假设它们是相同的,因此必须执行代码。另一方面,假设没有线程问题或其他有趣的场景,我们知道这两个读取将是相同的,因此不会导致抛出异常。

添加

根据标准的规则,对 volatile 对象的任何读取或写入都构成可观察的行为(也称为副作用),因此即使以下内容也应该足够了:

volatile auto copy = *((char*)ptr);

这包括写入 volatile object copy,因此无法对其进行优化。

于 2013-09-06T11:13:05.137 回答
4

Windows API 有

BOOL WINAPI IsBadReadPtr(_In_ const VOID *lp,_In_ UINT_PTR ucb);
BOOL WINAPI IsBadWritePtr(_In_ LPVOID lp, _In_ UINT_PTR ucb);

您需要阅读备注部分,但您的案例可能足够简单,这些功能可能就足够了。无论注释部分在尝试自己处理不安全指针时都会提供一些有用的建议。

于 2013-09-16T10:25:36.180 回答
0

从这里对类似问题的回答来看,似乎是:

  • 编译器依赖
  • 不平凡

我发现的最佳信息来源是这里的问题/答案:

检查指针是否指向堆上分配的内存

对我来说最合理的似乎是:

  1. 静态分析(valgrind)、调试、重构
  2. 为您的编译器使用一些技巧
  3. 检查该答案中宣传的商业解决方案
于 2013-09-15T16:55:45.220 回答