Project

General

Profile

Actions

Bug #13176

closed

Segfault during exception raising because rb_thread_t.errinfo is set to IMEMO object

Added by jeremyevans0 (Jeremy Evans) about 7 years ago. Updated about 7 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-openbsd]
[ruby-core:79371]

Description

There appears to be a problem in ruby 2.4.0 and ruby 2.5.0dev (ruby 2.5.0dev (2017-01-31 trunk 57485) [x86_64-openbsd]) where rb_thread_t.errinfo gets set to an IMEMO object, and later used as the cause of an exception, which blows up when the exception is raised. First, the gdb backtrace:

Program received signal SIGSEGV, Segmentation fault at 0x00000000000018
0x000016413f931995 in iv_index_tbl_make (obj=24471839573840) at variable.c:1324
#1  0x000016413f931a8c in generic_ivar_set (obj=24471839573840, id=7585, val=8) at variable.c:1353
#2  0x000016413f931e48 in rb_ivar_set (obj=24471839573840, id=7585, val=8) at variable.c:1414
#3  0x000016413f7dd5b0 in exc_setup_cause (exc=24471839573760, cause=24471839573840) at eval.c:461
#4  0x000016413f7dd6e0 in setup_exception (th=0x1642049f9000, tag=6, mesg=24471839573760, cause=52) at eval.c:497
#5  0x000016413f7dddf6 in rb_longjmp (tag=6, mesg=24471839573760, cause=52) at eval.c:601
#6  0x000016413f7dde4d in rb_exc_raise (mesg=Could not find the frame base for "rb_exc_raise".) at eval.c:614
#7  0x00001641186c619d in spg__flush_results (rconn=24469332626760) at sequel_pg.c:1004
#8  0x000016413f7deb1e in rb_ensure (b_proc=0x1641186c5d3d <spg__yield_each_row>, data1=24471839574280, e_proc=0x1641186c60d1 <spg__flush_results>, data2=24469332626760) at eval.c:931
#9  0x00001641186c61e9 in spg_yield_each_row (self=24471839576040, rconn=24469332626760) at sequel_pg.c:1013
#10 0x000016413f93add6 in call_cfunc_1 (func=0x1641186c61a3 <spg_yield_each_row>, recv=24471839576040, argc=1, argv=0x16416eb3e890) at vm_insnhelper.c:1585
#11 0x000016413f93b8cd in vm_call_cfunc_with_frame (th=0x1642049f9000, reg_cfp=0x16416ec3d670, calling=0x7f7ffffd8190, ci=0x1641e10f1aa0, cc=0x16411eb2d980) at vm_insnhelper.c:1752
#12 0x000016413f93bb14 in vm_call_cfunc (th=0x1642049f9000, reg_cfp=0x16416ec3d670, calling=0x7f7ffffd8190, ci=0x1641e10f1aa0, cc=0x16411eb2d980) at vm_insnhelper.c:1847
#13 0x000016413f9416b1 in vm_exec_core (th=0x1642049f9000, initial=0) at insns.def:967
#14 0x000016413f9549f4 in vm_exec (th=0x1642049f9000) at vm.c:1712
#15 0x000016413f9528ef in invoke_bmethod (th=0x1642049f9000, iseq=0x1641bbe3cde0, self=24472494004560, captured=0x164123905c80, me=0x16413ee55bd8, type=2576941057, opt_pc=0) at vm.c:988
#16 0x000016413f952cbb in invoke_iseq_block_from_c (th=0x1642049f9000, captured=0x164123905c80, self=24472494004560, argc=0, argv=0x7f7ffffd9080, passed_block_handler=0, cref=0x0, splattable=0, is_lambda=1) at vm.c:1017
#17 0x000016413f953042 in invoke_block_from_c_unsplattable (th=0x1642049f9000, block=0x164123905c80, self=24472494004560, argc=0, argv=0x7f7ffffd9080, passed_block_handler=0, is_lambda=1) at vm.c:1086
#18 0x000016413f953120 in vm_invoke_bmethod (th=0x1642049f9000, proc=0x164123905c80, self=24472494004560, argc=0, argv=0x7f7ffffd9080, block_handler=0) at vm.c:1127
#19 0x000016413f93c3da in vm_call_bmethod_body (th=0x1642049f9000, calling=0x7f7ffffd95f0, ci=0x7f7ffffd9280, cc=0x7f7ffffd9250, argv=0x7f7ffffd9080) at vm_insnhelper.c:1875
#20 0x000016413f93c345 in vm_call_bmethod (th=0x1642049f9000, cfp=0x16416ec3da90, calling=0x7f7ffffd95f0, ci=0x7f7ffffd9280, cc=0x7f7ffffd9250) at vm_insnhelper.c:1892
#21 0x000016413f93d238 in vm_call_method_each_type (th=0x1642049f9000, cfp=0x16416ec3da90, calling=0x7f7ffffd95f0, ci=0x7f7ffffd9280, cc=0x7f7ffffd9250) at vm_insnhelper.c:2168
#22 0x000016413f93d6d4 in vm_call_method (th=0x1642049f9000, cfp=0x16416ec3da90, calling=0x7f7ffffd95f0, ci=0x7f7ffffd9280, cc=0x7f7ffffd9250) at vm_insnhelper.c:2265
#23 0x000016413f93c7de in vm_call_opt_send (th=0x1642049f9000, reg_cfp=0x16416ec3da90, calling=0x7f7ffffd95f0, orig_ci=0x16411f36cf40, orig_cc=0x164203e784a0) at vm_insnhelper.c:1961
#24 0x000016413f93d2c9 in vm_call_method_each_type (th=0x1642049f9000, cfp=0x16416ec3da90, calling=0x7f7ffffd95f0, ci=0x16411f36cf40, cc=0x164203e784a0) at vm_insnhelper.c:2179
#25 0x000016413f93d6d4 in vm_call_method (th=0x1642049f9000, cfp=0x16416ec3da90, calling=0x7f7ffffd95f0, ci=0x16411f36cf40, cc=0x164203e784a0) at vm_insnhelper.c:2265
#26 0x000016413f93d8c8 in vm_call_general (th=0x1642049f9000, reg_cfp=0x16416ec3da90, calling=0x7f7ffffd95f0, ci=0x16411f36cf40, cc=0x164203e784a0) at vm_insnhelper.c:2308
#27 0x000016413f942195 in vm_exec_core (th=0x1642049f9000, initial=0) at insns.def:1066
#28 0x000016413f9549f4 in vm_exec (th=0x1642049f9000) at vm.c:1712
#29 0x000016413f952da1 in invoke_block (th=0x1642049f9000, iseq=0x16412dd7bae8, self=24469332631680, captured=0x16416ec3dda8, cref=0x0, type=572653569, opt_pc=0) at vm.c:969
#30 0x000016413f952c80 in invoke_iseq_block_from_c (th=0x1642049f9000, captured=0x16416ec3dda8, self=24469332631680, argc=1, argv=0x7f7ffffda498, passed_block_handler=0, cref=0x0, splattable=1, is_lambda=0) at vm.c:1014
#31 0x000016413f952a94 in invoke_block_from_c_splattable (th=0x1642049f9000, block_handler=24470287015337, argc=1, argv=0x7f7ffffda498, passed_block_handler=0, cref=0x0) at vm.c:1032
#32 0x000016413f952de3 in vm_yield (th=0x1642049f9000, argc=1, argv=0x7f7ffffda498) at vm.c:1069
#33 0x000016413f94e877 in rb_yield_0 (argc=1, argv=0x7f7ffffda498) at vm_eval.c:1009
#34 0x000016413f94e850 in rb_yield_1 (val=24472494007280) at vm_eval.c:1015
#35 0x000016413f94e8aa in rb_yield (val=24472494007280) at vm_eval.c:1025
#36 0x000016413f77689a in rb_ary_each (ary=24472494006960) at array.c:1824
#37 0x000016413f93ada7 in call_cfunc_0 (func=0x16413f77682b <rb_ary_each>, recv=24472494006960, argc=0, argv=0x16416eb3e258) at vm_insnhelper.c:1579
#38 0x000016413f93b8cd in vm_call_cfunc_with_frame (th=0x1642049f9000, reg_cfp=0x16416ec3dd90, calling=0x7f7ffffda950, ci=0x16413e9fa160, cc=0x16418ddfd200) at vm_insnhelper.c:1752
#39 0x000016413f93bb14 in vm_call_cfunc (th=0x1642049f9000, reg_cfp=0x16416ec3dd90, calling=0x7f7ffffda950, ci=0x16413e9fa160, cc=0x16418ddfd200) at vm_insnhelper.c:1847
#40 0x000016413f93d043 in vm_call_method_each_type (th=0x1642049f9000, cfp=0x16416ec3dd90, calling=0x7f7ffffda950, ci=0x16413e9fa160, cc=0x16418ddfd200) at vm_insnhelper.c:2145
#41 0x000016413f93d6d4 in vm_call_method (th=0x1642049f9000, cfp=0x16416ec3dd90, calling=0x7f7ffffda950, ci=0x16413e9fa160, cc=0x16418ddfd200) at vm_insnhelper.c:2265
#42 0x000016413f93d8c8 in vm_call_general (th=0x1642049f9000, reg_cfp=0x16416ec3dd90, calling=0x7f7ffffda950, ci=0x16413e9fa160, cc=0x16418ddfd200) at vm_insnhelper.c:2308
#43 0x000016413f9416b1 in vm_exec_core (th=0x1642049f9000, initial=0) at insns.def:967
#44 0x000016413f9549f4 in vm_exec (th=0x1642049f9000) at vm.c:1712
#45 0x000016413f952da1 in invoke_block (th=0x1642049f9000, iseq=0x1641267ba7f0, self=24469584412240, captured=0x16416ec3df58, cref=0x0, type=572653569, opt_pc=0) at vm.c:969
#46 0x000016413f952c80 in invoke_iseq_block_from_c (th=0x1642049f9000, captured=0x16416ec3df58, self=24469584412240, argc=1, argv=0x7f7ffffdb7f8, passed_block_handler=0, cref=0x0, splattable=1, is_lambda=0) at vm.c:1014
#47 0x000016413f952a94 in invoke_block_from_c_splattable (th=0x1642049f9000, block_handler=24470287015769, argc=1, argv=0x7f7ffffdb7f8, passed_block_handler=0, cref=0x0) at vm.c:1032
#48 0x000016413f952de3 in vm_yield (th=0x1642049f9000, argc=1, argv=0x7f7ffffdb7f8) at vm.c:1069
#49 0x000016413f94e877 in rb_yield_0 (argc=1, argv=0x7f7ffffdb7f8) at vm_eval.c:1009
#50 0x000016413f94e850 in rb_yield_1 (val=24469332631680) at vm_eval.c:1015
#51 0x000016413f94e8aa in rb_yield (val=24469332631680) at vm_eval.c:1025
#52 0x000016413f778a56 in rb_ary_collect (ary=24472494010520) at array.c:2733
#53 0x000016413f93ada7 in call_cfunc_0 (func=0x16413f7789d2 <rb_ary_collect>, recv=24472494010520, argc=0, argv=0x16416eb3e0c0) at vm_insnhelper.c:1579
#54 0x000016413f93b8cd in vm_call_cfunc_with_frame (th=0x1642049f9000, reg_cfp=0x16416ec3df40, calling=0x7f7ffffdbcc0, ci=0x1641894147c0, cc=0x164144950aa0) at vm_insnhelper.c:1752
#55 0x000016413f93bb14 in vm_call_cfunc (th=0x1642049f9000, reg_cfp=0x16416ec3df40, calling=0x7f7ffffdbcc0, ci=0x1641894147c0, cc=0x164144950aa0) at vm_insnhelper.c:1847
#56 0x000016413f93d043 in vm_call_method_each_type (th=0x1642049f9000, cfp=0x16416ec3df40, calling=0x7f7ffffdbcc0, ci=0x1641894147c0, cc=0x164144950aa0) at vm_insnhelper.c:2145
#57 0x000016413f93d6d4 in vm_call_method (th=0x1642049f9000, cfp=0x16416ec3df40, calling=0x7f7ffffdbcc0, ci=0x1641894147c0, cc=0x164144950aa0) at vm_insnhelper.c:2265
#58 0x000016413f93d8c8 in vm_call_general (th=0x1642049f9000, reg_cfp=0x16416ec3df40, calling=0x7f7ffffdbcc0, ci=0x1641894147c0, cc=0x164144950aa0) at vm_insnhelper.c:2308
#59 0x000016413f9416b1 in vm_exec_core (th=0x1642049f9000, initial=0) at insns.def:967
#60 0x000016413f9549f4 in vm_exec (th=0x1642049f9000) at vm.c:1712
#61 0x000016413f952da1 in invoke_block (th=0x1642049f9000, iseq=0x1641701a0910, self=24469584412240, captured=0x1641c68b4100, cref=0x0, type=572653569, opt_pc=0) at vm.c:969
#62 0x000016413f952c80 in invoke_iseq_block_from_c (th=0x1642049f9000, captured=0x1641c68b4100, self=24469584412240, argc=0, argv=0x16413ee545b8, passed_block_handler=0, cref=0x0, splattable=0, is_lambda=0) at vm.c:1014
#63 0x000016413f953042 in invoke_block_from_c_unsplattable (th=0x1642049f9000, block=0x1641c68b4100, self=24469584412240, argc=0, argv=0x16413ee545b8, passed_block_handler=0, is_lambda=0) at vm.c:1086
#64 0x000016413f952f5a in vm_invoke_proc (th=0x1642049f9000, proc=0x1641c68b4100, self=24469584412240, argc=0, argv=0x16413ee545b8, passed_block_handler=0) at vm.c:1111
#65 0x000016413f9531b2 in rb_vm_invoke_proc (th=0x1642049f9000, proc=0x1641c68b4100, argc=0, argv=0x16413ee545b8, passed_block_handler=0) at vm.c:1141
#66 0x000016413f86f371 in rb_proc_call (self=24469463297920, args=24469483898280) at proc.c:847
#67 0x000016413f7dc592 in rb_call_end_proc (data=24469463297920) at eval_jump.c:13
#68 0x000016413f7dc744 in exec_end_procs_chain (procs=0x16413fc75d50, errp=0x1642049f90d8) at eval_jump.c:108
#69 0x000016413f7dc840 in rb_exec_end_proc () at eval_jump.c:125
#70 0x000016413f7dcc26 in ruby_finalize_0 () at eval.c:122
#71 0x000016413f7dcdb2 in ruby_cleanup (ex=0) at eval.c:179
#72 0x000016413f7dd1e4 in ruby_run_node (n=0x16410f990280) at eval.c:300
#73 0x0000163f0e700680 in main (argc=4, argv=0x7f7ffffdcff8) at main.c:36

Some debugging in the core dump, showing that errinfo is getting set to an IMEMO object, which is later used as the cause of an exception:

#0  0x000016413f931995 in iv_index_tbl_make (obj=24471839573840) at variable.c:1324
1324        st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(klass);
(gdb) info args
obj = 24471839573840
(gdb) print rb_type(obj)
$16 = 26  # RUBY_T_IMEMO !
(gdb) info locals
klass = 0
iv_index_tbl = (st_table *) 0x34
(gdb) up
#1  0x000016413f931a8c in generic_ivar_set (obj=24471839573840, id=7585, val=8) at variable.c:1353
1353        ivup.u.iv_index_tbl = iv_index_tbl_make(obj);
(gdb) up
#2  0x000016413f931e48 in rb_ivar_set (obj=24471839573840, id=7585, val=8) at variable.c:1414
1414            generic_ivar_set(obj, id, val);
(gdb) up
#3  0x000016413f7dd5b0 in exc_setup_cause (exc=24471839573760, cause=24471839573840) at eval.c:461
461                 rb_ivar_set(cause, id_cause, Qnil);
(gdb) up
#4  0x000016413f7dd6e0 in setup_exception (th=0x1642049f9000, tag=6, mesg=24471839573760, cause=52) at eval.c:497
497             exc_setup_cause(mesg, get_thread_errinfo(th));
(gdb) print get_thread_errinfo(th)
$17 = 24471839573840
(gdb) print th->errinfo
$18 = 24471839573840

The segfault ultimately happens because rb_obj_class on IMEMO objects is 0, and iv_index_tbl_make doesn't expect rb_obj_class to return 0.

Unfortunately, I was not able to create a minimal example showing the problem. This is the simplest reproducible example I could create, which requires PostgreSQL and the sequel, sequel_pg, and pg gems:

require 'sequel'
DB = Sequel.connect('postgres://sequel_test@localhost/sequel_test') # or similar PostgreSQL database connection string
DB.extension(:pg_streaming)
DB.stream_all_queries = true
DB.drop_table?(:items, :items2)
DB.create_table!(:items2){Integer :id, :primary_key=>true}
DB.create_table!(:items){foreign_key :id, :items2, :deferrable=>true}
DB[:items].insert(1)

This same code works (raises an exception, no segfault) from ruby 1.8.7 to 2.3. Only in ruby 2.4.0 and ruby 2.5.0dev does it segfault.

Updated by nobu (Nobuyoshi Nakada) about 7 years ago

  • Status changed from Open to Feedback

IMEMO as an exception is struct vm_throw_data, which is used by Kernel#throw.
Does sequel use throw?

diff --git a/eval.c b/eval.c
index e16d59b8bb..514413a14c 100644
--- a/eval.c
+++ b/eval.c
@@ -455,7 +455,7 @@ exc_setup_cause(VALUE exc, VALUE cause)
 	}
     }
 #endif
-    if (!NIL_P(cause) && cause != exc) {
+    if (!NIL_P(cause) && cause != exc && !RB_TYPE_P(cause, T_IMEMO)) {
 	rb_ivar_set(exc, id_cause, cause);
 	if (!rb_ivar_defined(cause, id_cause)) {
 	    rb_ivar_set(cause, id_cause, Qnil);

Updated by jeremyevans0 (Jeremy Evans) about 7 years ago

Neither sequel, sequel_pg, nor pg appear to use throw according to grep.

I can confirm that the patch does fix the issue. After a fix is committed to trunk, it will also need to be backported to 2.4.

Updated by jeremyevans0 (Jeremy Evans) about 7 years ago

  • Backport changed from 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN to 2.2: DONTNEED, 2.3: DONTNEED, 2.4: REQUIRED

Updated by nobu (Nobuyoshi Nakada) about 7 years ago

Nor Timeout.timeout?

Updated by jeremyevans0 (Jeremy Evans) about 7 years ago

Timeout.timeout doesn't appear to be called directly, though I didn't audit all code involved. The problematic code uses rb_ensure and inside the ensure function it uses rb_exc_raise: https://github.com/jeremyevans/sequel_pg/blob/1.6.17/ext/sequel_pg/sequel_pg.c#L1004

I tried to build an example with a simple C extension that didn't use Sequel, but unfortunately I was not able to get it to crash.

Actions #6

Updated by nobu (Nobuyoshi Nakada) about 7 years ago

  • Status changed from Feedback to Closed

Applied in changeset r57510.


eval.c: hide internal objects

  • eval.c (rb_ensure): veil internal exception objects not to leak
    in ensure functions. [ruby-core:79371] [Bug #13176]

Updated by naruse (Yui NARUSE) about 7 years ago

  • Backport changed from 2.2: DONTNEED, 2.3: DONTNEED, 2.4: REQUIRED to 2.2: DONTNEED, 2.3: DONTNEED, 2.4: DONE

ruby_2_4 r57885 merged revision(s) 57510,57511.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0