2016-06-07 3 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 *», поэтому кажется, что было бы сложно обойти этот тип кода, и все же я хочу избежать копирования из памяти, где я не должно быть.

Если кто-нибудь может подтвердить, что я делаю неправильно, и лучший способ исправить это, я был бы признателен.

EDIT: Администратор по какой-то причине изменил мой тег C для C#. Код, который я дал, в основном C, с одним вызовом функции из объектива C, который на самом деле не имеет значения. Этот вызов мог быть C.

ответ

0

Проблема с вашим подходом заключается в том, что вы преобразовываете существующий struct sockaddr* в struct sockaddr_storage*. Представьте, что произойдет, если оригинал был `` struct sockaddr_in . Since sizeof (struct sockaddr_in) < sizeof (struct sockaddr_storage) `, дезинфицирующее устройство для памяти жалуется на ссылку на несвязанные ячейки памяти.

struct sockaddr_storage по существу container, содержащий ваши struct sockaddr_in или struct 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