“points to uninitialised byte(s)” Valgrind errors

2019-02-05 01:33发布

问题:

I've been using Valgrind to look for memory leaks in my code, and while no memory leaks are being found, some errors are reported all of them originating at a single function/class method:

==17043== ERROR SUMMARY: 10100 errors from 3 contexts (suppressed: 0 from 0)
==17043== 
==17043== 100 errors in context 1 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043==    at 0x5441DA2: send (send.c:28)
==17043==    by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==    by 0x404F1C: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==    by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==  Address 0x7feffff61 is on thread 1's stack
==17043==  Uninitialised value was created by a stack allocation
==17043==    at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== 
==17043== 
==17043== 100 errors in context 2 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043==    at 0x5441DA2: send (send.c:28)
==17043==    by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==    by 0x404E8A: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==    by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==  Address 0x7feffff61 is on thread 1's stack
==17043==  Uninitialised value was created by a stack allocation
==17043==    at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== 
==17043== 
==17043== 9900 errors in context 3 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043==    at 0x5441DA2: send (send.c:28)
==17043==    by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==    by 0x404EE8: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==    by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==  Address 0x7feffff61 is on thread 1's stack
==17043==  Uninitialised value was created by a stack allocation
==17043==    at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== 
==17043== ERROR SUMMARY: 10100 errors from 3 contexts (suppressed: 0 from 0)

The sendMsg(const char _type, const double _value), that the errors are pointing at, is part of unix_socket class:

//...
typedef struct{
    char type;    
    double value; 
} MESSAGE;

//...
int unix_socket::sendMsg(const char _type, const double _value){
    MESSAGE msg;
    msg.type=_type;
    msg.value=_value;
    int n = send(client_sock, &msg, sizeof(msg), 0);
    if (n < 0) {
        perror("send");
        return -1;
    } 
    c_sent=msg.type;
    v_sent=msg.value;
    return 0;
}

I don't see what is the problem. Where exactly are the uninitialized values? Or should I just ignore the errors reported by Valgrind?

回答1:

Look at the MESSAGE struct:

typedef struct{
    char type;    
    double value; 
} MESSAGE;

Due to data structure alignment, value's address may be forced to align to address of a multiple of word size. Therefore, several unused bytes is padded between MESSAGE::type and MESSAGE::value. Those are the bytes which weren't initialized and thus reported by Valgrind.

As a workaround, you could force initializing the whole struct by memset().

MESSAGE msg;
memset(&msg, 0, sizeof(MESSAGE));
msg.type=_type;
msg.value=_value;


回答2:

Although @timrau has described quite correctly what the core problem is here (alignment/packing), I'm not a fan of the proposed solution.

You have described a MESSAGE in your code as consisting of a char and a double. The size of the actual data structure in memory however is not sizeof(char) + sizeof(double), and that is the core problem.

The proposed solution suggests simply clearing out all of the bits of the MESSAGE structure before filling in the important bits. The problem I have with that is both a semantic one a technical one -- the size of the data structure sent down the wire is not an accurate representation of what you modeled in the code. In other words, you're not just sending a char and a double -- you're sending a char, a double and some other cruft (padding).

My suggestion is to get rid of the cruft and send only what you modeled in your code.

There is no direct support in C++ to turn off alignment and padding, but all compilers I'm aware of provide a simple mechanism to align data structures to N bytes:

#pragma pack (push, 1)

typedef struct{
    char type;    
    double value; 
} MESSAGE;

#pragma pack (pop)

This will make the MESSAGE data structure exactly what you've modeled in your code, with no padding. Doing this makes the memset unnecesarry, and you'll send exactly sizeof(char) + sizeof(double) bytes down the wire.