coriuser
coriuser

Reputation: 21

Syscall param msgsnd(msgp->mtext) points to uninitialised byte(s) - Message queues - Valgrind

I made a C program that tests some message queues on parallel processes. The messages are defined like this:

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

In my program, msqid is the identifier of the message queue that I obtain with msgget, and msg is an instance of Message for which all fields are initialised (all chars beyond the end of the string also get the value '\0' just in case). So I call msgsnd, specifying that the size corresponds to Message without the long value for the type (that's what I'm supposed to do, right?), and 0 for the flag so it waits to send the message.

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

The program works just fine, the data is sent correctly and another process receives it and prints everything correctly. However, Master Valgrind doesn't see it that way:

    ==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== 

The official documentation for msgsnd talks about a struct msgbuf, which contains a field called mtext, but I don't really understand what it means, how it corresponds to my customised struct for Message and how I'm suppossed to give it a value. So, any ideas on how to solve this?

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

Upvotes: 2

Views: 1602

Answers (1)

Paul Floyd
Paul Floyd

Reputation: 6916

The issue is probably that your _Message is getting aligned to an 8 byte boundary (I'm assuming a 64bit build, the same would be true for 32bit builds and 4byte boundaries).

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

If SIZE is an odd multiple of 4 then the overall size of _Message will be a multiple of 8 and you will see no problem.

If SIZE is any other value then the _Message will get padded to the next multiple of 8. For instance if SIZE is 10 then the sum of the size of the members is 22 bytes (and there are no alignment holes as well). This will be rounded up to 24 meaning 2 padding bytes at the end of the struct.

Valgrind is complaining that this padding is uninitialized. When you memset the instance to zero then both the member data and the padding get initialized and Valgrind no longer complains.

On the Valgrind side it isn't easy to fix this. Syscalls like this take pointers to anything and Valgrind can't tell whether uninitialized bytes are a genuine error or whether they are holes/padding in structures. One possibility would be to generate a lower level of warning for uninitialized ranges that are less than the word size.

Upvotes: 2

Related Questions