Безопасно ли использовать SOCKET для int под Win64?

Im работает над портом Windows программы POSIX С++.

Проблема заключается в том, что стандартные функции POSIX, такие как accept() или bind(), ожидают, что 'int является первым параметром, в то время как его коллеги WinSock используют "SOCKET". Когда скомпилировано для 32-битного, все в порядке, потому что оба 32-битные, но под Win64 SOCKET - 64 бит, а int остается 32-битным, и он генерирует много предупреждений компилятора следующим образом: warning C4244: '=' : conversion from 'SOCKET' to 'int', possible loss of data

Я попытался решить проблему с помощью typedef:

#ifdef _WIN32
 typedef SOCKET sock_t;
#else
 typedef int sock_t;
#endif

и заменив 'ints на sock_t в соответствующих местах.

Это было нормально, пока я не достиг части кода, который вызывает API OpenSSL. Как оказалось, OpenSSL использует ints для сокетов даже на Win64. Это казалось действительно странным, поэтому я начал искать ответ, но единственное, что я нашел, это старое сообщение в списке рассылки openssl-dev, который ссылается на комментарий e_os.h:

/*
 * Even though sizeof(SOCKET) is 8, it safe to cast it to int, because
 * the value constitutes an index in per-process table of limited size
 * and not a real pointer.
 */

Итак, мой вопрос: действительно ли безопасно бросать SOCKET в int? Id нравится видеть какую-то документацию, которая доказывает, что значения для SOCKET не могут превышать 2 ^ 32. Спасибо заранее! Райк

3 ответа

Простой ответ на этот вопрос - нет. Взгляните на описание значений SOCKET в MSDN [1]:

У дескрипторов Windows Sockets нет ограничений, кроме того, что значение INVALID_SOCKET не является допустимым сокетом. Ручки сокета могут принимать любое значение в диапазоне от 0 до INVALID_SOCKET-1.

Таким образом, API допускает все значения в диапазоне [0, 2 ^ 64 - 1] в 64-битной Windows. И если API когда-либо вернет значение больше 2 ^ 32 - 1, присвоение ему int приведет к усечению дескриптора. Также рассмотрите описание возвращаемого значения из функции socket() [2]:

Если ошибка не возникает, сокет возвращает дескриптор, ссылающийся на новый сокет.

Обратите внимание, что он наиболее решительно не обещает вернуть дескриптор ядра. Это позволяет обсуждать возможные значения для дескрипторов ядра.

Все сказанное, начиная с этой записи, функция socket() действительно возвращает дескриптор ядра (или что-то неотличимое от дескриптора ядра) [3], а дескрипторы ядра действительно ограничены 32 битами [4]. Но имейте в виду, что Microsoft может изменить любую из этих вещей завтра, не нарушая своих интерфейсных контрактов.

Однако, поскольку огромное количество приложений зависело от этих конкретных деталей реализации (и что более важно, так же как и OpenSSL), Microsoft, вероятно, дважды подумает о внесении каких-либо изменений. Итак, продолжайте и запустите SOCKET в int. Просто имейте в виду, что это неотъемлемо опасная, плохая практика и никогда не оправдана во имя целесообразности.


/*
 * Even though sizeof(SOCKET) is 8, it safe to cast it to int, because
 * the value constitutes an index in per-process table of limited size
 * and not a real pointer.
 */

Этот комментарий верен. SOCKET= дескриптор файла в серии Windows NT. Я никогда не видел 9-разрядную серию 64 бит, поэтому не о чем беспокоиться.


Этот post кажется повторением информации о объектах ядра в msdn:

Обработки объектов ядра зависят от процесса. То есть, процесс должен либо создать объект, либо открыть существующий объект для получения дескриптора объекта ядра. Предел для каждого процесса для дескрипторов ядра равен 2 ^ 24.

В потоке далее приводятся ссылки Windows Internals by Russinovich and Solomon как источник для высоких бит, равных нулю.

licensed under cc by-sa 3.0 with attribution.