2016-06-07 12 views
1

Ich habe eine Funktion, die "struct sockaddr *" als Parameter (nennen wir diese input_address) nimmt, und dann muss ich an dieser Adresse operieren, die eine Sockaddr_in oder sockaddr_in6 sein kann , da ich sowohl IPv4 als auch IPv6 unterstütze.Sicher konvertieren von struct sockaddr zu struct sockaddr_storage

Ich bekomme etwas Speicherbeschädigung und versuche, es auf seine Quelle zu verfolgen, und dabei einen Code gefunden, der verdächtig scheint, also möchte ich überprüfen, ob dies der richtige Weg ist, Dinge zu tun.

struct sockaddr_storage *input_address_storage = (struct sockaddr_storage *) input_address; 
struct sockaddr_storage result = [UtilityClass performSomeOperation: *input_address_storage]; 

Zuerst dachte ich, die Besetzung in der ersten Zeile sicher war, dann aber in der zweiten Zeile muss ich dereferenzieren diesen Zeiger, die wie es scheint, falsch sein kann. Der Grund, warum ich besorgt bin, ist, dass es am Ende Speicher kopieren kann, der jenseits der ursprünglichen Struktur liegt (da sockaddr_in kürzer ist als sockaddr_in6). Ich bin nicht sicher, ob dies eine Speicherbeschädigung verursachen könnte (meine Vermutung ist nein), aber dennoch gibt mir dieser Code ein schlechtes Gefühl.

Ich kann nicht die Tatsache ändern, dass meine Funktion ein "struct sockaddr *" nimmt, also scheint es, als würde es schwierig sein, diese Art von Code zu umgehen, und dennoch möchte ich das Kopieren von einem Speicherort, wo ich sollte nicht sein.

Wenn jemand prüfen kann, ob das, was ich tue, falsch ist, und der beste Weg, dies zu beheben, würde ich es begrüßen.

EDIT: Ein Admin hatte mein C-Tag für C# aus irgendeinem Grund geändert. Der Code, den ich gab, ist in erster Linie C, mit einem Funktionsaufruf von Ziel C, der eigentlich keine Rolle spielt. Dieser Anruf hätte 0 sein können.

Antwort

0

Das Problem mit Ihrem Ansatz besteht darin, dass Sie eine vorhandene struct sockaddr* in eine struct sockaddr_storage* konvertieren. Stellen Sie sich vor, was passiert, wenn das Original ein "struct sockaddr_in . Since sizeof (struct sockaddr_in) < sizeof (struct sockaddr_storage)" ist, beschwert sich der Speicher-Desinfektor über die ungebundene Speicherreferenz.

struct sockaddr_storage ist im Wesentlichen ein container, um entweder Ihre struct sockaddr_in oder struct sockaddr_in6 zu enthalten.

Daher ist es nützlich, wenn Sie ein struct sockaddr* Objekt übergeben möchten, aber genügend Speicher für sockaddr_in und reservieren möchten.

Ein gutes Beispiel ist die recvfrom(3) Aufruf:

ssize_t recvfrom(int socket, void *restrict buffer, size_t length, 
       int flags, struct sockaddr *restrict address, 
       socklen_t *restrict address_len); 

Da address erfordert ein struct sockaddr* Objekt, werden wir ein struct sockaddr_storage erste, konstruieren und geben es in:

struct sockaddr_storage address; 
socklen_t address_length = sizeof(struct sockaddr_storage); 
ssize_t ret = recvfrom(fd, buffer, buffer_length, 0, (struct sockaddr*)&address, &address_length); 

if (address.ss_family == AF_INET) { 
    DoIpv4Work((struct sockaddr_in*)&address, ...); 
} else if (address.ss_family == AF_INET6) { 
    DoIpv6Work((struct sockaddr_in6*)&address, ...); 
} 

Der Unterschied in Ihrem Ansatz und meins ist, dass ich eine struct sockaddr_storage zuweisen und dann als struct sockaddr verwenden, aber Sie tun die REVERSE, und verwenden Sie eine struct sockaddr und dann als struct sockaddr_storage verwenden.

+0

Danke für die Erklärung. Was du gesagt hast, macht Sinn, aber es löst mein Problem nicht direkt, da meine Anforderung ist, dass ich eine Funktion habe, die ein "struct sockaddr *" braucht, also muss ich etwas umgekehrt machen. Die Frage ist also, vorausgesetzt, ich muss das Gegenteil tun, was ist der richtige Weg, dies zu tun. – Locksleyu