什么会导致 C++ 中的分段错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6923574/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What can cause segmentation faults in C++?
提问by fluffels
I noticed there's not question with a list of common causes of segmentation faults in C++, so I thought I'd add it.
我注意到 C++ 中分段错误的常见原因列表没有问题,所以我想我会添加它。
Naturally it's community Wiki, since there's no onecorrect answer.
自然是社区维基,因为没有一个正确的答案。
I think this might be useful for newer programmers learning C++, feel free to close it if you disagree.
我认为这可能对学习 C++ 的新程序员有用,如果您不同意,请随时关闭它。
采纳答案by Mihai Maruseac
Segmentation fault is caused by bad accesses to memory, only if your OS has a MMU (Memory Management Unit). Otherwise, you won't get it but only strange behavior.
分段错误是由对内存的错误访问引起的,仅当您的操作系统具有 MMU(内存管理单元)时。否则,您将不会得到它,而只会得到奇怪的行为。
The virtual memory (the entire memory accessible to you = 2^(sizeof(pointer_type)*8)
(ie: 2^num_bits_in_pointer_type
)) is mapped to physical memory in units named pages or segments (paging superseded segmentation but they are still used).
虚拟内存(您可以访问的整个内存= 2^(sizeof(pointer_type)*8)
(即:)2^num_bits_in_pointer_type
)以命名页面或段的单位映射到物理内存(分页取代了分段,但它们仍在使用)。
Each page has some protection rights, if you try to read from a page with no-read access you'll get a segfault. If you try to write to a readonly location you'll get a SIGSEGV.
每个页面都有一些保护权限,如果您尝试从具有非读取访问权限的页面中读取,则会出现段错误。如果您尝试写入只读位置,您将获得一个 SIGSEGV。
If you have an unitialized pointer and use it it may happen that it will point to another good location so you'll don't get a segfault. If you have a small array reading after it's bound may corrupt other memory areas if it doesn't get past the page boundary.
如果您有一个未初始化的指针并使用它,它可能会指向另一个好的位置,这样您就不会出现段错误。如果您在绑定后读取一个小数组,如果它没有超过页面边界,则可能会损坏其他内存区域。
Also, since there are many pages, not all of them are really mapped. If you touch a non-mapped page you'll get a segfault. Actually, any access to a non mapped page will have to take into account copy on write, pages on swap, lazy loading, memory mapped files and other things. See this article on page fault handling, especially the second diagram there, posted here below too (but read the article for more explanations)
此外,由于有很多页面,并非所有页面都被真正映射。如果您触摸未映射的页面,则会出现段错误。实际上,对非映射页面的任何访问都必须考虑写入时复制、交换页面、延迟加载、内存映射文件和其他事情。请参阅有关页面错误处理的这篇文章,尤其是那里的第二张图,也贴在下面(但请阅读文章以获得更多解释)
(source: champ at vistech.net)
(来源:vistech.net 的冠军)
You are mainly interested in what happens in user space and all paths leading to SIGSEGV. but kernel space is also interesting.
您主要对用户空间中发生的事情以及通向 SIGSEGV 的所有路径感兴趣。但内核空间也很有趣。
回答by Seb Holzapfel
Many of the ways to 'segfault' C++ aren't necessarily guaranteedto happen, in fact, that is the case with most of the examples posted here. It's merely good luck (or bad luck, depending on how you look at it!) if you can perform these operations without a segfault occuring.
许多方法来“段错误” C ++并不一定保证的情况发生,事实上,与大多数的例子都贴在这里的情况。如果您可以在不发生段错误的情况下执行这些操作,那只是运气好(或运气不好,取决于您如何看待它!)。
That is actually one of the things in C++ that separates it from other languages; undefined behaviour. Whereas in Java or C# you might get an 'InvalidOperationException' or similar, which is guaranteed to happen when these operations are performed; in C++, the standard just says 'undefined behaviour', which is basically luck of the draw, and you never want that to happen.
这实际上是 C++ 中将它与其他语言区分开来的东西之一;未定义的行为。而在 Java 或 C# 中,您可能会收到“InvalidOperationException”或类似的信息,这在执行这些操作时肯定会发生;在 C++ 中,标准只是说“未定义的行为”,这基本上是幸运的,你永远不希望这种情况发生。
回答by fluffels
Dereferencing NULL pointers.
取消引用 NULL 指针。
#include <cstddef> //For NULL.
int* p1 = NULL; //p1 points to no memory address
*p1 = 3; //Segfault.
回答by Seb Holzapfel
Accessing an array out of bounds (Possible):
访问数组越界(可能):
int ia[10];
ia[10] = 4; // Someone forgot that arrays are 0-indexed! Possible Segfault.
回答by Anton Golov
A favourite of mine:
我的最爱:
#include <iostream>
struct A {
virtual void f() {
std::cout << "A::f();\n";
}
int i;
};
struct B : A {
virtual void f() {
std::cout << "B::f();\n";
}
int j;
};
void seti(A* arr, size_t size) {
for (size_t i = 0; i < size; ++i)
arr[i].i = 0;
}
int main() {
B b[10];
seti(b, 10);
b[3].f();
}
As with most things that can cause a segfault, this can also fail to fail. On ideone, for example, b[3].f()
fails, but b[2].f()
works.
与大多数可能导致段错误的事情一样,这也可能失败。例如,在 ideone 上,b[3].f()
失败,但b[2].f()
有效。
回答by James Kanze
The obvious answer is “undefined behavior”, but this begs
the question for an unexperienced programmer, and some types of
undefined behavior are much less likely to cause a segmentation fault
(or another type of crash) than others. The most frequent causes of
segmentation faults are generally pointer related: dereferencing an
uninitialized pointer, a null pointer, or a previously freed pointer;
accessing beyond the end (or in front of the beginning, but that's less
frequent) of an object (array or other); using the results of an illegal
pointer cast (static_cast
to a derived type, when the object doesn't
actually have that type, or most reinterpret_cast
); etc.
显而易见的答案是“未定义行为”,但这对没有经验的程序员来说是个问题,并且某些类型的未定义行为比其他类型更不可能导致分段错误(或其他类型的崩溃)。段错误的最常见原因通常与指针有关:取消引用未初始化的指针、空指针或先前释放的指针;访问对象(数组或其他)的末尾(或开头,但频率较低);使用非法指针转换的结果(static_cast
到派生类型,当对象实际上不具有该类型时,或大多数reinterpret_cast
);等等。
Perhaps the most important point to keep in mind here, however, is that
in general, these are not guaranteed to cause a segmentation fault, and
that often, the segmentation fault that they cause will only occur
sometime later, in a completely unrelated operation. Thus, writing
beyond the end of a local array will usually “work”,
but will modify whatever happens to follow the array on the stack: some
other local variable (modifying the vptr
of an object on the stack
may lead to a segmentation fault when you attempt to call a virtual
function on the object), the frame pointer of the calling function
(which will probably cause a segmentation fault in that function, after
you've returned), or the return address (which may cause all sorts of
strange behavior—a segmentation fault or an illegal instruction
trap are probably the best that can occur). Writing beyond the end of
freed memory, or through an already freed pointer, can corrupt the free
space arena, causing a segmentation fault in a much (sometime much,
much) later allocation or free; it can also modify some other, totally
unrelated object, corrupting its vptr
or some other pointer in the
object, or just some random data—again, a segmentation fault is
probably the best possible result (far preferrable to continuing with
corrupted data).
然而,这里要记住的最重要的一点是,一般来说,这些并不能保证会导致分段错误,而且通常,它们导致的分段错误只会在稍后的某个时间发生,在完全不相关的操作中。因此,写入超出本地数组的末尾通常会“工作”,但会修改堆栈中数组后面发生的任何事情:一些其他局部变量(修改vptr
当您尝试在对象上调用虚拟函数时,堆栈上的对象可能会导致分段错误),调用函数的帧指针(在您返回后,这可能会导致该函数中的分段错误) ,或返回地址(这可能会导致各种奇怪的行为——分段错误或非法指令陷阱可能是最好的情况)。超出已释放内存的末尾或通过已释放的指针进行写入可能会破坏可用空间区域,从而在很多(有时很多很多)以后的分配或释放中导致分段错误;它还可以修改其他一些完全不相关的对象,破坏它的vptr
或者对象中的一些其他指针,或者只是一些随机数据——同样,分段错误可能是最好的结果(比继续使用损坏的数据更可取)。
回答by Aamir
Trying to modify string literals:
尝试修改字符串文字:
char* mystr = "test";
mystr[2] = 'w';
This CANcause segmentation fault.
这CAN导致段故障。
回答by fluffels
Dereferencing freed memory could potentially cause a segfault.
取消引用已释放的内存可能会导致段错误。
SomeClass* someObject = new SomeClass();
delete someObject;
someObject->someMethod(); //Could cause a segfault.
回答by fluffels
Forgetting to initialize pointers, leaving them with random memory addresses. Note: this may not alwayssegfault, but it could.
忘记初始化指针,给它们留下随机内存地址。注意:这可能并不总是段错误,但它可以。
int* p1; //No initialization.
*p1 = 3; //Possible segfault.