windows 访问冲突异常究竟是如何触发的

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4842213/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 16:05:55  来源:igfitidea点击:

How exactly an access violation exception is triggered

c++windowsvisual-c++compiler-constructioncpu

提问by Lior Kogan

Sometimes bugs can cause memory access violation exception.

有时错误会导致内存访问冲突异常。

How exactly this exception is triggered? What mechanism works behind the scenes?

这个异常究竟是如何触发的?什么机制在幕后运作?

Does it need support from the CPU (starting at what CPU?) / from the OS (starting at what version?) / from the compiler (starting at what version?)

它是否需要来自 CPU(从什么 CPU 开始?)/来自操作系统(从什么版本开始?)/来自编译器(从什么版本开始?)的支持

Edit:

编辑:

One specific scenario I want to understand better:

我想更好地理解的一个特定场景:

The following code may cause an access violation exception.

下面的代码可能会导致访问冲突异常。

TCHAR* czXXX= _T("ABCDEFG");
czXXX[0]= 'A';

I guess czXXX points to a read-only memory block, but what exactly happens?

我猜 czXXX 指向一个只读内存块,但究竟发生了什么?

回答by sarnold

Memory access violations are a large topic :)

内存访问违规是一个很大的话题:)

The Protection of Information in Computer Systems(from 1973 :) lays out of a mechanism of segments, where processes are allocated a baseand a bound; any attempt to access memory outside the range base:base+boundmeant the program had done something silly and should be killed.

计算机系统中的信息保护(从 1973 年开始:)提出了一种机制,其中为进程分配了基数界限;任何试图访问范围之外的内存都base:base+bound意味着该程序做了一些愚蠢的事情,应该被杀死。

The 80x86 line of processors implement basic segment support, and the GEMSOSsecurity kernel is an A1-certified operating system kernel based on this mechanism.

80x86 系列处理器实现了基本段支持,GEMSOS安全内核是基于此机制的 A1 认证操作系统内核。

But segments aren't very dynamic, and almost all modern operating systems are pagingsystems, that page inmemory when it isn't available. This relies on the CPU having an MMU, memory management unit, that checks all memory accesses for correct privileges and presence/absence of the correct memory mapping. When a process tries to access memory that isn't currently mapped into RAM, the MMU signals the CPU that a fault has occurred, and the CPU suspends the process to load the requested memory page from disk. (Or, if the memory should not be mapped for the process, say it tries to access 0x0or some random memory location that hasn't been mapped with mmapor similar memory allocating primitives, it kills the process.)

但是段不是很动态,几乎所有现代操作系统都是分页系统,当内存中的页面不可用时。这依赖于具有MMU内存管理单元的 CPU ,它检查所有内存访问的正确权限和正确内存映射的存在/不存在。当进程尝试访问当前未映射到 RAM 的内存时,MMU 会向 CPU 发出故障发生的信号,并且 CPU 会挂起进程以从磁盘加载请求的内存页面。(或者,如果不应该为进程映射内存,比如它试图访问0x0或一些尚未映射的随机内存位置mmap或类似的内存分配原语,它会终止进程。)

Intel's 80386 was the first Intel chip to support paging, which is why Windows 3.1's "386 Enchanced Mode" was somuch better than the 286 mode.

英特尔的80386是第一个英特尔芯片,支持分页,这就是为什么Windows 3.1中的“386 Enchanced模式”是这样比286模式好得多。

Compilers aren't really involved, but the CPU, MMU, and operating system kernel mustall work together.

编译器并没有真正涉及,但 CPU、MMU 和操作系统内核必须一起工作。

回答by Eli Iser

In x86 architecture (and most others as well), this is started from the MMU - the Memory Management Unit. The MMU is used to translate virtual memory addresses to physical memory addresses. If a request is made to access an invalid address (0x00000000 or something too high) the MMU will trap (interrupt) to the OS (this is in fact done for every access not in the TLB (Translate Lookaside Buffer - the MMU translation "cache")). Here the OS will be able to tell that this is an illegal memory access, and propagate to the user application via the OS-dependent mechanism (signals in Linux (SIGSEGV), I'm not familiar with Windows enough to say how it is done in it).

在 x86 架构(以及大多数其他架构)中,这是从 MMU(内存管理单元)开始的。MMU 用于将虚拟内存地址转换为物理内存地址。如果请求访问无效地址(0x00000000 或某些太高的地址),MMU 将捕获(中断)到操作系统(这实际上是针对不在 TLB 中的每次访问完成的(翻译后备缓冲区 - MMU 翻译“缓存”) "))。在这里,操作系统将能够判断这是非法内存访问,并通过依赖于操作系统的机制(Linux 中的信号(SIGSEGV),我对 Windows 不够熟悉,无法说明它是如何完成的)传播到用户应用程序在里面)。

This feature is available for any modern CPU, OS and compiler. The most basic requirement is an MMU, which is present in all but the most basic embedded CPUs. I doubt there is any PC currently operating that doesn't support this.

此功能适用于任何现代 CPU、操作系统和编译器。最基本的要求是 MMU,它存在于除最基本的嵌入式 CPU 之外的所有处理器中。我怀疑当前是否有任何 PC 不支持此功能。

Edit:

编辑:

Following the OP edit, when a literal string is used, the memory is placed in the .text segment of the executable. This is where the binary code and constant values sit. Naturally, in most OSs this is read-only (especially under Linux with various security enhancements). When you try to change a value of a literal string you are basically trying to write to a read-only memory, causing an access violation. Again, this is caught by the MMU that sees a write command to a read-only memory address.

在 OP 编辑​​之后,当使用文字字符串时,内存被放置在可执行文件的 .text 段中。这是二进制代码和常量值所在的位置。自然,在大多数操作系统中,这是只读的(尤其是在具有各种安全增强功能的 Linux 下)。当您尝试更改文字字符串的值时,您基本上是在尝试写入只读存储器,从而导致访问冲突。同样,这被 MMU 捕获,该 MMU 看到了对只读存储器地址的写命令。

回答by Kevin Lacquement

When you try to access a memory address, the computer goes through several steps:

当您尝试访问内存地址时,计算机会经历以下几个步骤:

  • If the address is part of the current memory segment, access is granted.
  • Otherwise, if the address's segment is in memory with appropriate access permission, access is granted.
  • 如果地址是当前内存段的一部分,则允许访问。
  • 否则,如果地址段在具有适当访问权限的内存中,则授予访问权限

If the address is not in memory, the CPU will generate a memory check exception. At this point, the operating system takes over.

如果地址不在内存中,CPU 会产生内存检查异常。此时,操作系统接管。

  • If the segment is available in virtual memory with appropriate access permission, it is loaded into memory and assigned to the virtual memory manager; access is then granted.
  • 如果该段在具有适当访问权限的虚拟内存中可用,则将其加载到内存中并分配给虚拟内存管理器;然后授予访问权限。

If, at this point, the memory is not available, there is one of two possibilities. Either the address is not available, or you do not have the permissions you need (eg, trying to write into read-only memory). In this case, the operating system will pass the access violation to the process.

如果此时内存不可用,则有两种可能性之一。地址不可用,或者您没有所需的权限(例如,尝试写入只读存储器)。在这种情况下,操作系统会将访问冲突传递给进程。

As to CPU and OS versions, this is any system that allows virtual memory. I don't know the details of this.

至于 CPU 和操作系统版本,这是任何允许虚拟内存的系统。我不知道这件事的细节。

回答by Ramon Zarazua B.

All of these answers explain what happens at a processor level very well. As mentioned, once the processor raises an interrupt to the os, then things change with different operating systems.

所有这些答案都很好地解释了处理器级别发生的情况。如前所述,一旦处理器向操作系统发出中断,那么不同的操作系统就会发生变化。

Windows uses a mechanism known as "Structured exceptions". Very important not to confuse this with C++ exceptions, they are different. Structured exceptions conceptuallywork in the same way as C++ exceptions, in that they unwind the stack looking for a handler. Since Structured Exceptions are language agnostic, they do notcall destructors or do any cleanup.

Windows 使用一种称为“结构化异常”的机制。不要将此与 C++ 异常混淆,这一点非常重要,它们是不同的。结构化异常在概念上与 C++ 异常的工作方式相同,因为它们展开堆栈以寻找处理程序。由于结构化异常与语言无关,因此它们不会调用析构函数或进行任何清理。

Structured Exceptions can be caught with

可以捕获结构化异常

__try
{
  //Usual code
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
  //Handling code
}
__finally
{
  //Cleanup
}

Be warned however, that once you get a Structured Exception, your program has already crashed,so there is no sane way to 'recover'.

但是请注意,一旦您遇到结构化异常,您的程序就已经崩溃,因此没有理智的方法来“恢复”。

More information on SEH.

有关SEH 的更多信息。

回答by Nawaz

Memory access violation may occur here also:

内存访问冲突也可能发生在这里:

delete pSample;

//again deleting the same memory!
delete pSample;

For such cases, exception is raised from the memory model of the OS. Mostly it's the OS whose job is to validate the memory access from any process!

对于这种情况,会从操作系统的内存模型中引发异常。大多数情况下,操作系统的工作是验证来自任何进程的内存访问!

回答by Marlon

void Kaboom()
{
    int* certain_death = NULL;
    *certain_death = 0;
}