[freetds] infinite loop in dbcancel

Joshua Lang joshua.h.lang at gmail.com
Wed Mar 16 15:23:48 EDT 2016

FreeTDS version: 0.95.79
OS: Debian 7.9 (wheezy)

Here's the scenario:

Application has a long-running (pooled) connection to a database.
The database is restarted.
The application then consumes as much of one CPU as it can.

Unfortunately I have yet to find a simple repro for this issue locally, but
here is what I've found debugging the live application:

strace shows a constant stream of the following call:

poll([{fd=150, events=POLLOUT}, {fd=98, events=POLLIN}], 2, 1000) = 1
([{fd=150, revents=POLLOUT|POLLERR|POLLHUP}])

The (relevant) stack trace from gdb:

(gdb) bt
#0  0x00007f1fae4d16b3 in *__GI___poll (fds=<optimized out>,
nfds=<optimized out>, timeout=1000)
    at ../sysdeps/unix/sysv/linux/poll.c:87
#1  0x00007f1fa50ff883 in tds_select () from
#2  0x00007f1fa50ffe70 in tds_goodwrite () from
#3  0x00007f1fa5100062 in tds_connection_write () from
#4  0x00007f1fa51046f7 in tds_put_cancel () from
#5  0x00007f1fa50f574b in tds_send_cancel () from
#6  0x00007f1fa50c3560 in dbcancel () from

I've stepped through this with gdb and here are the results:
1. tds_select is called, returning -1 (verified in gdb)
2. errno returns to 11 (EAGAIN) (verified in gdb, by stepping through the
c-lib function call to return it)
3. TDSSOCK_WOULDBLOCK therefore causes the loop to repeat:
https://github.com/FreeTDS/freetds/blob/master/src/tds/net.c#L803 and we're
back to step 1 and an infinite loop

The TDSSOCK_WOULDBLOCK seems strange to me, and the comment after it
agrees. I wouldn't expect the socket read to block if the poll call just
indicated it was ready for read.

More information about the FreeTDS mailing list