检查nullptr是否100%保护内存布局不受segfault影响
does checking for nullptr 100% protect from segfault regarding memory layout?
假设我正在迭代一个数组,但超出了这个数组,因为我的循环很愚蠢
如果内存中的对象直接位于与此数组类型相同的此数组之后,
检查array[invalid_index] == nullptr
是否可以保护我?
检查索引(大小未知)是否对C数组有效的正确方法是什么?
不可能通过指向数组第一个元素的指针来确定数组的大小。你需要以某种方式传达尺寸。
常见的策略是将数组保持为数组,并通过类型系统传递大小,将大小作为单独的值提供或使用sentinel值(如c字符串中的null字符)。在c++中,建议使用std::vector
或std::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
如果您不知道数组的大小,则无法检查其有效性。其他典型的错误来源是错误地假设了阵列的大小或寿命。
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C++中带有List类的迭代器Segfault
- 使用Vulkan hpp vk::enumerateInstanceVersion()会导致segfault
- 为什么擦除方法会影响结束方法
- 内联如何影响模块接口中的成员函数
- 为什么返回类型的'const'限定符对标有 __forceinline/内联的函数没有影响?
- 在容量内调整矢量大小时的性能影响
- 重载运算符的范围是什么?它是否会影响作为类成员的集合的插入函数?
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- 未达到的情况会影响开关外壳性能
- std::partition segfault issue
- OpenSSL: EC_POINT_set_compressed_coordinates_GFp segfault
- 循环仅对第一行正常工作.其他行不受 for 的影响
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 模板如何影响C++中隐式声明的规则?
- 命名空间信息会影响C++的可读性
- [[可能]]和[[不太可能]]影响程序汇编的简单示例?
- 如何保护非托管应用程序中的字符串不受进程转储的影响
- 检查nullptr是否100%保护内存布局不受segfault影响
- 为什么 std::set.erase(first, last) 会影响从中获取 (first, last) 的容器?