C语言 系统调用参数msgsnd(msgp->mtext)指向未初始化的字节-消息队列- Valgrind

5n0oy7gb  于 2023-01-25  发布在  其他
关注(0)|答案(1)|浏览(92)

我编写了一个C程序,测试并行进程上的一些消息队列。消息的定义如下:

typedef struct _Message{
    long type;
    int some_number;
    char some_info[SIZE];
}Message;

在我的程序中,msqid是使用msgget获得的消息队列的标识符,msg是Message的一个示例,它的所有字段都已初始化(为了以防万一,字符串末尾以外的所有字符也将得到值'\0'),所以我调用msgsnd,指定size对应于没有类型long值的Message(这就是我应该做的,对吗?),0表示标志,这样它就可以等待发送消息。

msgsnd(msqid, &msg, sizeof(Message) - sizeof(long), 0);

程序运行得很好,数据发送正确,另一个进程接收数据并正确打印所有内容,但瓦尔格林大师并不这么看:

==3514== Syscall param msgsnd(msgp->mtext) points to uninitialised byte(s)
    ==3514==    at 0x4F368F3: __msgsnd_nocancel (syscall-template.S:81)
    ==3514==    by 0x400E9D: func_a ......
    ==3514==    by 0x4011CB: main ......
    ==3514==  Address 0xfff00002c is on thread 1's stack
    ==3514==  in frame #1, created by func_a (???)
    ==3514==

msgsnd的官方文档提到了一个struct msgbuf,它包含一个名为mtext的字段,但我不太明白它的意思,它如何与我定制的消息struct相对应,以及我应该如何给予它一个值。

struct msgbuf {
     long mtype;       /* message type, must be > 0 */
     char mtext[1];    /* message data */
  };
ubof19bj

ubof19bj1#

问题可能是您的_Message与8字节边界对齐(我假设是64位构建,32位构建和4字节边界也是如此)。

typedef struct _Message{
    long type; // 8 bytes
    int some_number; // 4 bytes
    char some_info[SIZE]; // SIZE bytes
}Message;

如果SIZE是4的奇数倍,那么_Message的总大小将是8的倍数,您将不会看到任何问题。
如果SIZE是任何其他值,则_Message将被填充到8的下一个倍数。例如,如果SIZE是10,则成员的大小之和是22字节(也没有对齐孔)。这将被舍入到22,意味着在结构的末尾有2个填充字节。
Valgrind抱怨此填充未初始化。当您将示例memset为零时,成员数据和填充都会初始化,Valgrind不再抱怨。
在Valgrind方面,修复这个问题并不容易。像这样的系统调用接受指向任何东西的指针,Valgrind无法判断未初始化的字节是真正的错误还是结构中的漏洞/填充。一种可能性是对小于字长的未初始化范围生成一个较低级别的警告。

相关问题