检查nullptr是否100%保护内存布局不受segfault影响

does checking for nullptr 100% protect from segfault regarding memory layout?

本文关键字:segfault 影响 布局 内存 nullptr 是否 100% 保护 检查      更新时间:2023-10-16

假设我正在迭代一个数组,但超出了这个数组,因为我的循环很愚蠢
如果内存中的对象直接位于与此数组类型相同的此数组之后,
检查array[invalid_index] == nullptr
是否可以保护我?

检查索引(大小未知)是否对C数组有效的正确方法是什么?

不可能通过指向数组第一个元素的指针来确定数组的大小。你需要以某种方式传达尺寸。

常见的策略是将数组保持为数组,并通过类型系统传递大小,将大小作为单独的值提供或使用sentinel值(如c字符串中的null字符)。在c++中,建议使用std::vectorstd::array,它们总是知道自己的大小。

试图取消引用超出数组边界的数组元素是未定义的行为。一旦您尝试读取array[invalid_index],就会出现未定义的行为。因此,不可能将array[invalid_index]用于任何有用的目的,包括边界检查。nullptr在这里没有任何作用。

否,检查nullptr不会保护您。完全0%。

是你创建了有问题的数组。检查索引是否有效的正确方法是知道您创建的数组的大小(请记住:创建数组的是),然后检查索引是否在范围内。更好的是,编写代码,这样索引一开始就不会超出范围,因此,从开始不需要检查

除了数组最后一个元素之后的假设元素外,尝试仅计算(甚至不访问,仅计算)不属于数组的元素的地址会立即调用未定义的行为[expr.add]/4。而且,毫无例外,试图访问一个实际上不是数组元素的元素总是会调用未定义的行为。100%。内置的下标运算符只是计算给定元素的地址并访问该地址[expr.sub]/1处的对象的简写。因此,实际上,在进入未定义行为区域之前,您甚至无法将读取的值与nullptr进行比较…

这种检查不会保护您。

许多C API与使用它的程序员有一种契约,即他们将遵守API指定的约定,而无需对该契约进行任何严格的机械强制执行。例如,基于C的字符串API大多断言字符串总是以null结尾的,并且任何基于C的串API的正确使用都将假设并取决于字符串以null结尾。

当这个合同生效时,通常被认为执行这些类型的检查是安全的,因为传递字符串的人应该保证这个合同,通常是通过在字符串或数据结构中填充一个额外的null值来明确地履行这个合同,比如:

char string[13] = "Hello World!"; //string[12] contains the value 0
/*...*/
char const* str = string;
do {
char curr = *str++;
if(curr == 0) 
break;
/*...*/
} while(true);

在大多数基于C的StringAPI中,该代码在被保证的合同的特定上下文中被认为是"安全的"。

但这取决于程序员自己的行为,这是无法保证的。对于程序员来说,不需要太多时间就可以对他们的代码和类似的东西做出错误的行为:

char string[12] = "Hello World"; 
string[11] = '!';

会立即打破我刚才展示的字符串循环。这就是为什么C++程序员觉得(在我看来,这是理所当然的)这些检查是不安全的:除非你相信你的用户(程序员)遵守你的规则,否则它们根本无法保证正确。

这就是为什么我们更喜欢不能像这样意外中断的API。

std::string string = "Hello World!";
for(char curr : string) { //for-each loop, intrinsically safe unless the iterators are improperly implemented
/*Do whatever with curr*/
}

因此,回到你最初的问题:处理这个问题的安全方法是使用专门为保护我们安全而设计的物品。使用std::array<T, N>而不是T arr[N],这将允许对每个循环使用。如果您需要使用基于索引的迭代,那么在任何性能不高的情况下,都应该选择at(index)而不是[index]。这些做法将使您的代码安全,而不仅仅是相信您的数据配置正确。

检查nullptr是否100%保护不受segfault 影响

否。访问无效内存的方法有很多,空指针只是其中之一。

你必须做的是避免所有未定义的行为。

检查索引(大小未知)是否对C数组有效的正确方法是什么?

检查它的方法是与数组的大小进行比较:

if (index < size)
// valid

如果您不知道数组的大小,则无法检查其有效性。其他典型的错误来源是错误地假设了阵列的大小或寿命。