2013-10-14 10 views
8

Ich habe Valgrind verwendet, um Speicherlecks in meinem Code zu suchen, und während keine Speicherlecks gefunden werden, werden einige Fehler gemeldet, die alle von a stammen einzelne Funktion/Klassenmethode:"zeigt auf nicht initialisierte Byte (s)" Valgrind Fehler

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

die sendMsg(const char _type, const double _value), dass die Fehler zeigen auf, einen Teil der unix_socket Klasse ist:

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

ich sehe nicht, was das Problem ist. Wo genau sind die nicht initialisierten Werte? Oder sollte ich einfach die von Valgrind gemeldeten Fehler ignorieren?

Antwort

13

Blick auf die MESSAGE struct:

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

Aufgrund Datenstruktur Ausrichtung value ‚s-Adresse kann zu Adresse eines Vielfachen der Wortgröße auszurichten gezwungen werden. Daher werden mehrere nicht verwendete Bytes zwischen MESSAGE::type und MESSAGE::value aufgefüllt. Das sind die Bytes, die nicht initialisiert und somit von Valgrind gemeldet wurden.

Als eine Umgehungsmöglichkeit können Sie die Initialisierung der gesamten Struktur durch memset() erzwingen.

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

Eine Alternative wäre, die Struktur in einen Byte-Vektor zu packen und diesen zu verschicken, auf die genaue Größe jedes Elements zusammengezogen. Das Senden von Strukturen über die Wire-in-struct-Form ist niemals eine großartige Idee.Ein Client, der den aktuellen Mechanismus liest, hat keine Möglichkeit zu wissen, was die Strukturauffüllung ist, und als Konsequenz hat er keine Möglichkeit zu wissen, ob "Wert" auf 1 Byte, 2 Byte, 4 Byte oder sogar 8 Byte ausgerichtet ist . Würde ich dies kodieren, würde ich wahrscheinlich ein Length-Definitive-Protokoll verwenden und Code sowohl ein- als auch auspacken, um sicherzustellen, dass die Werte korrekt sind, wodurch Ausrichtungsprobleme eliminiert werden. – WhozCraig

+0

Sie sind wright, das hat funktioniert! Wenn ich es sozusagen verlasse, auf welche Nachteile könnte ich dann stoßen? – joaocandre

+0

@WhozCraig Ich benutze es nur als Unix-Sockets, um Daten zwischen zwei verschiedenen Programmen zu teilen, wäre es die Mühe wert? – joaocandre

9

Obwohl @timrau ganz richtig, was das Kernproblem hier beschrieben ist (Ausrichtung/Verpackung), ich bin kein Fan von der vorgeschlagenen Lösung.

Sie haben in Ihrem Code eine MESSAGE beschrieben, die aus einer char und einer double besteht. Die Größe der tatsächlichen Datenstruktur im Speicher ist jedoch nicht sizeof(char) + sizeof(double) und , dass das Kernproblem ist.

Die vorgeschlagene Lösung schlägt vor, einfach alle Bits der Struktur MESSAGE vor dem Einfüllen der wichtigen Bits zu löschen. Das Problem, das ich damit habe, ist sowohl ein semantischer als auch ein technischer - die Größe der Datenstruktur, die über den Draht gesendet wird, ist keine genaue Darstellung dessen, was Sie im Code modelliert haben. Mit anderen Worten, Sie senden nicht nur eine char und eine double - Sie senden eine char, eine double und einige andere cruft (Padding).

Mein Vorschlag ist es, den Crust loszuwerden und nur das zu senden, was Sie in Ihrem Code modelliert haben.

Es gibt keine direkte Unterstützung in C++ deaktivieren Ausrichtung und Polsterung, aber alle Compiler Ich bin mir bewusst einen einfachen Mechanismus zur Verfügung stellen Datenstrukturen N Bytes auszurichten:

#pragma pack (push, 1) 

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

#pragma pack (pop) 

Dies wird die MESSAGE machen Datenstruktur genau was Sie in Ihrem Code modelliert haben, ohne Polsterung. Dadurch wird die memset unnötige, und Sie senden genau sizeof(char) + sizeof(double) Bytes auf dem Draht.

+0

Dies ist wahrscheinlich eine elementare Frage, aber selbst wenn diese Struktur in 1-Byte-Ausrichtung gepackt ist, wie wird das Empfangsende (andere Seite des Sockets) das wissen? – joaocandre

+0

Der Client benötigt die gleiche Strukturdefinition - genau wie wenn Sie nicht packen. –

+0

Wenn ich das schnell machen müsste, wäre das der Ansatz, den ich wählen würde. Wenn ich es * portabel * machen müsste, würde ich wahrscheinlich die Zeit verbringen, um die Mitglieder zu serialisieren. Aber das verdient noch meine Stimme und hat es dementsprechend. Es ist, von allem, was ich gesehen habe, genug für die Anforderungen des OP. – WhozCraig

Verwandte Themen