如果指针从未被解引用,硬件陷阱如何在三个超出结尾的指针中发生?

7

在他的2005年11月1日 C++专栏中,Herb Sutter写道...

int A[17];
int* endA = A + 17;
for( int* ptr = A; ptr < endA; ptr += 5 )
{
  // ...
}

在一些CPU架构上,包括当前的一些架构,上述代码可能会导致硬件陷阱发生在创建三个末尾指针的位置,无论该指针是否被解引用。

CPU如何在位模式上触发陷阱?还有其他情况吗?

int A[17];

// (i) hardware will trap this ?
int *pUgly = A + 18; 

// (ii) hardware will trap this, too?
int *pEnd = A + 17;
++pEnd;  

// (iii) will this fool it?
int *precious = A + 17;
unsigned long tricksy = reinterpret_cast<unsigned long>(precious) ; 
++tricksy;
int *pHobbits = reinterpret_cast<int *>(tricksy); 

应该理解为“一些当前的CPU架构”仅指已发货的产品,如果虚构作品中描述或暗示了最近出版日期的架构,则也应包括在内。

1
难道它不是四分之一过末尾,就像endA是过末尾一位吗? - Adrian Panasiuk
2个回答

5
指针操作是与实现相关的。
在某些平台上,只有特定的寄存器可以用于存储指针值(只有特定的寄存器可以作为索引寄存器),并且非特权程序代码写入此类寄存器的值时立即检查其是否为有效地址。在这种情况下,如果指针值对应于程序地址空间中不存在的地址,则硬件陷阱肯定会发生。
如果是这种情况,任何未被编译器优化掉的分配新值给指针的代码都可能导致陷阱。

1
有没有这样的平台,还是这就像“如果你位于贝斯平云城,请勿使用这个挖掘机”? - Thomas L Holaday
1
有一些,就像Sutter所说的,“包括当前的一些”。我记不起来具体的名字,但我知道它们存在。虽然它们并不是非常普遍。但是,一些架构已经使用了单独的寄存器来存储指针和数据,这使得检测无效地址变得非常容易。但是,是否存在这样的平台并不重要吧?只要不要这样做就可以了。 ;) - jalf
2
超现实主义作家博尔赫斯写道,动物可以分为三种:可以触摸的动物,只能从远处看到的动物以及只能从他人的故事中了解的动物。我的问题是这些CPU如何进行陷阱操作,因此真正的CPU技术文档将是有指导意义的。 - Thomas L Holaday
你已经得到了答案。如果CPU有特殊的“地址寄存器”,在其中执行指针算术运算,那么它可以在每个指令之间验证该寄存器中存储的值是否实际上是合法地址,并在其不是时生成硬件陷阱。至少,它可以轻松检测到溢出,这可能会发生在超过数组末尾时。 Motorola 68000具有这样的单独地址寄存器,但我不知道它是否会在非法地址上生成陷阱。 - jalf
我无法找到任何证据表明Motorola 68000会在非法地址上陷阱。 - Thomas L Holaday

3

您可能需要搜索“推测性读取”。一旦地址被形成,缓存架构将相应的数据线带入缓存可能是明智的选择。通常情况下,这不会有任何问题,但如果您显著超出界限(例如进入下一页),这种做法可能不再适用。


1
不,那不是问题所在。关于投机读取的重点是它们只是优化,仅此而已。如果它们尝试读取的地址超出限制,它们就不会读取它。 - jalf
@jalf:这不就是说硬件陷阱没有可见的后果吗?MMU仍然会被呈现一个无法解析到物理地址的虚拟地址,并且必须通过某种方式进行通信。 - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接