进程的地址空间中未使用的内存是否仅受到读取权限的保护,因此写入单位指针指向的位置总是会导致页面错误被操作系统捕获?或者情况并非如此,除了代码之外的每个内存位置(哪个都是只读访问权限)都有写访问权限?
我问这是因为我的朋友正在向我展示他的代码,他没有初始化指针并在其指向的内存中写入,但仍然他的程序没有崩溃与mingw gcc编译器的Windows但总是崩溃使用visual c ++,在mac或linux中。
我认为操作系统不保护未使用区域的内存并且导致崩溃,因为在mingw生成的代码中,随机指针值指向某些使用区域,如堆栈,堆或代码,而在其他情况下,它指向一些自由区域。但是,如果操作系统真的不能保护未使用的区域,那么这些类型的错误,例如未初始化的指针是否难以调试?
我想这就是为什么建议在调用delete
或free
之后总是为指针指定NULL,这样当用它访问某些内容时,它确实会导致可见的崩溃。
答案 0 :(得分:3)
未初始化的指针不一定指向未使用的地址空间。它们很可能是恰好指向可写内存的值。例如堆栈上的指针恰好是先前执行的函数存储有效地址的地方。
答案 1 :(得分:3)
在典型的当前服务器/桌面操作系统(以及很多小型系统,如手机)中,您拥有虚拟内存。这意味着操作系统会构建一个表,该表从您的代码使用的虚拟地址转换为指定要寻址的实际内存的物理地址。该映射通常在“页面”中完成 - 例如,一次4KB的存储器块。
至少在通常的情况下,完全没有使用的地址空间部分根本就不会被映射 - 也就是说,操作系统不会在表中为那部分构建一个条目地址空间。但是请注意,分配的内存(必要性)将四舍五入为页面大小的倍数,因此正在使用的每个内存块通常会跟随一些实际上没有使用但尚未分配的内存量。 “可用”。由于保护也(通常)在每页的基础上完成,如果该页面的其余部分(例如)是只读的,则尾端的其余部分将是相同的。
答案 2 :(得分:2)
这取决于操作系统的实现。例如,在某些配置中,ExecShield将保护超出程序范围的大部分内存,并且通常要保护数据段的前几个字节(以便用信号通知访问) NULL指针),但可能是指针实际指向程序中有效的任意内存地址。
答案 3 :(得分:2)
c / c ++不提供内存保护。您可能会发现指针恰好包含指向有效内存的指针,例如上一个函数在堆栈上有一个ptr变量,另一个稍后调用的函数碰巧使用相同的堆栈空间作为指针。
如果编译并使用gcc运行,以下代码将打印“Hello”: #include
char buffer[10];
void function1(void) {
char * ptr = buffer;
sprintf(buffer, "Hello");
return;
}
void function2(void) {
char * ptr2;
printf("%s\n", ptr2);
}
int main(int argc, char * argv[]) {
function1();
function2();
}
对于调试构建一些编译器(我知道Visual Studio曾经这样做)将秘密地将所有变量(如ptr2)初始化为错误值以检测这些类型的错误。
通常使用C,你会发现操作系统滥用内存已被滥用程序。
答案 4 :(得分:1)
简单地说,我假设答案是“不,地址中未使用的内存不受空间保护。” C不够复杂,无法处理这种情况。