2016-06-07 157 views
1

我有一個函數,它接受「struct sockaddr *」作爲參數(我們稱之爲input_address),然後我需要對該地址進行操作,該地址可能是sockaddr_in或sockaddr_in6 ,因爲我支持IPv4和IPv6。安全地從struct sockaddr轉換爲struct sockaddr_storage

我得到一些內存損壞,並試圖追查它的來源,並在過程中發現一些代碼似乎懷疑,所以我想驗證,如果這是正確的方式做事情。

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

起初我以爲在第一線投是安全的,但隨後在第二行,我需要取消引用該指針,這似乎像它可能是錯誤的。我擔心的原因是它最終可能會複製超出原始結構的內存(因爲sockaddr_in比sockaddr_in6更短)。我不確定這是否會導致內存損壞(我的猜測是否定),但是這段代碼給了我一個不好的感覺。

我不能改變我的函數採用「struct sockaddr *」的事實,所以看起來好像很難解決這種類型的代碼,但我想避免從內存位置複製I不應該。

如果任何人都可以驗證我所做的是否是錯誤的,並且解決這個問題的最佳方法,我會很感激。

編輯:由於某種原因,管理員已將C標籤更改爲C#。我給出的代碼主要是C,而來自目標C的一個函數調用並不重要。該呼叫可能是C.

回答

0

您的方法存在的問題是,您正在將現有的struct sockaddr*轉換爲struct sockaddr_storage*。想象一下,如果原始結構是struct(struct sockaddr_in)sizeof(struct sockaddr_storage)`sizeof(struct sockaddr_storage)',那麼內存清理器會抱怨未綁定的內存引用會發生什麼。

struct sockaddr_storage本質上是一個container包含您的struct sockaddr_instruct sockaddr_in6

因此,當您想要傳入struct sockaddr*對象但希望爲sockaddr_in和分配足夠的內存時,它非常有用。

一個很好的例子是recvfrom(3)電話:

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

由於address需要struct sockaddr*對象,我們將構建一個struct sockaddr_storage第一,並通過它:

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, ...); 
} 

的差額,在你的方法我的是我分配一個struct sockaddr_storage,然後使用它作爲struct sockaddr,但你做REVERSE,並使用struct sockaddr然後用它作爲struct sockaddr_storage

+0

感謝您的解釋。你說的是有道理的,但是它並不直接解決我的問題,因爲我的要求是我有一個函數需要一個「struct sockaddr *」,所以我必須做相反的事情。所以問題是,假設我需要做相反的事情,那麼做到這一點的正確方法是什麼。 – Locksleyu