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

joa*_*dre 9 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)
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

我不明白这是什么问题.未初始化的值究竟在哪里?或者我应该忽略Valgrind报告的错误?

tim*_*rau 13

MESSAGE结构:

typedef struct{
    char type;    
    double value; 
} MESSAGE;
Run Code Online (Sandbox Code Playgroud)

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

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

MESSAGE msg;
memset(&msg, 0, sizeof(MESSAGE));
msg.type=_type;
msg.value=_value;
Run Code Online (Sandbox Code Playgroud)

  • @joaocandre 只要它们都使用相同的结构打包设置编译*或*此特定结构#pragma'd 使用单字节打包,那么不,你不会有问题。但是想象一下,如果一端使用 4 字节对齐,另一端使用单字节。一端期望结构为 12 个字节,而另一端期望 9 个字节。显然这不会成功。如果您完全控制了两端,那么只要每个人都按照相同的规则进行比赛,您就可以保持原样。我上面描述的是我将如何操纵游戏以确保它在不考虑上述规则的情况下正常运行。 (2认同)

Joh*_*ing 9

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

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

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

我的建议是摆脱困境,只发送你在代码中建模的内容.

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

#pragma pack (push, 1)

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

#pragma pack (pop)
Run Code Online (Sandbox Code Playgroud)

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