关于C#:地址空间中未使用的内存是否受保护
Is unused memory in address space protected
进程地址空间中未使用的内存是否仅通过读取权限来保护,例如,写入由未初始化指针指向的位置总是会导致页面错误被操作系统捕获?或者不是这样,除了代码之外的每个内存位置(当然被赋予只读访问权限),都被赋予写访问权限?
我问这个是因为我的朋友向我展示了他的代码,他没有初始化指针并写入指针指向的内存,但他的程序仍然没有与 windows 的 mingw gcc 编译器崩溃,但总是崩溃在 mac 或 linux 中使用 visual c。
我认为操作系统不保护未使用区域的内存并且导致崩溃是因为在 mingw 生成的代码中,随机指针值指向一些使用区域,例如堆栈,堆或代码,而在其他情况下,它指向一些空闲区域。但是如果操作系统真的不保护未使用的区域,那么这些类型的错误,例如未初始化的指针,是不是很难调试?
我想这就是为什么建议在调用 delete 或 free 之后总是将 NULL 分配给指针的原因,这样当用它访问某些东西时,它确实会导致可见的崩溃。
相关讨论
- 是的,未初始化的指针错误很难调试。症状往往非常神秘。如果你发现自己说"代码不可能做到这一点......",怀疑是未初始化的指针。
- 编译器之间观察到的差异可能与未初始化指针的初始化对象有关。从编译器的angular来看,一个"安全"的方法是将所有指针初始化为 NULL——这样,如果你使用它,你将导致一个段错误,而不是指向内存中的一个随机位置......但这是具体实施,并可能解释您观察到的内容。
在典型的当前服务器/桌面操作系统(以及相当多的小型系统,例如手机)中,您拥有虚拟内存。这意味着操作系统会构建一个表,将代码使用的虚拟地址转换为指定要寻址的实际内存的物理地址。这种映射通常在"页面"中完成——例如,一次 4KB 的内存块。
至少在通常情况下,根本不使用的地址空间部分根本不会被映射 - 即,操作系统不会在表中为该部分构建条目地址空间。但是请注意,分配的内存将(必须)四舍五入为页面大小的倍数,因此每个正在使用的内存块通常后面会跟着一些没有真正使用但仍然分配和"可用"。由于保护也(通常)在每页的基础上完成,如果该页面的其余部分(比如说)是只读的,则尾端的其余部分将是相同的。
相关讨论
- 杰瑞,我知道虚拟内存和页面等等,我只是想问一下是否只通过提供读取访问权限来保护空闲区域。
- @MetallicPriest:大多数未使用的页面都设置为没有页面描述符,因此它们不是只读的或其他任何东西。
未初始化的指针不一定指向未使用的地址空间。它们很可能是恰好指向可写内存的值。例如堆栈上的指针恰好是先前执行的函数存储有效地址的位置。
相关讨论
- 我问的是他们指向某个空闲区域的情况。我知道当它指向已使用的区域(例如堆栈或代码内存)时,它肯定会崩溃。
- 如果它指向堆栈,它可能根本不会崩溃,堆栈通常是读/写的。代码段通常是读取/执行的,在某些架构上可能只是执行
- 如果它指向已释放的内存,它也几乎肯定不会(立即)崩溃,因为大多数实现不会取消映射或返回到操作系统释放最多的内存。
- 关键是,如果指针未初始化,它可以指向任何东西——代码、堆栈、释放的内存、代码中其他地方分配的内存、未对齐的内存、NULL、操作系统内存、映射到物理设备的内存硬件(受约束操作系统),无论如何。
c/c 不提供内存保护。您可能会发现指针恰好包含指向有效内存的指针,例如前一个函数在堆栈上有一个 ptr 变量,而稍后调用的另一个函数恰好使用相同的堆栈空间作为指针。
如果使用 gcc 编译和运行以下代码,将打印"Hello":
#include
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
char buffer[10];
void function1(void) { void function2(void) { int main(int argc, char * argv[]) { |
对于调试版本,一些编译器(我知道 Visual Studio 曾经这样做过)会秘密地将所有变量(如 ptr2)初始化为错误值以检测此类错误。
通常使用 C 时,您会发现内存已被操作系统滥用而杀死您的程序。
这取决于操作系统的实现。在某些配置中,例如,ExecShield 将保护大部分超出程序边界的内存,并且通常要保护数据段的前几个字节(使用 NULL 指针表示访问),但也有可能是指针实际上指向程序中一个有效的、任意的内存地址。
简单地说,我假设答案是"不,地址中未使用的内存不受空间保护。" C 语言不够复杂,无法处理此类情况。
相关讨论
- 这与 C 无关,但与进程内存映射保护有关,这取决于操作系统。
- 但是这种保护可以内置到语言中,我假设当他提到"空间保护"时,他是在强调特定语言的属性(无论它是否内置):例外。