我可以在 Linux 上创建循环缓冲区吗? (当前代码段错误)
受到 Windows 版此示例的启发。简而言之,他们创建一个文件句柄(使用CreateFileMapping
),然后创建两个指向同一内存的不同指针(MapViewOfFileEx
或MapViewOfFile3
)
所以我尝试了使用 shm_open
、ftruncate
和 mmap
执行相同的操作。我过去曾多次使用 mmap
来处理内存和文件,但我从未将其与 shm_open
混合使用或使用 shm_open
。
我的代码在第二个 mmap
上失败,并出现段错误。我尝试直接在两个 mmap 上执行系统调用,但仍然出现段错误:( 我该如何正确执行此操作?我的想法是我可以执行 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;
}
Inspired by this example for Windows. In short, they create a file handle (with CreateFileMapping
) then create 2 different pointers to the same memory (MapViewOfFileEx
or MapViewOfFile3
)
So I tried to do the same thing with shm_open
, ftruncate
and mmap
. I used mmap
a few times in the past for memory and files but I never mixed it with shm_open
or used shm_open
.
My code fails on the second mmap
with a segfault. I tried doing a syscall directly on both mmaps and it still segfaults :( How do I do this properly? The idea is I can do memcpy(p+len-10, src, 20)
and have the first 10bytes of src be at the end of the memory and last 10 written to the start (hence circular)
#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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Linux 通常从某个点开始选择地址空间进行映射,并随着每次保留而降低。因此,您的第二个
mmap
调用替换了以前的文件映射之一(可能是libc.so
),这导致SIGSEGV
为SEGV_ACCERR
代码> - 无效的访问权限。您正在使用不可执行的数据覆盖libc.so
的可执行部分(正在执行)。使用
strace
检查内部发生的情况:将您传递的地址与
/proc/$pid/maps
文件进行比较,您将看到您正在覆盖的内容。您的错误是假设可以在不事先保留内存的情况下使用
MAP_FIXED
。要正确执行此操作,您需要:len * 2
大小、PROT_NONE
和MAP_ANONYMOUS | 调用
(并且没有文件)mmap
来保留内存MAP_PRIVATEmmap
与MAP_FIXED
一起使用,用您需要的内容覆盖该映射的部分此外,您应该更喜欢使用
memfd_create<在 Linux 上 /code> 而不是
shm_open
以避免共享内存文件保留。如果您的程序崩溃,使用shm_unlink
取消它们的链接并没有帮助。这还为您提供了一个程序实例私有的文件。Linux usually selects address space for mappings starting from a certain point and goes lower with each reservation. So your 2nd
mmap
call replaces one of previous file mappings (likelylibc.so
), which leads toSIGSEGV
withSEGV_ACCERR
- invalid access permissions. You are overwriting executable section oflibc.so
(that is being executed right now) with non-executable data.Use
strace
to check what is going on inside:Compare addresses you are passing around with
/proc/$pid/maps
file and you will see what you are overwriting.Your mistake was to assume
MAP_FIXED
can be used without reserving memory beforehand. To do this properly you need to:mmap
withlen * 2
size,PROT_NONE
andMAP_ANONYMOUS | MAP_PRIVATE
(and without file)mmap
withMAP_FIXED
to overwrite portions of that mapping with the content you needAdditionally, you should prefer using
memfd_create
instead ofshm_open
on Linux to avoid shared memory files from staying around. Unlinking them withshm_unlink
doesn't help if your program crashes. This also gives you a file that is private to your program instance.您不需要再次调用
mmap
来生成新指针。 (你甚至不能这样做。)只需增加它即可。指针
p2
不会指向分配的内存块之后的地址。You do not need to call
mmap
again to gen new pointer. (You even must not to do it.) Just increment it.The pointer
p2
will not point to the address just after the memory block allocated.