UB в сетевом API Windows
От: Videoman Россия https://hts.tv/
Дата: 02.04.25 20:41
Оценка: 8 (2)
Создаю UDP сокет под WSA как обычно:
handle = ::socket(AF_INET, SOCK_DGRAM, 0);

Связываю сокет с адресатом через ::connect() (соединение естественно реально не устанавливается)

Задаю таймаут на прием:
const int timeout = 500;
::setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&timeout), sizeof(timeout)));

Принимаю в цикле данные с помощью WSARecv() в блокирующем режиме (без OVERLAPPED).

В случае, если пакеты приходят, всё нормально. Если пакетов нет, то ожидаемо возвращается SOCKET_ERROR и WSAGetLastError() возвращает WSAETIMEDOUT. Так работает почти везде.
Но на одном очень быстром сервере (128 ядер), иногда, вместо WSAETIMEDOUT возвращается WSA_IO_PENDING. Т.е. на блокирующем вызове (только по истечении таймаута) функция WSARecv возвращает, что операция не завершена и активна (потенциально). Тут я уже напрягся, т.к. OVERLAPPED создается внутри на стеке и потенциально драйвер может туда записать.
После продолжительных тестов на этом сервере опасения подтвердились: код падал в случайных местах незадолго после возврата из WSARecv.

Вопрос к знатокам, как такое поведение вообще возможно? Это баг реализации ? Если да, то на каком уровне проблема может быть?

P.S. Всё это было нужно только для того, что бы использовать таймаут на приеме пакетов по UPD и обошел я это реализацией своей блокирующей версией, которая явно использует OVERLAPPED и вызывает у него CancelIOEx() и дожидается c помощью WSAGetOverlappedResult() реального завершения операции. Вроде пока пронесло, но осадочек отрицательный остался.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.