简体   繁体   English

关于在C ++中的访问冲突?

[英]In regards to access violation in C++?

I have to examine access violation in C++ in different data structures. 我必须检查C ++中不同数据结构中的访问冲突。 From what I know, it depends on what compiler you are using. 据我所知,这取决于您使用的编译器。

However, I'd like to know why g++ compiler tends to print some meaningless number when access violation occurs? 但是,我想知道为什么当发生访问冲突时,g ++编译器倾向于打印一些无意义的数字? For example, if I have int a[10]; 例如,如果我有int a[10]; and I do cout << a[100] << endl; 并且我做cout << a[100] << endl; , it will print something like 49738290 which doesn't mean anything. ,它将显示类似49738290的内容,但并不代表任何内容。 Shouldn't it be printing something like null or '\\0'? 它不应该打印null或'\\ 0'之类的东西吗? I think the same thing occurs when you use iterators when the iterator goes out of bounds. 我认为,当迭代器超出范围时,使用迭代器也会发生相同的情况。

I think in visual studio, it wouldn't print something like 49738290. It might print null or \\0, sometimes it will make your program crash. 我认为在Visual Studio中,它不会打印类似49738290的内容。它可能会打印null或\\ 0,有时会导致程序崩溃。 What is the reason of all that? 这是什么原因呢?

Any compiler experts? 有编译专家吗?

"Undefined behavior" means that the results are undefined. “不确定行为”表示结果不确定。 Anything can happen. 什么都可能发生。 You can get a 0 back. 您可以获得0。 You can get some positive number back. 您可以得到一些正数。 You can get some negative number back. 您可以得到一些负数。 Or your program can crash. 否则您的程序可能会崩溃。 You can get a different result each time you run the program. 每次运行该程序时,您都会得到不同的结果。

With undefined behavior, you cannot expect any specific result, or action to occur. 对于未定义的行为,您无法期望任何特定的结果或动作会发生。

In C++, at run time the program doesn't know what the length of the array is (in fact it may not know if its an array or a pointer, when passed to a function the two both are just passed as addresses). 在C ++中,程序在运行时不知道数组的长度(实际上,它可能不知道它是数组还是指针,当传递给函数时,两者都只是作为地址传递)。 So it assumes the index is valid, and looks at the 100th element of the array based on the size of the data. 因此,它假定索引是有效的,并根据数据的大小查看数组的第100个元素。 What happens is technically undefined- the operation is illegal so the app can do anything. 从技术上讲,发生的事情是不确定的-该操作是非法的,因此该应用程序可以执行任何操作。

What realistically happens with most compilers/OSes- it will look at the 100th int in the array, based on where the array starts. 大多数编译器/ OS实际发生的情况-它会根据数组的起始位置查看数组中的第100个整数。 Depending on where the array is in memory, that may be an address you can read from or it may not. 根据数组在内存中的位置,它可能是您可以读取的地址,也可能不是。 If it isn't, you crash. 如果不是,则会崩溃。 If it is it will work, and it will read whatever random piece of memory is there. 如果是这样,它将起作用,并且它将读取那里的任何随机内存。 That may be other variables, blank space, code, memory allocated from the OS but as yet unused, or anything else. 可能是其他变量,空格,代码,从OS分配但尚未使用的内存或其他任何东西。 So its a pseudo-random variable (do not use this as a random number, bad things may happen). 因此,它是一个伪随机变量(请勿将其用作随机数,否则可能会发生不好的事情)。

What gets more fun is if you try to write it- in addition to the problems above, you may also overwrite random data- which could be other variables that will get randomly changed, pointers that will now point to other random pieces of memory, code that now does something different, or the stack in which case you could jump to random memory (in fact this is how some hacks work). 更有趣的是,如果您尝试编写它,除了上面的问题之外,您还可能会覆盖随机数据,这可能是其他变量,这些变量将被随机更改,指针现在将指向其他随机存储器,代码现在,它的功能有所不同,或者是堆栈,在这种情况下,您可以跳转到随机内存(实际上,这是某些黑客的工作方式)。

In short, don't read/write past your bounds. 简而言之,不要超出范围。

What is the reason of all that? 这是什么原因呢?

As @Sam says, what you are doing is "undefined behavior". 正如@Sam所说,您正在做的是“未定义的行为”。 That means that anything could happen. 那意味着什么都可能发生。 Anything. 没事

In practice, what will happen is that the program will attempt to dereference a pointer whose value is undefined. 实际上,将发生的情况是程序将尝试取消引用未定义值的指针。 We cannot predict what it will be. 我们无法预测会是什么。 It could depend on what happened before in the execution. 这可能取决于执行之前发生的情况。 Or not. 或不。 The C++ language spec says nothing. C ++语言规范什么也没说。 (This is "undefined behaviour" ... remember.) (这是“未定义的行为” ...记住。)

The pointer will either be a valid address, or an address that does not refer to a valid memory location. 指针将是有效地址,或者是不引用有效存储位置的地址。

  • If the address is valid, then the value in that cell will be fetched. 如果地址有效,则将获取该单元格中的值。 We don't know what it will be, but it is quite likely to be zero ... which you will see as NULL or an '\\000' depending on the context. 我们不知道它将是什么,但是它很可能为零……根据上下文,您将看到它为NULL'\\000' But it could be something else. 但这可能是另外一回事。

  • If the address is not valid, then attempting to access it will give a memory access fault or segmentation violation. 如果地址无效,则尝试访问该地址将产生内存访问错误或分段冲突。 This is detected by the hardware that is (typically) used to implement virtual memory and/or protect the system against one process (application) accessing memory that belongs to the OS or another process. 这是由硬件检测到的,该硬件通常用于实现虚拟内存和/或保护系统免受某个进程(应用程序)访问属于OS或另一进程的内存的影响。

These are the likely behaviors in a typical modern operating system. 这些是典型的现代操作系统中可能发生的行为。 On the other hand, if your code was running on a "bare-metal" system with no memory protection, then it is conceivable that your read of an essentially random address could land on a memory-mapped device register, and trigger the device to do something. 另一方面,如果您的代码在没有内存保护的“裸机”系统上运行,则可以想象,您读取的是一个基本随机的地址可能会落在内存映射的设备寄存器上,并触发设备执行以下操作:做一点事。 Anything is possible. 一切皆有可能。


The lesson is that when you are coding in C and C++, you need to write your code carefully, and avoid doing things that cause "undefined behavior". 这个教训是,当您使用C和C ++进行编码时,需要仔细编写代码,并避免做会导致“未定义行为”的事情。 If that is too hard, then consider using a language where the compiler and runtime stop you getting into trouble like this. 如果这太难了,请考虑使用一种语言,使编译器和运行时避免您遇到这种麻烦。 (But that comes at a cost ... in terms of performance.) (但这是以性能为代价的。)

As Sam Varshavchik has said in his answer, the behaviour is undefined according to the C++ standard. 正如Sam Varshavchik在回答中所说的那样,根据C ++标准,行为是不确定的。

That means the implementation (loosely speaking, combination of compiler, library, and host system) can produce any result it likes. 这意味着实现(松散地说,编译器,库和主机系统的组合)可以产生任何喜欢的结果。 And there is no requirement that code built with two different compilers produce the same result. 并不需要使用两个不同的编译器构建的代码产生相同的结果。 If you limit attention to one compiler, there is no guarantee that the same result will be produced today and next Wednesday. 如果将注意力集中在一个编译器上,则不能保证今天和下周三将产生相同的结果。

In practice, accessing element 100 of a 10 element array typically tries to access what is at the corresponding location in memory. 实际上,访问10元素的数组中的元素100通常会尝试访问内存中相应位置的内容。 In your example,, if an int is 4 bytes, accessing a[100] will attempt to treat the four bytes starting 400 bytes after the start of the array as if it is an int . 在您的示例中,如果int为4字节,则访问a[100]将尝试将数组开始后400字节开始的四个字节视为int

If that memory exists (it might not, because it might be outside memory the operating system has assigned to your program) then the result obtained will be determined by whatever happens to reside in that location in memory. 如果该内存存在(可能不存在,因为它可能在操作系统已分配给您的程序的外部内存中),则所获得的结果将取决于驻留在内存中该位置的任何内容。 That might correspond to other variables in your program - set by other code in your program to be anything it likes. 这可能与程序中的其他变量相对应-由程序中的其他代码将其设置为任意变量。 It might contain a random set of bits corresponding to whatever was stored in that memory after running some other program hosted by your operating system. 在运行由操作系统托管的其他程序之后,它可能包含随机的一组位,这些位对应于该内存中存储的内容。 The operating system might have overwritten the memory with some random set of bits before making it available to your program (yes, some operating systems do this for security reasons). 操作系统可能会使用一些随机位覆盖内存,然后再将其提供给程序使用(是的,出于安全原因,某些操作系统会这样做)。 If the memory location does not actually exist, accessing it might produce some form of access violation. 如果该内存位置实际上不存在,则访问它可能会产生某种形式的访问冲突。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM