对于 64 位应用程序,.NET 使用 WSAStartup 是否安全?

Is the .NET use of WSAStartup safe for 64-bit apps?

对于 64 位应用程序,WSAData 结构的 .NET Framework 版本和本机 Win32 版本之间存在不匹配,因为字段的顺序不同。我复制了用于我们基于 C# 的产品的 .NET 版本,一位同事担心我导致了内存损坏。使用 DllImport / PInvoke 时是否存在由于这种不匹配而导致内存损坏的风险?将本机版本编组到托管版本时是否存在无效内存访问的风险?假设我不关心实际访问生成的 WSAData 对象的字段。我只是想确定我对 WSAStartup 的调用不会破坏内存或使应用程序崩溃。

这里是 WinSock2.h 中的原生 C++ 版本。请注意,成员的顺序在 64 位和 32 位中是不同的。 WSADESCRIPTION_LEN 是 256,WSASYS_STATUS_LEN 是 128。

typedef struct WSAData {
        WORD                    wVersion;
        WORD                    wHighVersion;
#ifdef _WIN64
        unsigned short          iMaxSockets;
        unsigned short          iMaxUdpDg;
        char FAR *              lpVendorInfo;
        char                    szDescription[WSADESCRIPTION_LEN+1];
        char                    szSystemStatus[WSASYS_STATUS_LEN+1];
#else
        char                    szDescription[WSADESCRIPTION_LEN+1];
        char                    szSystemStatus[WSASYS_STATUS_LEN+1];
        unsigned short          iMaxSockets;
        unsigned short          iMaxUdpDg;
        char FAR *              lpVendorInfo;
#endif
} WSADATA, FAR * LPWSADATA;

这里是 managed version in the .NET Framework:

[StructLayout(LayoutKind.Sequential)]
internal struct WSAData {
    internal short wVersion;
    internal short wHighVersion;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=257)]
    internal string szDescription;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=129)]
    internal string szSystemStatus;
    internal short iMaxSockets;
    internal short iMaxUdpDg;
    internal IntPtr lpVendorInfo;
}

[DllImport(WS2_32, CharSet=CharSet.Ansi, BestFitMapping=false,
    ThrowOnUnmappableChar=true, SetLastError=true)]
internal static extern SocketError WSAStartup(
    [In] short wVersionRequested,
    [Out] out WSAData lpWSAData
                                               );

是的,结构错了...可以用错误的结构和正确的结构来测试:

[StructLayout(LayoutKind.Sequential)]
internal struct WSAData
{
    internal short wVersion;
    internal short wHighVersion;
    internal short iMaxSockets;
    internal short iMaxUdpDg;
    internal IntPtr lpVendorInfo;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
    internal string szDescription;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
    internal string szSystemStatus;
}

WSAData data;
int res = WSAStartup(2 << 8 | 2, out data);
Console.WriteLine("64bits: {0}, Result = {1}, szDescription: {2}, szSystemStatus: {3}", Environment.Is64BitProcess, res, data.szDescription, data.szSystemStatus);

但是你没有任何问题,因为 .NET 可能不使用所有这些不同的字段(它需要描述什么?)Unicode 转换甚至不会有问题,因为使用的方法是 Ansi 字符 (CharSet=CharSet.Ansi),每个 Ansi 字符都是 Unicode 中的合法字符。

当然,这是不正确的。 .NET Framework 侥幸逃脱,结构大小仍然正确(32 位模式下为 400 字节,64 位模式下为 408 字节),因此不会发生内存损坏。而且它实际上并没有使用任何返回的信息,如果他们这样做的话,他们肯定会发现这个错误。

您可以在 connect.microsoft.com 提交错误,但我怀疑他们会急于修复它。