简体   繁体   English

安全地从struct sockaddr转换为struct sockaddr_storage

[英]Safely converting from struct sockaddr to struct sockaddr_storage

I have a function which takes in "struct sockaddr *" as a parameter (let's call this input_address), and then I need to operate on that address, which may be a sockaddr_in or sockaddr_in6, since I support both IPv4 and IPv6. 我有一个函数,它接受“struct sockaddr *”作为参数(让我们调用这个input_address),然后我需要操作该地址,可能是sockaddr_in或sockaddr_in6,因为我同时支持IPv4和IPv6。

I'm getting some memory corruption and trying to track it down to it's source, and in the process found some code that seems suspect, so I would like to validate if this is the right way to do things. 我得到了一些内存损坏并试图跟踪它的源代码,并且在此过程中发现了一些似乎可疑的代码,所以我想验证这是否是正确的做事方式。

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

At first I thought the cast in the first line was safe, but then in the second line I need to dereference that pointer, which seems like it may be wrong. 起初我认为第一行中的强制转换是安全的,但是在第二行中我需要取消引用该指针,这看起来可能是错误的。 The reason I am concerned is that it may end up copying memory that is beyond where the original structure is (since sockaddr_in is shorter than sockaddr_in6). 我担心的原因是它最终可能会复制超出原始结构的内存(因为sockaddr_in比sockaddr_in6短)。 I am not sure if this could cause a memory corruption (my guess is no), but nevertheless this code gives me a bad feeling. 我不确定这是否会导致内存损坏(我的猜测是否定的),但是这段代码给了我一种不好的感觉。

I can't change the fact my function takes a "struct sockaddr *", so it seems like it would be difficult to work around this type of code, and yet I want to avoid copying from a memory location where I shouldn't be. 我无法改变我的函数采用“struct sockaddr *”的事实,所以似乎很难解决这种类型的代码,但我想避免从我不应该的内存位置进行复制。

If anyone can validate whether what I am doing is wrong, and the best way to fix this, I'd appreciate it. 如果有人能够验证我所做的事情是否错误,以及解决这个问题的最佳方法,我会很感激。

EDIT: An admin had changed my C tag for C# for some reason. 编辑:由于某种原因,管理员已经为C#更改了我的C标签。 The code I gave is primarily C, with one function call from objective C that doesn't really matter. 我给出的代码主要是C,来自目标C的一个函数调用并不重要。 That call could have been C. 那个电话可能是C.

The problem with your approach is that you are converting an existing struct sockaddr* into a struct sockaddr_storage* . 您的方法的问题是您正在将现有的struct sockaddr*转换为struct sockaddr_storage* Imagine what happens if the original was a ``struct sockaddr_in . Since 想象一下如果原版是一个``struct sockaddr_in会发生什么. Since . Since sizeof(struct sockaddr_in) < sizeof(struct sockaddr_storage)`, the memory-sanitizer complains of unbound memory reference. . Since sizeof(struct sockaddr_in)<sizeof(struct sockaddr_storage)`,内存清理程序会抱怨未绑定的内存引用。

struct sockaddr_storage is essentially a container to contain either your struct sockaddr_in or struct sockaddr_in6 . struct sockaddr_storage本质上是一个包含 struct sockaddr_instruct sockaddr_in6容器

Hence, it is useful when you want to pass in a struct sockaddr* object but want to allocate enough memory for both sockaddr_in and sockaddr_in6 . 因此,当您想要传入struct sockaddr*对象但希望为sockaddr_insockaddr_in6分配足够的内存时,它很有用。

A good example is the recvfrom(3) call: 一个很好的例子是recvfrom(3)调用:

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

Since address requires a struct sockaddr* object, we will construct a struct sockaddr_storage first, and pass it in: 由于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, ...);
}

The difference in your approach and mine is that I allocate a struct sockaddr_storage and then use it as struct sockaddr , but you do the REVERSE , and use a struct sockaddr and then use it as struct sockaddr_storage . 您和我的方法的不同之处在于我分配了一个struct sockaddr_storage然后将其用作struct sockaddr ,但是您执行REVERSE ,并使用struct sockaddr然后将其用作struct sockaddr_storage

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM