@@ -22,8 +22,9 @@ use rb_sys::{
2222 rb_raise, rb_eIOError,
2323 rb_sym2id, rb_id2name, rb_id2sym, rb_obj_classname, rb_num2long
2424} ;
25- use rb_sys:: { RARRAY_LEN , RARRAY_CONST_PTR , RSTRING_LEN , RSTRING_PTR , RB_INTEGER_TYPE_P , RB_TYPE_P , RB_SYMBOL_P , RB_FLOAT_TYPE_P , NIL_P } ;
25+ use rb_sys:: { RARRAY_LEN , RARRAY_CONST_PTR , RSTRING_LEN , RSTRING_PTR , RB_INTEGER_TYPE_P , RB_TYPE_P , RB_SYMBOL_P , RB_FLOAT_TYPE_P , NIL_P , rb_protect } ;
2626use rb_sys:: { Qtrue , Qfalse , Qnil } ;
27+ use std:: os:: raw:: c_int;
2728use runtime_tracing:: {
2829 Tracer , Line , ValueRecord , TypeKind , TypeSpecificInfo , TypeRecord , FieldTypeRecord , TypeId ,
2930 EventLogKind , TraceLowLevelEvent , CallRecord , FullValueRecord , ReturnRecord , RecordEvent ,
@@ -71,6 +72,7 @@ extern "C" {
7172 static rb_cRegexp: VALUE ;
7273 static rb_cStruct: VALUE ;
7374 static rb_cRange: VALUE ;
75+ fn rb_method_boundp ( klass : VALUE , mid : ID , ex : c_int ) -> VALUE ;
7476}
7577
7678struct Recorder {
@@ -260,6 +262,30 @@ unsafe fn value_to_string(val: VALUE, to_s_id: ID) -> Option<String> {
260262 Some ( String :: from_utf8_lossy ( slice) . to_string ( ) )
261263}
262264
265+ unsafe extern "C" fn call_to_s ( arg : VALUE ) -> VALUE {
266+ let data = & * ( arg as * const ( VALUE , ID ) ) ;
267+ rb_funcall ( data. 0 , data. 1 , 0 )
268+ }
269+
270+ unsafe fn value_to_string_safe ( val : VALUE , to_s_id : ID ) -> Option < String > {
271+ if RB_TYPE_P ( val, rb_sys:: ruby_value_type:: RUBY_T_STRING ) {
272+ let ptr = RSTRING_PTR ( val) ;
273+ let len = RSTRING_LEN ( val) as usize ;
274+ let slice = std:: slice:: from_raw_parts ( ptr as * const u8 , len) ;
275+ return Some ( String :: from_utf8_lossy ( slice) . to_string ( ) ) ;
276+ }
277+ let mut state: c_int = 0 ;
278+ let data = ( val, to_s_id) ;
279+ let str_val = rb_protect ( Some ( call_to_s) , & data as * const _ as VALUE , & mut state) ;
280+ if state != 0 {
281+ return None ;
282+ }
283+ let ptr = RSTRING_PTR ( str_val) ;
284+ let len = RSTRING_LEN ( str_val) as usize ;
285+ let slice = std:: slice:: from_raw_parts ( ptr as * const u8 , len) ;
286+ Some ( String :: from_utf8_lossy ( slice) . to_string ( ) )
287+ }
288+
263289unsafe fn to_value ( recorder : & mut Recorder , val : VALUE , depth : usize , to_s_id : ID ) -> ValueRecord {
264290 if depth == 0 {
265291 let type_id = recorder. tracer . ensure_type_id ( TypeKind :: Error , "No type" ) ;
@@ -314,7 +340,9 @@ unsafe fn to_value(recorder: &mut Recorder, val: VALUE, depth: usize, to_s_id: I
314340 let mut elements = Vec :: new ( ) ;
315341 for i in 0 ..len {
316342 let pair = * ptr. add ( i) ;
317- if RARRAY_LEN ( pair) < 2 { continue ; }
343+ if !RB_TYPE_P ( pair, rb_sys:: ruby_value_type:: RUBY_T_ARRAY ) || RARRAY_LEN ( pair) < 2 {
344+ continue ;
345+ }
318346 let pair_ptr = RARRAY_CONST_PTR ( pair) ;
319347 let key = * pair_ptr. add ( 0 ) ;
320348 let val_elem = * pair_ptr. add ( 1 ) ;
@@ -333,15 +361,17 @@ unsafe fn to_value(recorder: &mut Recorder, val: VALUE, depth: usize, to_s_id: I
333361 let set_cls = rb_const_get ( rb_cObject, set_id) ;
334362 if rb_obj_is_kind_of ( val, set_cls) != 0 {
335363 let arr = rb_funcall ( val, rb_intern ( b"to_a\0 " . as_ptr ( ) as * const c_char ) , 0 ) ;
336- let len = RARRAY_LEN ( arr) as usize ;
337- let ptr = RARRAY_CONST_PTR ( arr) ;
338- let mut elements = Vec :: new ( ) ;
339- for i in 0 ..len {
340- let elem = * ptr. add ( i) ;
341- elements. push ( to_value ( recorder, elem, depth - 1 , to_s_id) ) ;
364+ if RB_TYPE_P ( arr, rb_sys:: ruby_value_type:: RUBY_T_ARRAY ) {
365+ let len = RARRAY_LEN ( arr) as usize ;
366+ let ptr = RARRAY_CONST_PTR ( arr) ;
367+ let mut elements = Vec :: new ( ) ;
368+ for i in 0 ..len {
369+ let elem = * ptr. add ( i) ;
370+ elements. push ( to_value ( recorder, elem, depth - 1 , to_s_id) ) ;
371+ }
372+ let type_id = recorder. tracer . ensure_type_id ( TypeKind :: Seq , "Set" ) ;
373+ return ValueRecord :: Sequence { elements, is_slice : false , type_id } ;
342374 }
343- let type_id = recorder. tracer . ensure_type_id ( TypeKind :: Seq , "Set" ) ;
344- return ValueRecord :: Sequence { elements, is_slice : false , type_id } ;
345375 }
346376 }
347377 if rb_obj_is_kind_of ( val, rb_cTime) != 0 {
@@ -358,6 +388,11 @@ unsafe fn to_value(recorder: &mut Recorder, val: VALUE, depth: usize, to_s_id: I
358388 let class_name = cstr_to_string ( rb_obj_classname ( val) ) . unwrap_or_else ( || "Struct" . to_string ( ) ) ;
359389 let members = rb_funcall ( val, rb_intern ( b"members\0 " . as_ptr ( ) as * const c_char ) , 0 ) ;
360390 let values = rb_funcall ( val, rb_intern ( b"values\0 " . as_ptr ( ) as * const c_char ) , 0 ) ;
391+ if !RB_TYPE_P ( members, rb_sys:: ruby_value_type:: RUBY_T_ARRAY ) || !RB_TYPE_P ( values, rb_sys:: ruby_value_type:: RUBY_T_ARRAY ) {
392+ let text = value_to_string ( val, to_s_id) . unwrap_or_default ( ) ;
393+ let type_id = recorder. tracer . ensure_type_id ( TypeKind :: Raw , & class_name) ;
394+ return ValueRecord :: Raw { r : text, type_id } ;
395+ }
361396 let len = RARRAY_LEN ( values) as usize ;
362397 let mem_ptr = RARRAY_CONST_PTR ( members) ;
363398 let val_ptr = RARRAY_CONST_PTR ( values) ;
@@ -384,6 +419,11 @@ unsafe fn to_value(recorder: &mut Recorder, val: VALUE, depth: usize, to_s_id: I
384419 let class_name = cstr_to_string ( rb_obj_classname ( val) ) . unwrap_or_else ( || "Object" . to_string ( ) ) ;
385420 // generic object
386421 let ivars = rb_funcall ( val, rb_intern ( b"instance_variables\0 " . as_ptr ( ) as * const c_char ) , 0 ) ;
422+ if !RB_TYPE_P ( ivars, rb_sys:: ruby_value_type:: RUBY_T_ARRAY ) {
423+ let text = value_to_string ( val, to_s_id) . unwrap_or_default ( ) ;
424+ let type_id = recorder. tracer . ensure_type_id ( TypeKind :: Raw , & class_name) ;
425+ return ValueRecord :: Raw { r : text, type_id } ;
426+ }
387427 let len = RARRAY_LEN ( ivars) as usize ;
388428 let ptr = RARRAY_CONST_PTR ( ivars) ;
389429 let mut names: Vec < & str > = Vec :: new ( ) ;
@@ -408,6 +448,9 @@ unsafe fn to_value(recorder: &mut Recorder, val: VALUE, depth: usize, to_s_id: I
408448unsafe fn record_variables ( recorder : & mut Recorder , binding : VALUE ) -> Vec < FullValueRecord > {
409449 let mut result = Vec :: new ( ) ;
410450 let vars = rb_funcall ( binding, recorder. locals_id , 0 ) ;
451+ if !RB_TYPE_P ( vars, rb_sys:: ruby_value_type:: RUBY_T_ARRAY ) {
452+ return result;
453+ }
411454 let len = RARRAY_LEN ( vars) as usize ;
412455 let ptr = RARRAY_CONST_PTR ( vars) ;
413456 for i in 0 ..len {
@@ -426,13 +469,19 @@ unsafe fn record_variables(recorder: &mut Recorder, binding: VALUE) -> Vec<FullV
426469unsafe fn record_parameters ( recorder : & mut Recorder , binding : VALUE , defined_class : VALUE , mid : ID , register : bool ) -> Vec < FullValueRecord > {
427470 let mut result = Vec :: new ( ) ;
428471 let method_sym = rb_id2sym ( mid) ;
472+ if rb_method_boundp ( defined_class, mid, 0 ) == 0 {
473+ return result;
474+ }
429475 let method_obj = rb_funcall ( defined_class, recorder. inst_meth_id , 1 , method_sym) ;
430476 let params_ary = rb_funcall ( method_obj, recorder. parameters_id , 0 ) ;
477+ if !RB_TYPE_P ( params_ary, rb_sys:: ruby_value_type:: RUBY_T_ARRAY ) {
478+ return result;
479+ }
431480 let params_len = RARRAY_LEN ( params_ary) as usize ;
432481 let params_ptr = RARRAY_CONST_PTR ( params_ary) ;
433482 for i in 0 ..params_len {
434483 let pair = * params_ptr. add ( i) ;
435- if RARRAY_LEN ( pair) < 2 {
484+ if ! RB_TYPE_P ( pair , rb_sys :: ruby_value_type :: RUBY_T_ARRAY ) || RARRAY_LEN ( pair) < 2 {
436485 continue ;
437486 }
438487 let pair_ptr = RARRAY_CONST_PTR ( pair) ;
@@ -545,20 +594,18 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) {
545594 let mid_sym = rb_tracearg_callee_id ( arg) ;
546595 let mid = rb_sym2id ( mid_sym) ;
547596 let defined_class = rb_funcall ( self_val, recorder. class_id , 0 ) ;
597+ let mut args = Vec :: new ( ) ;
548598 if !NIL_P ( binding) {
549- // register parameter types first
550- let _ = record_parameters ( recorder, binding, defined_class, mid, false ) ;
599+ args = record_parameters ( recorder, binding, defined_class, mid, true ) ;
551600 }
552- let self_rec = to_value ( recorder, self_val, 10 , recorder. to_s_id ) ;
601+ let class_name = cstr_to_string ( rb_obj_classname ( self_val) ) . unwrap_or_else ( || "Object" . to_string ( ) ) ;
602+ let text = value_to_string_safe ( self_val, recorder. to_s_id ) . unwrap_or_default ( ) ;
603+ let self_type = recorder. tracer . ensure_type_id ( TypeKind :: Raw , & class_name) ;
604+ let self_rec = ValueRecord :: Raw { r : text, type_id : self_type } ;
553605 recorder
554606 . tracer
555607 . register_variable_with_full_value ( "self" , self_rec. clone ( ) ) ;
556608
557- let mut args = if NIL_P ( binding) {
558- vec ! [ ]
559- } else {
560- record_parameters ( recorder, binding, defined_class, mid, true )
561- } ;
562609 args. insert ( 0 , recorder. tracer . arg ( "self" , self_rec) ) ;
563610 recorder. tracer . register_step ( Path :: new ( & path) , Line ( line) ) ;
564611 let name_c = rb_id2name ( mid) ;
@@ -567,7 +614,6 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) {
567614 } else {
568615 String :: new ( )
569616 } ;
570- let class_name = cstr_to_string ( rb_obj_classname ( self_val) ) . unwrap_or_else ( || "Object" . to_string ( ) ) ;
571617 if class_name != "Object" {
572618 name = format ! ( "{}#{}" , class_name, name) ;
573619 }
0 commit comments