2016-11-09 56 views
3

我想了解为什么调用写入内存保护区域时不会触发sigsegv。请看例子:在受保护的内存区域写入()不会触发sigsegv,但标准访问确实

void *map_addr; 
unsigned long addr; 

map_addr = (void *)mmap(NULL, 0x4000, PROT_READ_WRITE, MAP_PRIVATE, fd, 0); 
mprotect(map_addr, 0x4000, PROT_NONE); 

addr = (unsigned long)map_addr; 

// case 1: 
*(volatile int*)(addr); // sigsegv sent 
// case 2: 
write(STDOUT_FILENO, map_addr, size); // sigsegv NOT sent 

而是发送sigsegv的,在这种情况下写返回-1并设置errno=EFAULT。为什么写有这种行为?我会想象写会尝试从地址读取,这会产生sigsegv故障,但显然不是这种情况。

+0

请提供标准的引用它需要通过访问未定义行为SIGSEGV。你有没有检查机器码?它执行了吗?调试器说什么? – Olaf

+0

@Olaf Case 1按预期执行并输入SIGSEGV的处理程序。如果我运行情况2,我不输入处理程序,并且写入只是返回-1,指定errno中的'EFAULT',所以在情况2下没有崩溃。 至于参考,我只是假设和I/O on保护内存生成sigsegv –

+0

@Olaf什么标准? linux标准? – melpomene

回答

7

write是一个系统调用,所以内存访问发生在内核中,而不是在你的进程中。内核首先检查传递的地址是否对调用进程有效,如果不是,则返回EFAULT

(我不知道为什么它被设计为以这种方式工作,虽然)。

+0

所以在这种情况下,'write'进入内核,它看到调用地址具有'PROT_NONE'并认为它是'EFAULT'? –

+0

我完全同意,如果你使通过地址*范围*。 –

+0

@SyntacticFructose是的,确切地说。 – melpomene

相关问题