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

934 Views Asked by At

There is a mismatch between the .NET Framework version and the native Win32 version of the WSAData struct, for 64-bit apps, because the order of the fields is different. I had copied the .NET version for use in our C#-based product and a coworker is concerned that I have caused a memory corruption. Is there any risk of memory corruption because of this mismatch when using DllImport / PInvoke? Is there any risk of an invalid memory access when marshaling the native version to the managed version? Let's assume I'm not concerned with actually accessing the fields of the resulting WSAData object. I just want to be certain that my call to WSAStartup does not corrupt memory or crash the app.

Here is the native C++ version in WinSock2.h. Note that the order of the members is different in 64-bit versus 32-bit. WSADESCRIPTION_LEN is 256 and WSASYS_STATUS_LEN is 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;

Here is the 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
                                               );
2

There are 2 best solutions below

4
On BEST ANSWER

Sure, this is incorrect. The .NET Framework gets away with it, the structure sizes are still correct (400 bytes in 32-bit mode, 408 in 64-bit mode) so no memory corruption can occur. And it doesn't actually use any of the returned info, they would surely have caught the bug if they did.

You can file the bug at connect.microsoft.com, I doubt they'll be in a hurry to fix it however.

0
On

Yes, the structure is wrong... You can test by using the wrong structure and the right structure:

[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);

BUT you don't have any problem, because probably .NET doesn't use all these various fields (what does it needs the description for?) There can't even be a problem with Unicode conversion, because the method used is the Ansi one (CharSet=CharSet.Ansi), and every Ansi character is a legal character in Unicode.