Description
Environment
Operating System
Intel Mac, x86_64
ProductName: macOS
ProductVersion: 13.4.1
ProductVersionExtra: (c)
BuildVersion: 22F770820d
TinyTDS Version and Information
[TinyTds][v2.1.5][tsql]: /usr/local/bin/tsql
Compile-time settings (established with the "configure" script)
Version: freetds v1.3.20
freetds.conf directory: /usr/local/etc
MS db-lib source compatibility: no
Sybase binary compatibility: yes
Thread safety: yes
iconv library: yes
TDS version: 7.3
iODBC: no
unixodbc: yes
SSPI "trusted" logins: no
Kerberos: yes
OpenSSL: yes
GnuTLS: no
MARS: yes
I'm actually pointing at a post-2.1.5 commit on tiny_tds
: 23ed1e4
, where #527 was merged.
FreeTDS Version
freetds: 1.3.20
SQL Server
Running against 2017 for Linux in a Docker container via Docker Desktop for Mac. SQL Server Authentication.
Description
In the course of trying to upgrade an application from Ruby 2.5/Rails 5.2.x to Ruby 3.1/Rails 6.1.x, I have noticed a significant increase in automated test failures (we're using rspec-rails
). These failures seem take a couple of forms:
1. An EXC_BAD_ACCESS (SIGABRT)
.
Terminal output:
<big long memory region dump trimmed>
Abort trap: 6
OS Crash Report:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x7ff8092e61f2 __pthread_kill + 10
1 libsystem_pthread.dylib 0x7ff80931dee6 pthread_kill + 263
2 libsystem_c.dylib 0x7ff809244b45 abort + 123
3 libruby.3.1.dylib 0x106e845e9 die + 9
4 libruby.3.1.dylib 0x106e84810 rb_bug_for_fatal_signal + 544
5 libruby.3.1.dylib 0x106fb475b sigsegv + 91
6 libsystem_platform.dylib 0x7ff80934b5ed _sigtramp + 29
7 ??? 0x0 ???
8 tiny_tds.bundle 0x10c34543e nogvl_dbsqlok + 88 (result.c:130) [inlined]
9 tiny_tds.bundle 0x10c34543e rb_tinytds_result_ok_helper + 109 (result.c:179) [inlined]
10 tiny_tds.bundle 0x10c34543e rb_tinytds_result_exec_helper + 126 (result.c:185)
11 tiny_tds.bundle 0x10c344528 rb_tinytds_result_do + 56 (result.c:528)
12 libruby.3.1.dylib 0x10704864d vm_call_cfunc_with_frame + 349
<snip>
Thread 1:
0 libsystem_kernel.dylib 0x7ff8092e629e poll + 10
1 libruby.3.1.dylib 0x1070004ac timer_pthread_fn + 140
2 libsystem_pthread.dylib 0x7ff80931e1d3 _pthread_start + 125
3 libsystem_pthread.dylib 0x7ff809319bd3 thread_start + 15
Thread 2:: connection_pool.rb:323
0 libsystem_kernel.dylib 0x7ff8092e629e poll + 10
1 libruby.3.1.dylib 0x106ff4acd rb_sigwait_sleep + 557
2 libruby.3.1.dylib 0x106ff5fb4 native_sleep + 500
3 libruby.3.1.dylib 0x106ff6b9b sleep_hrtime + 331
4 libruby.3.1.dylib 0x106f5f475 rb_f_sleep + 85
5 libruby.3.1.dylib 0x10704864d vm_call_cfunc_with_frame + 349
<snip>
Thread 3:: worker-1
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x106fffde5 gvl_acquire_common + 309
3 libruby.3.1.dylib 0x106ff7648 blocking_region_end + 216
4 libruby.3.1.dylib 0x106ff716f rb_nogvl + 175
5 tiny_tds.bundle 0x10c345433 nogvl_dbsqlok + 77 (result.c:129) [inlined]
6 tiny_tds.bundle 0x10c345433 rb_tinytds_result_ok_helper + 98 (result.c:179) [inlined]
7 tiny_tds.bundle 0x10c345433 rb_tinytds_result_exec_helper + 115 (result.c:185)
8 tiny_tds.bundle 0x10c344528 rb_tinytds_result_do + 56 (result.c:528)
9 libruby.3.1.dylib 0x10704864d vm_call_cfunc_with_frame + 349
<snip>
I'm pretty sure this was a simple unit test, given the running threads in the Ruby process. One thing that immediately catches my eye is that there appear to be two threads in the TinyTDS C code at the same time. I'm also curious about the nogvl_*
functions, but only b/c of their name. I'm not sure I fully understand their purpose.
2. An EXC_CRASH (SIGABRT)
.
Terminal output:
/Users/clintmiller/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activerecord-sqlserver-adapter-6.1.3.0/lib/active_record/connection_adapters/sqlserver/database_statements.rb:463: warning: TinyTds: dbsqlsend() returned FAIL.
Assertion failed: (conn->in_net_tds == NULL), function tds_free_connection, file mem.c, line 1209.
OS Crash Report:
Thread 0:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x7ff8092e629e poll + 10
1 libsybdb.5.dylib 0x1101c3ba6 tds_select + 221
2 libsybdb.5.dylib 0x1101c8419 tds_connection_network + 110
3 libsybdb.5.dylib 0x1101c8212 tds_read_packet + 235
4 libsybdb.5.dylib 0x1101afb94 tds_get_byte + 25
5 libsybdb.5.dylib 0x1101a8acf tds_process_tokens + 183
6 libsybdb.5.dylib 0x1101953e5 dbsqlok + 175
7 libruby.3.1.dylib 0x10ad8b158 rb_nogvl + 152
8 tiny_tds.bundle 0x11011c433 nogvl_dbsqlok + 77 (result.c:129) [inlined]
9 tiny_tds.bundle 0x11011c433 rb_tinytds_result_ok_helper + 98 (result.c:179) [inlined]
10 tiny_tds.bundle 0x11011c433 rb_tinytds_result_exec_helper + 115 (result.c:185)
11 tiny_tds.bundle 0x11011b528 rb_tinytds_result_do + 56 (result.c:528)
12 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 1:
0 libsystem_kernel.dylib 0x7ff8092e629e poll + 10
1 libruby.3.1.dylib 0x10ad944ac timer_pthread_fn + 140
2 libsystem_pthread.dylib 0x7ff80931e1d3 _pthread_start + 125
3 libsystem_pthread.dylib 0x7ff809319bd3 thread_start + 15
Thread 2:: connection_pool.rb:323
0 libsystem_kernel.dylib 0x7ff8092e629e poll + 10
1 libruby.3.1.dylib 0x10ad88acd rb_sigwait_sleep + 557
2 libruby.3.1.dylib 0x10ad89fb4 native_sleep + 500
3 libruby.3.1.dylib 0x10ad8ab9b sleep_hrtime + 331
4 libruby.3.1.dylib 0x10acf3475 rb_f_sleep + 85
5 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 3:: Timeout stdlib thread
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92c06 native_cond_sleep + 502
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad8a8b9 sleep_forever + 457
5 libruby.3.1.dylib 0x10ad95c17 queue_sleep + 39
6 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
7 libruby.3.1.dylib 0x10ad95b62 queue_do_pop + 226
8 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 4:: server.rb:76
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92c06 native_cond_sleep + 502
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad94276 thread_join_sleep + 230
5 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
6 libruby.3.1.dylib 0x10ad940bd thread_join + 157
7 libruby.3.1.dylib 0x10ad90d6e thread_join_m + 238
8 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 5:: puma reactor
0 libsystem_kernel.dylib 0x7ff8092e41ee kevent + 10
1 nio4r_ext.bundle 0x1191c6c69 kqueue_poll + 281 (ev_kqueue.c:102)
2 nio4r_ext.bundle 0x1191c3f55 ev_backend_poll + 21 (ev.c:4026)
3 libruby.3.1.dylib 0x10ad8b158 rb_nogvl + 152
4 nio4r_ext.bundle 0x1191c33b0 ev_run + 768 (ev.c:4216)
5 nio4r_ext.bundle 0x1191c902a NIO_Selector_run + 86 (selector.c:476) [inlined]
6 nio4r_ext.bundle 0x1191c902a NIO_Selector_select_synchronized + 186 (selector.c:431)
7 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
8 nio4r_ext.bundle 0x1191c8775 NIO_Selector_select + 101 (selector.c:409)
9 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 6:: puma threadpool reaper
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92bd7 native_cond_sleep + 455
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad8ab9b sleep_hrtime + 331
5 libruby.3.1.dylib 0x10acf3475 rb_f_sleep + 85
6 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 7:: puma threadpool trimmer
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92bd7 native_cond_sleep + 455
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad8ab9b sleep_hrtime + 331
5 libruby.3.1.dylib 0x10acf3475 rb_f_sleep + 85
6 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 8:: puma server
0 libsystem_kernel.dylib 0x7ff8092e8282 __select + 10
1 libruby.3.1.dylib 0x10ad8d8b9 do_select + 425
2 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
3 libruby.3.1.dylib 0x10ad8d5ca rb_thread_fd_select + 1178
4 libruby.3.1.dylib 0x10ac6b5dd select_call + 1293
5 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
6 libruby.3.1.dylib 0x10ac5eb6c rb_f_select + 220
7 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 9:: worker.rb:96
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92c06 native_cond_sleep + 502
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad8a8b9 sleep_forever + 457
5 libruby.3.1.dylib 0x10ad95c17 queue_sleep + 39
6 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
7 libruby.3.1.dylib 0x10ad95b62 queue_do_pop + 226
8 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 10:: worker-1
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92c06 native_cond_sleep + 502
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad8a8b9 sleep_forever + 457
5 libruby.3.1.dylib 0x10ad95c17 queue_sleep + 39
6 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
7 libruby.3.1.dylib 0x10ad95b62 queue_do_pop + 226
8 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 11:: worker-2
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92c06 native_cond_sleep + 502
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad8a8b9 sleep_forever + 457
5 libruby.3.1.dylib 0x10ad95c17 queue_sleep + 39
6 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
7 libruby.3.1.dylib 0x10ad95b62 queue_do_pop + 226
8 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 12:: worker-1
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92c06 native_cond_sleep + 502
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad8a8b9 sleep_forever + 457
5 libruby.3.1.dylib 0x10ad95c17 queue_sleep + 39
6 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
7 libruby.3.1.dylib 0x10ad95b62 queue_do_pop + 226
8 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 13:: worker-1
0 libsystem_kernel.dylib 0x7ff8092e20ee __psynch_cvwait + 10
1 libsystem_pthread.dylib 0x7ff80931e758 _pthread_cond_wait + 1242
2 libruby.3.1.dylib 0x10ad92c06 native_cond_sleep + 502
3 libruby.3.1.dylib 0x10ad89e30 native_sleep + 112
4 libruby.3.1.dylib 0x10ad8a8b9 sleep_forever + 457
5 libruby.3.1.dylib 0x10ad95c17 queue_sleep + 39
6 libruby.3.1.dylib 0x10ac24ece rb_ensure + 350
7 libruby.3.1.dylib 0x10ad95b62 queue_do_pop + 226
8 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Thread 14 Crashed:: worker-2
0 libsystem_kernel.dylib 0x7ff8092e61f2 __pthread_kill + 10
1 libsystem_pthread.dylib 0x7ff80931dee6 pthread_kill + 263
2 libsystem_c.dylib 0x7ff809244b45 abort + 123
3 libsystem_c.dylib 0x7ff809243e5e __assert_rtn + 314
4 libsybdb.5.dylib 0x1101ce32f tds_free_connection.cold.1 + 35
5 libsybdb.5.dylib 0x1101a6509 tds_free_connection + 368
6 libsybdb.5.dylib 0x1101a671f tds_free_socket + 215
7 libsybdb.5.dylib 0x110194a27 dbclose + 239
8 tiny_tds.bundle 0x1101197af rb_tinytds_close + 63 (client.c:266)
9 libruby.3.1.dylib 0x10addc64d vm_call_cfunc_with_frame + 349
<snip>
Obviously, this case with more threads is a system/integration test that started a webserver.
Other Notes
It's interesting to note, that the application boots and runs in my development environment w/o any issues. I'm not sure how it will do with a production workload given the crashes I'm seeing in our test suite.
Next Steps
Making a minimal reproduction test-case would be useful, but I'm not quite sure where to start. On Ruby 2.5/Rails 5.2, our test suite rarely (if ever), crashed in this manner. Is there any other additional information I can provide or debug builds of TinyTDS I could use to reveal more helpful information?