Commit 9c94236e authored by Marc Hoersken's avatar Marc Hoersken Committed by Daniel Stenberg
Browse files

connect.c/ftp.c: Fixed dereferencing pointer breakin strict-aliasing

Fixed warning: dereferencing pointer does break strict-aliasing rules
by using a union instead of separate pointer variables.
Internal union sockaddr_u could probably be moved to generic header.
Thanks to Paul Howarth for the hint about using unions for this.

Important for winbuild: Separate declaration of sockaddr_u pointer.
The pointer variable *sock cannot be declared and initialized right
after the union declaration. Therefore it has to be a separate statement.
parent 3f9ab7cf
Loading
Loading
Loading
Loading
+21 −17
Original line number Diff line number Diff line
@@ -253,12 +253,16 @@ static CURLcode bindlocal(struct connectdata *conn,
  struct SessionHandle *data = conn->data;

  struct Curl_sockaddr_storage sa;
  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;

  union sockaddr_u {
    struct sockaddr sa;
    struct sockaddr_in sa4;
#ifdef ENABLE_IPV6
  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
    struct sockaddr_in6 sa6;
#endif
  };
  union sockaddr_u *sock = (union sockaddr_u *)&sa; /* bind to this address */

  struct Curl_dns_entry *h=NULL;
  unsigned short port = data->set.localport; /* use this port number, 0 for
@@ -373,18 +377,18 @@ static CURLcode bindlocal(struct connectdata *conn,
#ifdef ENABLE_IPV6
      /* ipv6 address */
      if((af == AF_INET6) &&
         (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
        si6->sin6_family = AF_INET6;
        si6->sin6_port = htons(port);
         (Curl_inet_pton(AF_INET6, myhost, &sock->sa6.sin6_addr) > 0)) {
        sock->sa6.sin6_family = AF_INET6;
        sock->sa6.sin6_port = htons(port);
        sizeof_sa = sizeof(struct sockaddr_in6);
      }
      else
#endif
      /* ipv4 address */
      if((af == AF_INET) &&
         (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
        si4->sin_family = AF_INET;
        si4->sin_port = htons(port);
         (Curl_inet_pton(AF_INET, myhost, &sock->sa4.sin_addr) > 0)) {
        sock->sa4.sin_family = AF_INET;
        sock->sa4.sin_port = htons(port);
        sizeof_sa = sizeof(struct sockaddr_in);
      }
    }
@@ -398,21 +402,21 @@ static CURLcode bindlocal(struct connectdata *conn,
    /* no device was given, prepare sa to match af's needs */
#ifdef ENABLE_IPV6
    if(af == AF_INET6) {
      si6->sin6_family = AF_INET6;
      si6->sin6_port = htons(port);
      sock->sa6.sin6_family = AF_INET6;
      sock->sa6.sin6_port = htons(port);
      sizeof_sa = sizeof(struct sockaddr_in6);
    }
    else
#endif
    if(af == AF_INET) {
      si4->sin_family = AF_INET;
      si4->sin_port = htons(port);
      sock->sa4.sin_family = AF_INET;
      sock->sa4.sin_port = htons(port);
      sizeof_sa = sizeof(struct sockaddr_in);
    }
  }

  for(;;) {
    if(bind(sockfd, sock, sizeof_sa) >= 0) {
    if(bind(sockfd, &sock->sa, sizeof_sa) >= 0) {
      /* we succeeded to bind */
      struct Curl_sockaddr_storage add;
      curl_socklen_t size = sizeof(add);
@@ -432,11 +436,11 @@ static CURLcode bindlocal(struct connectdata *conn,
      infof(data, "Bind to local port %hu failed, trying next\n", port);
      port++; /* try next port */
      /* We re-use/clobber the port variable here below */
      if(sock->sa_family == AF_INET)
        si4->sin_port = ntohs(port);
      if(sock->sa.sa_family == AF_INET)
        sock->sa4.sin_port = ntohs(port);
#ifdef ENABLE_IPV6
      else
        si6->sin6_port = ntohs(port);
        sock->sa6.sin6_port = ntohs(port);
#endif
    }
    else
+28 −22
Original line number Diff line number Diff line
@@ -955,14 +955,18 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
  char myhost[256] = "";

  struct Curl_sockaddr_storage ss;
  union sockaddr_u {
    struct sockaddr sa;
    struct sockaddr_in sa4;
#ifdef ENABLE_IPV6
    struct sockaddr_in6 sa6;
#endif
  };
  union sockaddr_u *sock = (union sockaddr_u *)&ss;

  Curl_addrinfo *res, *ai;
  curl_socklen_t sslen;
  char hbuf[NI_MAXHOST];
  struct sockaddr *sa=(struct sockaddr *)&ss;
  struct sockaddr_in * const sa4 = (void *)sa;
#ifdef ENABLE_IPV6
  struct sockaddr_in6 * const sa6 = (void *)sa;
#endif
  char tmp[1024];
  static const char mode[][5] = { "EPRT", "PORT" };
  int rc;
@@ -1017,7 +1021,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
    else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
        /* either ipv6 or (ipv4|domain|interface):port(-range) */
#ifdef ENABLE_IPV6
      if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
      if(Curl_inet_pton(AF_INET6, string_ftpport, &sock->sa6) == 1) {
        /* ipv6 */
        port_min = port_max = 0;
        strcpy(addr, string_ftpport);
@@ -1073,20 +1077,22 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
       the IP from the control connection */

    sslen = sizeof(ss);
    if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
    if(getsockname(conn->sock[FIRSTSOCKET], &sock->sa, &sslen)) {
      failf(data, "getsockname() failed: %s",
          Curl_strerror(conn, SOCKERRNO) );
      Curl_safefree(addr);
      return CURLE_FTP_PORT_FAILED;
    }
    switch(sa->sa_family) {
    switch(sock->sa.sa_family) {
#ifdef ENABLE_IPV6
    case AF_INET6:
      Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
      Curl_inet_ntop(sock->sa.sa_family, &sock->sa6.sin6_addr, hbuf,
                     sizeof(hbuf));
      break;
#endif
    default:
      Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
      Curl_inet_ntop(sock->sa.sa_family, &sock->sa4.sin_addr, hbuf,
                     sizeof(hbuf));
      break;
    }
    host = hbuf; /* use this host name */
@@ -1134,18 +1140,18 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,

  /* step 3, bind to a suitable local address */

  memcpy(sa, ai->ai_addr, ai->ai_addrlen);
  memcpy(&sock->sa, ai->ai_addr, ai->ai_addrlen);
  sslen = ai->ai_addrlen;

  for(port = port_min; port <= port_max;) {
    if(sa->sa_family == AF_INET)
      sa4->sin_port = htons(port);
    if(sock->sa.sa_family == AF_INET)
      sock->sa4.sin_port = htons(port);
#ifdef ENABLE_IPV6
    else
      sa6->sin6_port = htons(port);
      sock->sa6.sin6_port = htons(port);
#endif
    /* Try binding the given address. */
    if(bind(portsock, sa, sslen) ) {
    if(bind(portsock, &sock->sa, sslen) ) {
      /* It failed. */
      error = SOCKERRNO;
      if(possibly_non_local && (error == EADDRNOTAVAIL)) {
@@ -1157,7 +1163,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
              Curl_strerror(conn, error) );

        sslen = sizeof(ss);
        if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
        if(getsockname(conn->sock[FIRSTSOCKET], &sock->sa, &sslen)) {
          failf(data, "getsockname() failed: %s",
                Curl_strerror(conn, SOCKERRNO) );
          Curl_closesocket(conn, portsock);
@@ -1190,7 +1196,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
  /* get the name again after the bind() so that we can extract the
     port number it uses now */
  sslen = sizeof(ss);
  if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
  if(getsockname(portsock, (struct sockaddr *)&sock->sa, &sslen)) {
    failf(data, "getsockname() failed: %s",
          Curl_strerror(conn, SOCKERRNO) );
    Curl_closesocket(conn, portsock);
@@ -1224,17 +1230,17 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
      /* if disabled, goto next */
      continue;

    if((PORT == fcmd) && sa->sa_family != AF_INET)
    if((PORT == fcmd) && sock->sa.sa_family != AF_INET)
      /* PORT is ipv4 only */
      continue;

    switch (sa->sa_family) {
    switch (sock->sa.sa_family) {
    case AF_INET:
      port = ntohs(sa4->sin_port);
      port = ntohs(sock->sa4.sin_port);
      break;
#ifdef ENABLE_IPV6
    case AF_INET6:
      port = ntohs(sa6->sin6_port);
      port = ntohs(sock->sa6.sin6_port);
      break;
#endif
    default:
@@ -1251,7 +1257,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
       */

      result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
                             sa->sa_family == AF_INET?1:2,
                             sock->sa.sa_family == AF_INET?1:2,
                             myhost, port);
      if(result) {
        failf(data, "Failure sending EPRT command: %s",