2016-06-07 155 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