检查NULL时要忽略多少位?

BCS*_*BCS 0 c++ low-level segmentation-fault

以下使用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();
}
Run Code Online (Sandbox Code Playgroud)

这是因为虽然i它不是NULL仍然无效.如果调用代码从NULL指针获取数组索引操作的地址,则会发生同样的问题.

对此的一个解决方案是修剪低阶位:

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

但是我应该/可以摆脱多少位?


编辑,我并不担心未定义的行为,因为无论如何我都会中止(但比seg-v更干净).

FWIW:这是一个半假设的情况.在我发布之前,导致我想到这个问题的错误已得到解决,但我之前遇到过它并且正在考虑将来如何使用它.

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

  • 如果使用seg-v的东西调用Set,那就是一个bug
  • 可以通过不是我要修复的工作的代码来调用Set.(例如我提交了一个错误)
  • 可以通过我试图解决的代码调用Set.(例如,我正在添加健全性检查作为我的调试工作的一部分.)
  • 以一种不提供有关Set的调用位置信息的方式调用我.(即允许Get to seg-v不是调试任何东西的有效方法.)
  • 代码不需要是可移植的,也不能捕获100%的坏指针.它只需要经常在我当前的系统上工作,让我找到出错的地方.

Mik*_*our 12

除了NULL之外,没有可移植的方法来测试任何无效指针.&ip[3]在对它做任何事情之前,评估会给出未定义的行为; 唯一的解决方案是在对指针进行任何算术之前测试NULL .

如果您不需要可移植性,并且不需要保证捕获所有错误,那么在大多数主流平台上,您可以检查地址是否在内存的第一页内; 通常将NULL定义为地址零,并保留第一页以捕获大多数空指针解引用.在POSIX平台上,这看起来像

static size_t page_size = sysconf(_SC_PAGESIZE);
assert(reinterpret_cast<intptr_t>(i) >= page_size);
Run Code Online (Sandbox Code Playgroud)

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