Безопасно ли приводить SOCKET к int под Win64? - PullRequest
23 голосов
/ 23 декабря 2009

Я работаю над портом Windows программы POSIX C ++.

Проблема в том, что стандартные функции 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

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

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


/*
 * Even though sizeof(SOCKET) is 8, it's 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?

Я хотел бы увидеть некоторую документацию, которая доказывает, что значения для SOCKET не могут быть больше, чем 2 ^ 32.

Заранее спасибо!
Ryck

Ответы [ 3 ]

9 голосов
/ 23 декабря 2009

Эта запись кажется повторяющей информацию о объектах ядра в msdn:

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

Поток продолжает ссылаться на Windows Internals Руссиновича и Соломона в качестве источника старших бит, равных нулю.

4 голосов
/ 22 октября 2014

Простой ответ на этот вопрос - нет. Взгляните на описание значений 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 возвращает дескриптор, ссылающийся на новый сокет.

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

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

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

  1. http://msdn.microsoft.com/en-us/library/windows/desktop/ms740516(v=vs.85).aspx
  2. http://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx
  3. http://msdn.microsoft.com/en-us/library/windows/desktop/ms742295(v=vs.85).aspx
  4. http://msdn.microsoft.com/en-us/library/windows/desktop/aa384267(v=vs.85).aspx

Редактировать (2018-01-29)

Поскольку эта тема все еще представляет интерес, стоит отметить, что довольно просто написать код переносимых сокетов в C ++ 11, не прибегая к сомнительным приведениям типов:

using socket_t = decltype(socket(0, 0, 0));

socket_t s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
0 голосов
/ 23 декабря 2009
/*
 * Even though sizeof(SOCKET) is 8, it's 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. Я никогда не видел 64-битную серию 9x, поэтому не о чем беспокоиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...