当我将偏移量更改为任何非零值时,在 C 中映射共享内存时出现无效参数错误

Mmapping shared memory in C giving Invalid argument error when I change the offset to anything nonzero

提问人:entonces 提问时间:10/19/2023 更新时间:10/19/2023 访问量:44

问:

我正在尝试打开一个共享内存文件,写入其中,分叉到新进程,然后调用 execl 运行其他组件,然后在这些组件中我想访问在父组件中创建的共享内存。但我不想要整个结构,只想要其中的一部分。因此,我使用 offsetof 来查找偏移量并将其传递给 mmap。问题是,当我将偏移量更改为零以外的任何值时,它会给出无效参数错误。它在零的情况下工作正常。

我做了一个最小的虚拟程序,有同样的错误,而大程序的代码太大了。 `

#include<stdio.h>
#include<unistd.h>
#include<sys/mman.h>
#include<stddef.h>
#include<fcntl.h>

typedef struct test
{
    int moo;
    char hello;
}Lil;


typedef struct bigstruct
{
    int a;
    char cow;
    Lil lil;
}Big;

int main()
{
    int fd = shm_open("/moomor", O_CREAT | O_RDWR, 0666);
    if(fd == -1)
    {
        perror("shmopen");
        return 1;
    }
    ftruncate(fd, sizeof(Big));
    Big * big = (Big *)mmap(NULL, sizeof(Big), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(big == MAP_FAILED)
    {
        perror("mmap");
        return 1;
    }
    big->lil.hello = 'h';
    printf("hello: %c\n", big->lil.hello); //prints correctly
    munmap(big, sizeof(Big)); //tried it with this in and out

    int offset = offsetof(Big, lil); //gives offset of eight
    printf("Offset: %d\n", offset);
    Lil *lily = (Lil *)mmap(NULL, sizeof(Lil), PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
    if(lily == MAP_FAILED)
    {
        perror("mmap"); //this causes an error
        goto cleanup;
    }
    printf("HH: %c\n", lily->hello);
    munmap(lily, sizeof(Lil));

    cleanup:
    shm_unlink("/moomor");
    close(fd);
}
c unix posix mmap 执行

评论


答:

2赞 Andreas Wenzel 10/19/2023 #1

假设您使用的是基于 Linux 的平台,函数 mmap 的手册页声明如下:

offset 必须是 sysconf(_SC_PAGE_SIZE) 返回的页面大小的倍数。

您似乎在发布的代码中违反了此规则。

评论

0赞 entonces 10/19/2023
非常感谢!我同意这似乎是问题所在,为了解决这个问题,我假设我会得到我想要的结构的偏移量。然后找到最近的页面对齐倍数并将余数传递到子进程中,获取指向该特定页面的 void 指针,然后使用偏移量获取特定结构?
0赞 Andreas Wenzel 10/19/2023
@entonces:找到“最近”的页面对齐倍数对我来说似乎是错误的。我宁愿猜测您可能希望找到“下一个较低”的页面对齐倍数,以便映射的内存范围包含您想要的所有数据。此外,数据可能跨越多个页面,因此我认为您不会想要使用“特定页面”。
0赞 entonces 10/19/2023
是的,接下来是我的意思,对不起。如果数据跨越多个页面,那不应该是问题,对吧?我已经实现了它,到目前为止它有效,谢谢。
1赞 Andreas Wenzel 10/19/2023
@entonces:是的,这应该不是问题。我的观点是,使用单个页面可能还不够。例如,如果数据恰好位于页面边界上,则即使数据的大小明显小于页面,它也可能跨越多个页面。