WinXP: sendto() failed with 10014 (WSAEFAULT) if destination address is const-qualified, IPv4-specific

StackOverflow https://stackoverflow.com/questions/16346556

  •  14-04-2022
  •  | 
  •  

Question

It seems, I found a bug in Windows... Ok, let not be such pathetic one. I'm trying to do generic sendto() operation for UDP and occasionaly found that WinXP (32 bit, SP3, checked on real and virtual machines) returns "-1" bytes sent with WSAGetLastError() as error 10014 (aka WSAEFAULT). Occurs only on IPv4 addresses (same code with IPv6 destination works perfectly). Major condition to reproduce is usage of "const struct sockaddr_in" declared at global scope. Here is the plain C code for VS2010 (also I've tried with Eclipse+MinGW, got same results):

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <winsock2.h>
#include <stdint.h>

#pragma comment(lib, "Ws2_32.lib")

#define INADDR_UPNP_V4 0xEFFFFFFA
#define htons(x) ((((uint16_t)(x) & 0xFF00) >> 8) | (((uint16_t)(x) & 0x00FF) << 8))
#define htonl(x) ((((uint32_t)(x) & 0xFF000000) >> 24) | (((uint32_t)(x) & 0x00FF0000) >> 8) | (((uint32_t)(x) & 0x0000FF00) << 8) | (((uint32_t)(x) & 0x000000FF) << 24))

// Magic "const" qualifier, causes run-time error
const struct sockaddr_in addr_global = {
    AF_INET,
    htons(1900),
    {
            htonl(INADDR_UPNP_V4)
    },
    {0},
};

int main(int argc, char** argv)
{
#define CR_LF "\r\n"

    // these two lines to un-buffer console window output at Win32, see URL below for details
    // http://wiki.eclipse.org/CDT/User/FAQ#Eclipse_console_does_not_show_output_on_Windows
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);

    printf("Started\n");

    const struct sockaddr_in addr_local = {
            AF_INET,
            htons(1900),
            {
                    htonl(INADDR_UPNP_V4)
            },
            {0},
    };

    const char *MSEARCH_REQUEST_V4 = "M-SEARCH * HTTP/1.1"CR_LF
    "Host:239.255.255.250:1900"CR_LF
    "MAN:\"ssdp:discover\""CR_LF
    "ST:ssdp:all"CR_LF
    "MX:3"CR_LF
    CR_LF;

    const int MSEARCH_LEN = strlen(MSEARCH_REQUEST_V4);

    WSADATA wsaData;
    int res = WSAStartup(MAKEWORD(2, 2), &wsaData);

    int af = AF_INET;
    int sock_id = socket(af, SOCK_DGRAM, IPPROTO_UDP);
    if (-1 == sock_id) {
        printf("%s: socket() failed with error %i/%i\n", __FUNCTION__,
                errno, WSAGetLastError());
        return 1;
    }

    int data_sent = 0;

    printf("1st sendto()\n");
    data_sent = sendto(sock_id, MSEARCH_REQUEST_V4,
            MSEARCH_LEN, 0,
            (const struct sockaddr * const)&addr_local,
            sizeof(struct sockaddr_in));
    if (data_sent < 0) {
        printf("%s: sendto(local) failed with error %i/%i\n", __FUNCTION__,
                errno, WSAGetLastError());
    }

    printf("2nd sendto(), will fail on WinXP SP3 (32 bit)\n");
    data_sent = sendto(sock_id, MSEARCH_REQUEST_V4,
            MSEARCH_LEN, 0,
            (const struct sockaddr * const)&addr_global,
            sizeof(struct sockaddr_in));
    if (data_sent < 0) {
        printf("%s: sendto(global) failed with error %i/%i\n", __FUNCTION__,
                errno, WSAGetLastError());
    }

    closesocket(sock_id);

    res = WSACleanup();
    printf("Finished\n");
    return 0;
}

So, if you run this code at Win7, for example, it will be absolutely OK. But WinXP fails on addr_global usage if it equipped with "const" qualifier (see "Magic" comment above). Also, "Output" window says:

First-chance exception at 0x71a912f4 in SendtoBugXP.exe: 0xC0000005: Access violation writing location 0x00415744.

With help of "Autos" window, it's easy to figure out that 0x00415744 location is address of addr_global.sin_zero field. It seems, WinXP to write zeros there and violates memory access flags. Or this is just silly me, trying to go wrong door?

Appreciate your comments a lot. Thanks in advance.

Was it helpful?

Solution 2

To summarize results from other forums: yes, this is Windows bug, existing up to WinXP in "desktop" and Win2003 at "server" segments. WinSock code does attempt to force-fill "sin_zero" field with zeros. And "const" global scope causes memory access violation. Stack trace is about like that:

Thread [1] 0 (Suspended : Signal : SIGSEGV:Segmentation fault)
WSHTCPIP!WSHGetSockaddrType() at 0x71a912f4
0x71a52f9f
WSAConnect() at 0x71ab2fd7
main() at tests_main.c:77 0x401584

The same behavior observed on bind() by other people.

OTHER TIPS

Yeah you found a bug. sendto() has that argument declared const, but wrote to it anyway. Good luck getting it fixed though. Hint: it might be in your antivirus or firewall.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top