------------------------------------------------------------ revno: 13811 revision-id: squid3@treenet.co.nz-20150426164802-xhlgkspab2qo0vhe parent: squid3@treenet.co.nz-20150426164536-2ok6tyj5k28uoslm fixes bug: http://bugs.squid-cache.org/show_bug.cgi?id=4234 author: Alex Dowad committer: Amos Jeffries branch nick: 3.5 timestamp: Sun 2015-04-26 09:48:02 -0700 message: Bug 4234: comm_connect_addr uses errno incorrectly comm_connect_addr() uses errno to determine whether library calls like connect() are successful. Its callers also use errno for extra information on the cause of any problem. However, after calling library functions like connect(), comm_connect_addr() calls other library functions which can overwrite errno. As the errno manpage explains, "a function that succeeds is allowed to change errno". So even when nothing is wrong, comm_connect_addr() may return an error flag if libc sets errno. And when something *is* wrong, incorrect error information may be returned to the caller because errno was overwritten with a different code. Correct this by using our own error code variable which is set only when a library call fails. To avoid breaking callers, set errno before returning. ------------------------------------------------------------ # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: squid3@treenet.co.nz-20150426164802-xhlgkspab2qo0vhe # target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5 # testament_sha1: 4c8d0babcc5f8d1080f1b1f722cbe71b822c6b77 # timestamp: 2015-04-26 16:48:41 +0000 # source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5 # base_revision_id: squid3@treenet.co.nz-20150426164536-\ # 2ok6tyj5k28uoslm # # Begin patch === modified file 'src/comm.cc' --- src/comm.cc 2015-04-23 11:44:47 +0000 +++ src/comm.cc 2015-04-26 16:48:02 +0000 @@ -581,6 +581,11 @@ return commSetConnTimeout(conn, -1, nil); } +/** + * Connect socket FD to given remote address. + * If return value is an error flag (COMM_ERROR, ERR_CONNECT, ERR_PROTOCOL, etc.), + * then error code will also be returned in errno. + */ int comm_connect_addr(int sock, const Ip::Address &address) { @@ -621,7 +626,7 @@ address.getAddrInfo(AI, F->sock_family); /* Establish connection. */ - errno = 0; + int xerrno = 0; if (!F->flags.called_connect) { F->flags.called_connect = true; @@ -633,10 +638,8 @@ // Async calls development will fix this. if (x == 0) { x = -1; - errno = EINPROGRESS; - } - - if (x < 0) { + xerrno = EINPROGRESS; + } else if (x < 0) { debugs(5,5, "comm_connect_addr: sock=" << sock << ", addrinfo( " << " flags=" << AI->ai_flags << ", family=" << AI->ai_family << @@ -645,30 +648,28 @@ ", &addr=" << AI->ai_addr << ", addrlen=" << AI->ai_addrlen << " )" ); - debugs(5, 9, "connect FD " << sock << ": (" << x << ") " << xstrerror()); + debugs(5, 9, "connect FD " << sock << ": (" << x << ") " << xstrerr(xerrno)); debugs(14,9, "connecting to: " << address ); } + } else { + errno = 0; #if _SQUID_NEWSOS6_ /* Makoto MATSUSHITA */ - - connect(sock, AI->ai_addr, AI->ai_addrlen); - - if (errno == EINVAL) { + if (connect(sock, AI->ai_addr, AI->ai_addrlen) < 0) + xerrno = errno; + + if (xerrno == EINVAL) { errlen = sizeof(err); x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen); - if (x >= 0) - errno = x; + xerrno = x; } - #else errlen = sizeof(err); - x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen); - if (x == 0) - errno = err; + xerrno = err; #if _SQUID_SOLARIS_ /* @@ -677,23 +678,24 @@ * connect and just returns EPIPE. Create a fake * error message for connect. -- fenner@parc.xerox.com */ - if (x < 0 && errno == EPIPE) - errno = ENOTCONN; - -#endif -#endif - + if (x < 0 && xerrno == EPIPE) + xerrno = ENOTCONN; + else + xerrno = errno; +#endif +#endif } Ip::Address::FreeAddr(AI); PROF_stop(comm_connect_addr); - if (errno == 0 || errno == EISCONN) + errno = xerrno; + if (xerrno == 0 || xerrno == EISCONN) status = Comm::OK; - else if (ignoreErrno(errno)) + else if (ignoreErrno(xerrno)) status = Comm::INPROGRESS; - else if (errno == EAFNOSUPPORT || errno == EINVAL) + else if (xerrno == EAFNOSUPPORT || xerrno == EINVAL) return Comm::ERR_PROTOCOL; else return Comm::COMM_ERROR; @@ -708,6 +710,7 @@ debugs(5, DBG_DATA, "comm_connect_addr: FD " << sock << " connection pending"); } + errno = xerrno; return status; }