引用计数为零,仍然没有分段错误
Zero reference count and still no segmentation fault
我在 Python/C API 和内存分配方面有开发技能,并且预计以下 Python 嵌入式C++代码会有问题并导致分段错误之类的东西:
#include <Python.h>
#include <iostream>
int main(){
Py_Initialize();
PyObject* pythonList = Py_BuildValue("[i i]",1,2);
Py_DECREF(pythonList); // I checked with Py_REFCNT(pythonList) that reference count is now 0
PyList_Check(pythonList); // hence, I was expecting here something like a segmentation fault, but this does not happen...
std::cout << "Ok, goodbye" << std::endl;
return 0;
}
但是,运行时不会发生任何不良情况(并且显示"好的,再见"(。
尽管访问(
PyList_Check(pythonList);
(已归零的 PyObject ,但这段代码实际上还可以吗?或者,这段代码是错误的,这里没有发生分段错误只是运气问题(为什么?
代码是错误的- 对Py_DECREF()
的调用释放了对象,这意味着pythonList
是一个悬空指针,因此当PyList_Check()
尝试尊重该指针时,将调用未定义的行为。
至于为什么这不会导致分割错误,正式的答案是,不需要未定义的行为来导致任何特定的可观察后果(例如分段错误(。 未定义的行为可能导致程序执行任何操作,程序员有责任避免调用它。
不过,实际上有一个更令人满意的解释:在大多数流行的系统上,当程序尝试访问未映射到任何物理内存年龄的虚拟内存页面或映射到程序不允许访问的物理页面时,会导致分段错误。 因此,如果您将pythonList
设置为指向某个随机/无效的内存位置,然后尝试取消引用它,则可能会遇到分段错误。 但是,pythonList
不是指向随机内存位置,而是指向有效 Python List 对象所在的内存位置(直到片刻前,Py_DECREF()
释放它(。 该内存的"释放"仅意味着进程的堆数据结构现在将这部分内存包含在其"可用内存列表"中,作为内存,下次进程的其他部分想要分配内存时可以重用该内存。 它不涉及告诉 MMU 该内存位置现在无法访问(一般来说,它不能,因为 MMU 检查内存页的有效性,而不是单个字节的有效性,并且包含有效对象和释放内存区域的内存页混合在一起是很常见的(。 因此,MMU/分段错误健全性检查系统不会捕获您对释放内存的读取(valgrind 可能会捕获它,但代价是您的程序运行速度比正常情况慢 10-100 倍(。
- 在某些循环内使用vector.push_back时出现分段错误
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 当我的阵列太大时出现分段错误
- 分段错误当我试图运行程序时出错
- 在c++中初始化矩阵时出现分段错误(核心转储)
- 尝试使用集合函数时出现分段错误
- 我无法缩小此分段错误的原因
- g++的分段错误(在NaN上使用to_string两次时)
- 我是如何在这段代码中出现分段错误的
- 创建结构的数组时遇到分段错误
- 在c++中键入向量中的所有值后,得到分段错误(核心转储)
- 在 c++ 中实现 Trie 时出现分段错误
- 为什么 fstream 在打开带有格式的文件时会导致分段错误?
- 为什么我遇到分段错误?
- 动态类的分段错误(家庭作业问题)
- 分段错误 - 读取初始化指针的数组
- 如何摆脱C ++中的分段错误错误?
- 使用 CTYPE 时出现分段错误
- 为什么代码给出分段错误?