访问冲突exception如何触发

有时候,错误会导致内存访问冲突exception。

这个exception如何被触发? 什么机制在幕后工作?

是否需要从CPU(从哪个CPU?)/从OS(从哪个版本?开始)/从编译器(从哪个版本开始)支持CPU?

编辑:

我想更好地理解一个具体情况:

以下代码可能会导致访问冲突exception。

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

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

内存访问冲突是一个很大的话题:)

计算机系统中的信息保护 (从1973年开始):列出了一个细分机制,在这个机制中,进程被分配了一个基础和一个界限 ; 任何尝试访问超出范围base:base+bound内存意味着该程序做了一些愚蠢的事情,应该被杀死。

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

但是段不是很有活力,几乎所有的现代操作系统都是分页系统,当页面不可用的时候, 页面在内存中。 这依赖于具有MMU (内存管理单元)的CPU,其检查所有存储器访问是否具有正确的权限以及是否存在正确的存储器映射。 当进程尝试访问当前未映射到RAM中的内存时,MMU会通知CPU发生了故障,并且CPU暂停进程以从磁盘加载所请求的内存页面。 (或者,如果内存不应该被映射到进程,比如说它试图访问0x0或者一些没有被映射到mmap或者类似的内存分配原语的随机内存位置,那么将会终止进程。)

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

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

在x86架构(以及其他大多数架构)中,这是从MMU(内存管理单元)开始的。 MMU用于将虚拟内存地址转换为物理内存地址。 如果请求访问一个无效的地址(0x00000000或太高),MMU将陷阱(中断)到操作系统(事实上这是为每个访问不是在TLB(翻译后备缓冲区 – MMU翻译“缓存“))。 在这里操作系统将能够告诉这是一个非法的内存访问,并通过操作系统相关的机制传播给用户应用程序(Linux中的信号(SIGSEGV),我不熟悉Windows足以说明它是如何完成的在里面)。

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

编辑:

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

当您尝试访问内存地址时,计算机将执行以下几个步骤:

  • 如果地址是当前内存段的一部分,则授予访问权限。
  • 否则,如果地址段在内存中具有适当的访问权限 ,则授予访问权限

如果地址不在内存中,CPU将产生内存检查异常。 在这一点上,操作系统接管。

  • 如果该段在具有适当访问权限的虚拟内存中可用,则将其加载到内存中并分配给虚拟内存管理器; 访问被授予。

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

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

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

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

结构化的例外可以被捕获

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

不过要注意的是,一旦你得到了一个结构化异常,你的程序已经崩溃了,所以没有“恢复”的理智方法。

有关SEH的更多信息。

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

 delete pSample; //again deleting the same memory! delete pSample; 

对于这种情况,OS的内存模型会引发异常。 主要是操作系统,其工作是验证任何进程的内存访问!

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