访问填充了从管道读取的数据的结构时出现分段错误

Posted

技术标签:

【中文标题】访问填充了从管道读取的数据的结构时出现分段错误【英文标题】:Segmentation fault while accessing struct filled with data read from pipe 【发布时间】:2011-04-19 22:25:08 【问题描述】:

在尝试访问名为 Request 的结构时,我一直遇到分段错误,该结构填充了从管道读取的数据。我的代码有什么问题?错误在这里抛出一个简单的 printf 试图打印名称字段

结构定义:

typedef struct 

    char code;      
    pid_t pid;       
    char *name;      
    char *object;    
    int id;          
    void *buffer;    
    size_t size;     
 Request;

编写者代码:

request.code   = MANADDUSER;   /* macro defining a char */
request.pid    = getpid();
request.name   = argument1;   /* dinamycally allocated string */
request.object = NULL;
request.id     = 0;
request.buffer = NULL;
request.size   = 0;
if((fifoto = open(FIFOTOMMBOXD, O_WRONLY)) == -1)   logMmboxman("error in opening FIFOTO\n", 1); 
else                                                logMmboxman("opened FIFOTO\n", 0);  

if((write(fifoto, &request, sizeof(Request))) != sizeof(Request))   logMmboxman("error in writing FIFOTO\n", 1);
else                                                                logMmboxman("written on FIFOTO\n", 0);
close(fifoto);

阅读器代码:

if((fifoto = open(FIFOTOMMBOXD, O_RDWR)) == -1)   logMmboxd("error in opening FIFOTO\n", 1); 
else                                              logMmboxd("opened FIFOTO\n", 0);  

if((read(fifoto, &request, sizeof(Request))) != sizeof(Request))   logMmboxd("error in reading FIFOTO\n", 1);
else                                                               logMmboxd("read from FIFOTO\n", 0);
close(fifoto);

printf("%s\n", request.name);

【问题讨论】:

请不要在标题中写标签。 你的代码不是测试用例;特别是,它没有显示 Request 对象的创建。 你是从哪里找到这种奇怪的代码格式样式的?我不得不说这是我以前从未见过的。 好的,我不会再使用标签了。我只发布了这些陈述以关注问题的核心。 【参考方案1】:

您可能正在通过管道发送Request.name 的地址。接收方拿到后,Request.name明显指向无效内存。

【讨论】:

字符串在写入过程中动态分配。然而,读取进程是一个小型服务器应用程序,由写入进程通过 fork+exec 抛出。一旦抛出,父进程开始通过管道内的子进程发送数据。我想我无法在子进程中读取分配给父进程的内存,如果是这样,我该如何访问该字符串?在管道上写下整个内容本身? 您可以确定字符串的固定大小并将其声明为数组,或者您可以编写自己的序列化/反序列化函数。我会选择第一个选项(因为我已经充分探索了第二个选项,但没有什么好处)。【参考方案2】:

这可以通过将结构更改为以下内容来解决:

typedef struct 

    char   code;      
    pid_t  pid;       
    char   name[SOMESIZE];
    char   object[SOMEOTHERSIZE];
    int    id;          
    size_t size;     
 Request;

并对读写器进行相应的修改。如果管道是在进程之间连接的,那么nameobjectbuffer所包含的地址在新的上下文中是没有意义的。

【讨论】:

我也在考虑这个解决方案。但是在这个小项目中,我必须使用规范表(?)定义的一些结构:在这个结构中,每个字段都定义为一个指针(char * 用于字符串,void * 用于数据缓冲区)。然后必须将此结构传递给服务器进程(在这种情况下,子进程由第一个通过管道发送数据的进程 forked())。如果我无法在子进程中访问此内存区域,我应该如何处理由父关联内存分配的数据和缓冲区? 必须有一些关于如何表示指针的规范。我在 1980 年代多次遇到的一个问题是指针相对于结构的开头。但是,这里仍然缺少一些东西。 name 必须在消息中的某处包含字符,或者它们以某种方式编码,可能是通过指向两端的标准字符串表。无论哪种方式,都缺少重要的一块拼图。【参考方案3】:

您是否将您希望在阅读器代码中打开的标志传递给?

我原以为你想要 O_RDONLY 而不是 O_RDWR。

【讨论】:

比这更复杂:读取管道的过程会在一段时间内继续读取(1)管道处理写入其上的数据。如果没有人在管道上写入并且进程使用 O_RDONLY 标志打开它,它将在 open 调用中抛出 -1,我将不得不处理这种情况。使用 O_RDWR 标志,它将阻塞,直到进程本身在管道上写入或其他人这样做。

以上是关于访问填充了从管道读取的数据的结构时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章

访问结构时出现分段错误

为啥在尝试使用指针访问结构时出现此分段错误?

访问共享内存时出现分段错误

访问共享进程内存时出现分段错误(核心转储)

填充数组时出现分段错误[关闭]

从堆栈读取时出现分段错误