受此Windows示例的啟發。簡而言之,他們創建一個檔案句柄(使用CreateFileMapping)然后創建兩個指向同一記憶體的不同指標(MapViewOfFileEx或MapViewOfFile3)
所以我嘗試對shm_open,ftruncate和做同樣的事情mmap。我mmap過去曾用過幾次記憶體和檔案,但我從未將它shm_open與shm_open.
我的代碼第二次因段mmap錯誤而失敗。我嘗試直接在兩個 mmap 上進行系統呼叫,但它仍然存在 segfaults :( 我該如何正確地做到這一點?我的想法是我可以做到memcpy(p len-10, src, 20)并且將 src 的前 10 個位元組放在記憶體的末尾,最后 10 個寫入開頭(因此是圓形的)
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
int main()
{
write(2, "Start\n", 6); //prints this
int len = 1024*1024*2;
int fd = shm_open("example", O_RDWR | O_CREAT, 0777);
assert(fd > 0); //ok
int r1 = ftruncate(fd, len);
assert(r1 == 0); //ok
char*p = (char*)mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
assert((long long)p>0); //ok
//Segfaults on next line
char*p2 = (char*)mmap(p len, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0); //segfaults
write(2, "Finish\n", 7); //doesn't print this
return 0;
}
uj5u.com熱心網友回復:
Linux 通常從某個點開始為映射選擇地址空間,并隨著每次保留而降低。因此,您的第二次mmap呼叫替換了以前的檔案映射之一(可能libc.so),這導致SIGSEGVwith SEGV_ACCERR- invalid 訪問權限。您正在用不可執行的資料覆寫libc.so(正在執行的)的可執行部分。
用于strace檢查內部發生的情況:
$ strace ./a.out
...
openat(AT_FDCWD, "/dev/shm/example", O_RDWR|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0777) = 3
ftruncate(3, 2097152) = 0
mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0x7f134c1bf000
mmap(0x7f134c3bf000, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x7f134c3bf000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7f134c4ccc37} ---
killed by SIGSEGV
將您傳遞的地址與/proc/$pid/maps檔案進行比較,您將看到您正在覆寫的內容。
您的錯誤是假設MAP_FIXED可以在不事先保留記憶體的情況下使用。要正確執行此操作,您需要:
- 通過呼叫大小和(不
mmap帶檔案)來保留記憶體len * 2PROT_NONEMAP_ANONYMOUS | MAP_PRIVATE - 使用
mmapwithMAP_FIXED用您需要的內容覆寫該映射的部分
此外,您應該更喜歡在 Linux 上使用memfd_create而不是使用,shm_open以避免共享記憶體檔案留在那里。如果您的程式崩潰,取消它們的鏈接shm_unlink將無濟于事。這也為您提供了一個對您的程式實體私有的檔案。
uj5u.com熱心網友回復:
您無需mmap再次呼叫來生成新指標。(你甚至不能這樣做。)只是增加它。
指標p2不會指向剛剛分配記憶體塊之后的地址。
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
int main()
{
write(2, "Start\n", 6); //prints this
int len = 1024*1024*2;
int fd = shm_open("example", O_RDWR | O_CREAT, 0777);
assert(fd > 0); //ok
int r1 = ftruncate(fd, len);
assert(r1 == 0); //ok
char*p = (char*)mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
assert((long long)p>0); //ok
char*p2 = p len;
write(2, "Finish\n", 7); //doesn't print this
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/447220.html
上一篇:快速位元組復制C 11
下一篇:區分目錄是否存在和權限錯誤
