2016-11-09 59 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

相關問題