“指向未初始化的字节”Valgrind错误

时间:2013-10-14 16:37:14

标签: c++ sockets valgrind memory-alignment

我一直在使用 Valgrind 来查找我的代码中的内存泄漏,虽然没有发现内存泄漏,但是报告了一些错误,所有这些错误都源于单个函数/类方法:

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

错误指向的sendMsg(const char _type, const double _value)unix_socket类的一部分:

//...
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;
}

我看不出有什么问题。未初始化的值究竟在哪里?或者我应该忽略Valgrind报告的错误?

2 个答案:

答案 0 :(得分:13)

查看MESSAGE结构:

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

由于数据结构对齐,可能会强制value的地址与多个字大小的地址对齐。因此,在MESSAGE::typeMESSAGE::value之间填充了几个未使用的字节。那些是没有初始化的字节,因此由Valgrind报告。

作为一种解决方法,您可以强制memset()初始化整个结构。

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

答案 1 :(得分:9)

尽管@timrau已经非常正确地描述了核心问题(对齐/打包),但我不是所提议解决方案的粉丝。

您已在代码中将MESSAGE描述为由chardouble组成。但是,内存中实际数据结构的大小不是sizeof(char) + sizeof(double)的核心问题。

建议的解决方案建议在填写重要位之前简单地清除MESSAGE结构的所有位。我遇到的问题是语义和技术问题 - 从线路发送的数据结构的大小并不能准确表示您在代码中建模的内容。换句话说,您不只是发送chardouble - 您发送了chardouble和其他一些(填充)。

我的建议是摆脱残骸,只发送你在代码中建模的东西。

C ++中没有直接支持来关闭对齐和填充,但我所知道的所有编译器都提供了一种简单的机制来将数据结构与N字节对齐:

#pragma pack (push, 1)

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

#pragma pack (pop)

这将使MESSAGE数据结构完全您在代码中建模的内容,没有填充。这样做会使memset不必要,并且您将准确地发送sizeof(char) + sizeof(double)字节。