Re: tinytds based on freetds crashing
Krzysztof Chodak <[email protected]>
| Newsgroups | gmane.comp.db.tds.freetds |
|---|---|
| Message-ID | <CAMiSJ3qo_6Rwb3uL5PpXqb1Om-fH22_MvV7h1QM0KazvT30FJw@mail.gmail.com> |
Seems you are right: I have made a test by sending the same query with microsoft tools and wireshark reports malformed packet as well so freetds is as good as microsoft here (or the other way round) :) I also found two wireshark TDS bug entries so indeed it was not the best (however very handy) tool to use. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1219 https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=3098 Best regards, Krzysztof Chodak On Thu, Apr 5, 2012 at 16:23, Frediano Ziglio <[email protected]> wrote: > Oh, don't mind, wireshark are not so updated. > Server reply to previous request, just closed connection after latest > request. > Last request however is correct (language token are very hard to > malform as it's the easier one and more used) > It seems relate to some timeout. Router or other stuff could be. Or > perhaps keepalive is not set correctly by our library. It seems that > server sent only a keepalive. > > Frediano > > Il 05 aprile 2012 12:07, Krzysztof Chodak <[email protected]> > ha scritto: > > That is why I am still saying it. > > [image: Inline image 1] > > My first trace was on wire using wireshark and I saw repetitive info like > > above. > > > > On Thu, Apr 5, 2012 at 12:58, Frediano Ziglio <[email protected]> > wrote: > > > >> Why you keep saying that server report malformed packets ?? > >> Server just drop connection without any notice to client so there is > >> nothing wrong in capture. > >> > >> Frediano > >> > >> Il 05 aprile 2012 07:32, Krzysztof Chodak <[email protected]> > >> ha scritto: > >> > Thanks you James for fruitful analysis. > >> > (error message when posting zip was: > >> > "Google tried to deliver your message, but it was rejected by the > >> > recipient domain. We recommend contacting the other email provider for > >> > further information about the cause of this error. The error that the > >> > other server returned was: 550 550 5.7.1 illegal attachment type > >> > (state 18)." > >> > As it was 335K it was over the limit) > >> > Thank you Ken for ticketing and Frediano for a fix. > >> > > >> > I would like to catch some more of your attention and get back to my > >> > first post and probably the core source of the > >> > problem. Why server is dropping the connection? James - would you be > >> > so kind to have a look at packets dump I initially posted (captured by > >> > wireshark, > >> > https://docs.google.com/open?id=0B8Pbr6Jr1eaCa1R0NnVfdnpUb1M4a0pVVGl3WEZTZw > >> ) > >> > and try to check why server is reporting malformed TDS packets? I > >> > could also try to help but I would need to know where TDS 7.1 protocol > >> > documentation resides? > >> > > >> > On Thu, Apr 5, 2012 at 08:18, Frediano Ziglio <[email protected]> > >> wrote: > >> >> Il giorno 04/apr/2012, alle ore 22:18, "James K. Lowden" < > >> [email protected]> ha scritto: > >> >> > >> >>> On Wed, 4 Apr 2012 13:00:05 +0200 > >> >>> Krzysztof Chodak <[email protected]> wrote: > >> >>> > >> >>>>> Here it is: TDSDUMP log with a (ruby/tinytds/freetds) crash at the > >> >>>>> end > >> >>>> > >> >>>> list does not like zip attachments so file is placed here: > >> >>>> > >> > https://docs.google.com/open?id=0B8Pbr6Jr1eaCZnFCUDk3LWxTYXVncFpCaUdfdjhIdw > >> >>> > >> >>> (What message did you get posting a zip file? It should be > >> >>> permitted provided it's under 75 KB.) > >> >>> > >> >>> The TDSDUMP log clarifies several points. > >> >>> > >> >>> FreeTDS 0.91 > >> >>> TDS 7.1 > >> >>> Windows (log file is on C: drive) > >> >>> client charset is UTF-8 (unusual but OK) > >> >>> > >> >>> The trouble starts when the server disconnects unexpectedly. It > ends > >> >>> when unbounded recursion caused by the application's error handler > >> >>> consumes the stack and crashes the process. > >> >>> > >> >>> Why the server disconnected isn't clear or even certain. All that > we > >> >>> know is that the last write returned "Connection reset by peer", > which > >> >>> normally indicates the connection was closed by the remote. > >> >>> > >> >>> The last packet sent is on line 81590 of the log file > >> >>> > >> >>> SELECT TOP (1) [users].* FROM [users] > >> >>> WHERE [users].[login] = N''bradoscb'' > >> >>> > >> >>> Immediately beneath the dumped packet we see > >> >>> > >> >>> net.c:667:send(2) failed: 10054 > >> >>> (WSAECONNRESET: Connection reset by peer.) > >> >>> > >> >>> which tells us the library detected the OS error. Then > >> >>> > >> >>> util.c:331:tdserror(03a04588, 03fe49b0, 20006, 10054) > >> >>> dblib.c:7929:dbperror(03d32008, 20006, 10054) > >> >>> dblib.c:7981:20006: "Write to the server failed" > >> >>> > >> >>> per normal, then > >> >>> > >> >>> dblib.c:5780:dbgetuserdata(03d32008) > >> >>> dblib.c:5780:dbgetuserdata(03d32008) > >> >>> dblib.c:4880:dbdead(03d32008) [alive] > >> >>> > >> >>> wrong. A disconnected session is anything but alive. > >> >>> > >> >>> dblib.c:4639:dbsqlok(03d32008) > >> >>> dblib.c:4669:dbsqlok() not done, calling tds_process_tokens() > >> >>> > >> >>> db-lib still thinks the session is up ... > >> >>> > >> >>> token.c:540:tds_process_tokens(03fe49b0, 00226220, 0022621c, 0x6914) > >> >>> util.c:156:Changed query state from PENDING to READING > >> >>> util.c:331:tdserror(03a04588, 03fe49b0, 20004, 10054) > >> >>> dblib.c:7929:dbperror(03d32008, 20004, 10054) > >> >>> dblib.c:7981:20004: "Read from the server failed" > >> >>> > >> >>> but the read failed ... > >> >>> > >> >>> dblib.c:5780:dbgetuserdata(03d32008) > >> >>> dblib.c:5780:dbgetuserdata(03d32008) > >> >>> dblib.c:4880:dbdead(03d32008) [alive] > >> >>> dblib.c:4639:dbsqlok(03d32008) > >> >>> dblib.c:4669:dbsqlok() not done, calling tds_process_tokens() > >> >>> > >> >>> and we enter an infinite loop. > >> >>> > >> >>> Analysis > >> >>> --------- > >> >>> > >> >>> Windows returns a valid error code WSAECONNRESET. This is reported > to > >> >>> the log in tds/net.c:tds_goodwrite() on line 667. That logic closes > >> >>> the socket and returns -1 to tds_write_packet(). > >> >>> > >> >>> How did we get there? The log shows > >> >>> > >> >>> dblib.c:6862:dbsqlsend(03d32008) > >> >>> write.c:168:tds_put_string wrote 194 bytes > >> >>> > >> >>> tds_put_string() calls > >> >>> tds_put_n() calls > >> >>> tds_write_packet > >> >>> > >> >>> tds_write_packet() returrns TDS_FAIL to tds_put_n() > >> >>> > >> >>> which discards the return code. :-( > >> >>> > >> >>> Propogating the error code is not the only way error information is > >> >>> provided to db-lib from libtds. tds_goodwrite() also calls > tdserror > >> >>> (), which calls the client's error handler. We see that in the log, > >> too > >> >>> > >> >>> util.c:331:tdserror(03a04588, 03fe49b0, 20006, 10054) > >> >>> dblib.c:7929:dbperror(03d32008, 20006, 10054) > >> >>> dblib.c:7981:20006: "Write to the server failed" > >> >>> > >> >>> What we do *not* see in the log is the product of the next line in > >> >>> tdserror() > >> >>> > >> >>> tdsdump_log(TDS_DBG_FUNC, > >> >>> "tdserror: client library returned %s(%d)\n", retname(rc), rc); > >> >>> > >> >>> The missing message in the log indicates the error handler is > Charlie > >> on > >> >>> the MTA: it Never Returned. > >> >>> > >> >>> It would appear -- whether by design or not -- that the > >> >>> client-installed error handler makes db-lib calls, in particular > >> >>> dbsqlok(). Don't do that. It engenders infinite recursion just > >> >>> as evinced by the log: > >> >>> > >> >>> dblib.c:4669:dbsqlok() not done, calling tds_process_tokens() > >> >>> token.c:540:tds_process_tokens(03fe49b0, 00226220, 0022621c, 0x6914) > >> >>> util.c:331:tdserror(03a04588, 03fe49b0, 20004, 10054) > >> >>> dblib.c:7929:dbperror(03d32008, 20004, 10054) > >> >>> dblib.c:7981:20004: "Read from the server failed" > >> >>> # no tdserror message here > >> >>> # to indicate the handler's return code > >> >>> ... > >> >>> dblib.c:4639:dbsqlok(03d32008) # from within handler > >> >>> dblib.c:4669:dbsqlok() not done, calling tds_process_tokens() > >> >>> > >> >>> (It looks like an infinite loop, but it's infinite recursion. > >> >>> Computationally equivalent constructs, just one is more familar to C > >> >>> programmers than the other.) > >> >>> > >> >>> Incidentally, this would also explain why dbdead() reports > "[active]". > >> >>> In tds_goodread(), the socket isn't closed until after tdserror() > >> >>> returns. Because the socket is still open within the recursion, all > >> >>> calls to dbdead() continue to find the socket open and it reports > >> >>> "active". > >> >>> > >> >> > >> >> Fixed in both 0.91 and master! > >> >> > >> >>> Give your error handler a nickle and let it return. Otherwise it > will > >> >>> eventually devour the stack along with your process. > >> >>> > >> >>> --jkl > >> >>> > >> >> > >> >> Frediano > >> >> > >> _______________________________________________ > >> FreeTDS mailing list > >> [email protected] > >> http://lists.ibiblio.org/mailman/listinfo/freetds > >> > > > > _______________________________________________ > > FreeTDS mailing list > > [email protected] > > http://lists.ibiblio.org/mailman/listinfo/freetds > > > _______________________________________________ > FreeTDS mailing list > [email protected] > http://lists.ibiblio.org/mailman/listinfo/freetds >