2013-10-14 3 views
8

Я использовал Valgrind, чтобы искать утечки памяти в моем коде, и, хотя утечек памяти не обнаружено, сообщается о некоторых ошибках, возникающих при один метод функции/класс:"указывает на неинициализированные байт" ошибки 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?

ответ

13

Посмотрите на MESSAGE структуры:

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

Благодаря выравниванию структуры данных, адрес value «s могут быть вынуждены выравнивать в адрес кратного размера слова. Поэтому несколько неиспользуемых байтов заполняются между MESSAGE::type и MESSAGE::value. Это байты, которые не были инициализированы и, таким образом, опубликованы Valgrind.

В качестве обходного пути вы можете принудительно инициализировать всю структуру на memset().

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

Альтернативой было бы упаковать структуру в байтовый вектор и отправить это, затянутое до точного размера каждого элемента. Отправка структур поверх проводной структуры никогда не является великой идеей.Клиент, читающий текущий механизм, не знает, что такое прокладка структуры, и, как следствие, не знает, выравнивается ли значение «значение» в 1-байтовом, 2-байтном, 4-байтном или даже 8-байтных , Если бы я закодировал это, я бы, вероятно, использовал протокол с определением длины и имел как пакетный, так и распакованный код, чтобы убедиться, что значения верны, тем самым устраняя проблемы выравнивания. – WhozCraig

+0

Вы правы, это сработало! Однако, оставив это как бы, какие недостатки я мог бы встретить? – joaocandre

+0

@WhozCraig Я просто использую его как сокеты Unix для обмена данными между двумя отдельными программами, было бы проблемой? – joaocandre

9

Хотя @timrau описал совершенно правильно, что основная проблема здесь (выравнивание/упаковка), я не поклонник предлагаемого решения.

В вашем коде вы описали MESSAGE, состоящий из char и 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) 

Это делает MESSAGE структура данных точно то, что вы смоделировали в своем коде, без прокладки. Это сделает memset ненужным, и вы отправите ровно sizeof(char) + sizeof(double) байтов по проводу.

+0

Это, вероятно, элементарный вопрос, но даже если эта структура упакована в 1-байтовое выравнивание, как это узнает принимающая сторона (другая сторона сокета)? – joaocandre

+0

Клиенту потребуется такое же определение структуры - точно так же, как если бы вы не упаковали. –

+0

Если бы мне пришлось сделать это быстро, это подход, который я бы взял. Если бы я должен был сделать это * переносимо *, я бы, скорее всего, потратил время на сериализацию членов. Но это все еще заслуживает моего голосования, и, соответственно, оно имеет. Этого из всех, что я видел, достаточно для требований OP. – WhozCraig