代码之家  ›  专栏  ›  技术社区  ›  BCS

检查NULL时要忽略多少位?

  •  0
  • BCS  · 技术社区  · 14 年前

    seg-V出现以下崩溃:

    // my code
    int* ipt;
    int bool set = false;
    void Set(int* i) {
      ASSERT(i);
      ipt = i;
      set = true;
    }
    
    int Get() {
      return set ? *ipt : 0;
    }
    
    // code that I don't control.
    struct S { int I, int J; }
    int main() {
      S* ip = NULL;
      // code that, as a bug, forgets to set ip...
      Set(&ip->J);
      // gobs of code
      return Get();
    }
    

    这是因为 i NULL 无效的 指针。

    void Set(int* i) {
      ASSERT((reinterpret_cast<size_t>(i))>>10);
      ipt = i;
      set = true;
    }
    


    FWIW:这是一个半假设的情况。让我想到这一点的bug在我发布之前已经修复,但是我以前遇到过它,并且正在考虑将来如何使用它。

    为了论证而可以假设的事情:

    • 如果Set调用时使用了seg-v,那就是一个bug
    • Set可能被代码调用,这不是我要修复的工作。(例如,我提交了一个bug)
    • Get my的调用方式不能提供有关Set调用位置的信息。(即,允许Get到seg-v不是调试任何东西的有效方法。)
    • 代码不需要是可移植的,也不需要捕获100%的错误指针。它只需要在我当前的系统上经常工作,就可以让我发现哪里出了问题。
    8 回复  |  直到 14 年前
        1
  •  12
  •   Mike Seymour    14 年前

    没有可移植的方法来测试除NULL以外的任何无效指针。评价 &ip[3] 在指针上做任何算术运算。

    static size_t page_size = sysconf(_SC_PAGESIZE);
    assert(reinterpret_cast<intptr_t>(i) >= page_size);
    

    但这并不是一个完整的解决方案。唯一真正的解决方案是首先修复滥用空指针的问题。

        2
  •  2
  •   dmckee --- ex-moderator kitten    14 年前

    您根本不应该对空指针执行指针算术(包括数组索引)。

    0 ,不是 NULL 在c++中。NULL是c的一个特性,在c++中仍然受支持,但不是惯用的。


        3
  •  1
  •   nos    14 年前

    如果可能的话,尝试处理未定义的行为将始终非常依赖于您的平台、编译器、版本等。

    Common*nixes从不精确地映射地址空间的第一页以捕获空指针访问,因此您可以检查指针值是否在0到4096之间(或者系统使用的任何页面大小)。

    但不要这样做,你不能防范一切可能出错的事情,而是要把重点放在正确的代码上。如果有人给你传递了一个无效的指针,那么很可能是指针验证检查无法修复的严重错误。

        4
  •  1
  •   David Thornley    14 年前

    有没有什么办法可以施加一些影响来纠正那些糟糕的代码?这不可能有好结果。从法律上讲,仅仅创建一个无效指针是未定义的行为。

    Set 总是会从 ip ,和 知识产权

    由于使用错误的指针都可能导致程序失败,因此应该考虑当代码触发内存冲突时会发生什么情况。

    另外,我不知道你的 ASSERT 是的,但是 assert

        5
  •  1
  •   tc.    14 年前

    如果你不介意一个非常糟糕的黑客,你可以用 volatile (注。 不稳定的 是邪恶的)。根据GCC文档,volatile访问必须跨序列点排序,因此您可以执行以下操作:

    int test = *(volatile int *)i;
    *(volatile int *)i = test;
    

    我不认为 = 是一个序列点,但是 可以 同时工作:

    *(volatile int *)i = *(volatile int *)i;
    
        6
  •  1
  •   user420442 user420442    14 年前

    我真的不建议尝试解决别人代码中的错误。如果您在开发代码时没有运行通过调试器编写的所有内容,那么再多的检查也无法帮助您捕获所有问题。让他们修改代码。

    通过静态分析工具定期运行代码也有帮助。

    请记住,可能不是某人忘记初始化指针,也可能是其他人从完全不相关的地方通过坏内存写入来覆盖该指针。也有一些工具可以帮助追踪这些东西。

    #define NULL 0 更好的原因有两个:

    3)当C++ 11最终发布 #define NULL nullptr #define nullptr 0 今天我想是这样,但如果您正在开发跨平台代码,将来可能会出现问题。)

    对于记录,C++标准明确声明空指针常量是一个值为0的rValueType类型。所以请不要再胡说空指针不必等于零。

        7
  •  0
  •   A. Levy    14 年前

    其中一个原因是,您不能以可移植的方式执行此操作,因为NULL不能保证为0。只指定空指针的比较值等于0。您可以在代码中编写0(或预处理器宏“NULL”),但编译器知道该0位于指针上下文中,因此它生成适当的代码将其与NULL指针进行比较,而不管NULL指针的实际实现是什么。看到了吗 here here 更多信息。将空指针重新解释为整数类型可能会导致它的值为true而不是false。

        8
  •  0
  •   Dobes Vandermeer Tahbaza    14 年前

    您必须考虑您的特定操作系统和硬件体系结构。如果您只对检测“接近null”的指针感兴趣,那么您可以使用ASSERT(i>pageSize),假设第一页在操作系统中始终是写保护的。

    但是。。。显而易见的问题是:为什么要麻烦?在这种情况下,操作系统会检测到空值,正如你所指出的,SEGV和ASSERT一样好,不是吗?