From: djberg96@... (Daniel Berger) Date: 2004-09-29T03:04:22+09:00 Subject: [BUG] Bus Error in kstat extension Hi all, Ruby 1.8.2 (2004-09-22) Solaris 9 gcc 3.3.3 I'm trying to build an extension for kstat on Solaris. Sample test scripts work fine, but test unit blows up with a bus error. That usually means I've got a problem somewhere in my C code with regards to memory allocation. Only, I don't see where. Here's the .c, .h, extconf.rb, test.rb, and tc_kstat.rb files, followed by the backtrace: /* rkstat.c */ #include #include #include #include "ruby.h" #include "rkstat.h" VALUE cKstatError; static VALUE ks_allocate(VALUE klass){ KstatStruct* ptr = malloc(sizeof(KstatStruct)); return Data_Wrap_Struct(klass,0,ks_free,ptr); } VALUE ks_init(VALUE self){ KstatStruct* ptr; Data_Get_Struct(self,KstatStruct,ptr); ptr->kc = kstat_open(); if(NULL == ptr->kc){ rb_raise(cKstatError,"kstat_open() failure"); } ptr->ksp = kstat_lookup( ptr->kc, NULL, -1, NULL ); if(NULL == ptr->ksp){ rb_raise(cKstatError,"kstat_lookup() failure"); } return self; } VALUE ks_record(VALUE self){ VALUE rbMHash, rbIHash, rbNHash, rbSHash; KstatStruct* ptr; kstat_io_t kio; Data_Get_Struct(self,KstatStruct,ptr); rbMHash = rb_hash_new(); // Module name is key, holds rbIHashes rbIHash = rb_hash_new(); // Instance name is key, holds rbNHashes rbNHash = rb_hash_new(); // Name is key, holds rbSHashes kstat_chain_update(ptr->kc); // Sync the chain with the kernel for( ptr->ksp = ptr->kc->kc_chain; ptr->ksp != NULL; ptr->ksp = ptr->ksp->ks_next ) { switch(ptr->ksp->ks_type){ case KSTAT_TYPE_NAMED: kstat_read(ptr->kc,ptr->ksp,NULL); rbSHash = map_named_data_type(ptr->ksp); break; case KSTAT_TYPE_IO: kstat_read(ptr->kc,ptr->ksp,&kio); rbSHash = map_io_data_type(kio); break; } rb_hash_aset(rbNHash,rb_str_new2(ptr->ksp->ks_name),rbSHash); rb_hash_aset(rbIHash,INT2FIX(ptr->ksp->ks_instance), rbNHash); rb_hash_aset(rbMHash,rb_str_new2(ptr->ksp->ks_module),rbIHash); } return rbMHash; } void Init_kstat(){ VALUE mSolaris, cKstat; // Module and Class declarations mSolaris = rb_define_module("Solaris"); cKstat = rb_define_class_under(mSolaris,"Kstat",rb_cObject); cKstatError = rb_define_class_under(mSolaris,"KstatError",rb_eStandardError); rb_define_alloc_func(cKstat,ks_allocate); // Instance Methods rb_define_method(cKstat,"initialize",ks_init,0); rb_define_method(cKstat,"record",ks_record,0); // Constants rb_define_const(cKstat,"VERSION",rb_str_new2(SOLARIS_KSTAT_VERSION)); } /* rkstat.h */ #define SOLARIS_KSTAT_VERSION "0.1.0" static VALUE map_named_data_type(kstat_t* ksp); // Structure wrapped as our Kstat class struct kstruct{ kstat_ctl_t* kc; kstat_t* ksp; }; typedef struct kstruct KstatStruct; static void ks_free(KstatStruct* p){ kstat_close(p->kc); free(p); } static VALUE map_io_data_type(kstat_io_t k){ VALUE rbHash = rb_hash_new(); rb_hash_aset(rbHash,rb_str_new2("nread"),ULL2NUM(k.nread)); rb_hash_aset(rbHash,rb_str_new2("nwritten"),ULL2NUM(k.nwritten)); rb_hash_aset(rbHash,rb_str_new2("reads"),UINT2NUM(k.reads)); rb_hash_aset(rbHash,rb_str_new2("writes"),UINT2NUM(k.writes)); rb_hash_aset(rbHash,rb_str_new2("wtime"),ULL2NUM(k.wtime)); rb_hash_aset(rbHash,rb_str_new2("wlentime"),ULL2NUM(k.wlentime)); rb_hash_aset(rbHash,rb_str_new2("wlastupdate"),ULL2NUM(k.wlastupdate)); rb_hash_aset(rbHash,rb_str_new2("rtime"),ULL2NUM(k.rtime)); rb_hash_aset(rbHash,rb_str_new2("rlentime"),ULL2NUM(k.rlentime)); rb_hash_aset(rbHash,rb_str_new2("rlastupdate"),ULL2NUM(k.rlastupdate)); rb_hash_aset(rbHash,rb_str_new2("wcnt"),UINT2NUM(k.wcnt)); rb_hash_aset(rbHash,rb_str_new2("rcnt"),UINT2NUM(k.rcnt)); return rbHash; } static VALUE map_named_data_type(kstat_t* ksp){ VALUE rbHash; kstat_named_t* knp; knp = (kstat_named_t *)ksp->ks_data; int i; rbHash = rb_hash_new(); for(i = 0; i < ksp->ks_ndata; i++, knp++) { switch (knp->data_type) { case KSTAT_DATA_CHAR: rb_hash_aset(rbHash,rb_str_new2(knp->name),rb_str_new2(knp->value.c)); break; case KSTAT_DATA_INT32: rb_hash_aset(rbHash,rb_str_new2(knp->name),INT2NUM(knp->value.i32)); break; case KSTAT_DATA_UINT32: rb_hash_aset(rbHash,rb_str_new2(knp->name),UINT2NUM(knp->value.ui32)); break; case KSTAT_DATA_INT64: rb_hash_aset(rbHash,rb_str_new2(knp->name),LL2NUM(knp->value.i64)); break; case KSTAT_DATA_UINT64: rb_hash_aset(rbHash,rb_str_new2(knp->name),ULL2NUM(knp->value.ui64)); break; default: rb_hash_aset(rbHash,rb_str_new2(knp->name),rb_str_new2("Unknown")); break; } } return rbHash; } # extconf.rb require "mkmf" require "ftools" # This package requires Solaris 2.8 or later unless have_header("kstat.h") STDERR.puts "The kstat.h header file was not found. Exiting." exit end have_library("kstat") create_makefile("solaris/kstat") # test.rb - works fine require "solaris/kstat" include Solaris k1 = Kstat.new k2 = Kstat.new p k1.record["cpu_info"][0]["cpu_info0"] p k1.record["nfs"][1]["nfs1"] p k2.record["cpu_info"][0]["cpu_info0"] p k2.record["nfs"][1]["nfs1"] # tc_kstat.rb - causes bus error. require "solaris/kstat" require "test/unit" include Solaris class TC_Kstat < Test::Unit::TestCase def setup @k = Kstat.new end def test_version assert_equal("0.1.0",Kstat::VERSION) end def test_record_basic assert_respond_to(@k, :record) end # If you remove this test or the test_record_io it works, # but if you try to run both it causes a bus error. def test_record_named assert_nothing_raised{ @k.record["cpu_info"][0]["cpu_info0"] } assert_kind_of(Hash, @k.record["cpu_info"][0]["cpu_info0"]) end def test_record_io assert_nothing_raised{ @k.record["nfs"][1]["nfs1"] } assert_kind_of(Hash, @k.record["nfs"][1]["nfs1"]) end def teardown @k = nil end end Here's the backtrace: djberge@sp5wd-b1-/home/djberge/workspace/solaris-kstat-995>gdb /opt/bin/ruby core GNU gdb 6.1 Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "sparc-sun-solaris2.8"...(no debugging symbols found)... Core was generated by `ruby test/tc_kstat.rb'. Program terminated with signal 6, Aborted. Reading symbols from /usr/lib/libdl.so.1...(no debugging symbols found)...done. Loaded symbols for /usr/lib/libdl.so.1 Reading symbols from /usr/lib/libm.so.1...(no debugging symbols found)...done. Loaded symbols for /usr/lib/libm.so.1 Reading symbols from /usr/lib/libc.so.1...(no debugging symbols found)...done. Loaded symbols for /usr/lib/libc.so.1 Reading symbols from /usr/platform/SUNW,Sun-Blade-100/lib/libc_psr.so.1...(no debugging symbols found)...done. Loaded symbols for /usr/platform/SUNW,Sun-Blade-100/lib/libc_psr.so.1 Reading symbols from ./solaris/kstat.so...(no debugging symbols found)...done. Loaded symbols for ./solaris/kstat.so Reading symbols from /usr/lib/libkstat.so.1...(no debugging symbols found)...done. Loaded symbols for /usr/lib/libkstat.so.1 #0 0xff31d3d4 in _libc_kill () from /usr/lib/libc.so.1 (gdb) backtrace #0 0xff31d3d4 in _libc_kill () from /usr/lib/libc.so.1 #1 0xff2b5698 in abort () from /usr/lib/libc.so.1 #2 0x000ed618 in rb_bug () #3 0x000b5e50 in sigbus () #4 #5 0x000bad34 in st_foreach () #6 0x00046490 in mark_tbl () #7 0x00046a68 in gc_mark_children () #8 0x000466ec in gc_mark () #9 0x000464f0 in mark_keyvalue () #10 0x000bada8 in st_foreach () #11 0x00046544 in mark_hash () #12 0x00046b6c in gc_mark_children () #13 0x000466ec in gc_mark () #14 0x000463c4 in mark_locations_array () #15 0x00046410 in rb_gc_mark_locations () #16 0x000482dc in rb_gc () #17 0x00045dbc in rb_newobj () #18 0x000bb068 in str_alloc () #19 0x000bb148 in str_new () #20 0x000bb1f8 in rb_str_new () #21 0x000bb25c in rb_str_new2 () #22 0xff261294 in map_named_data_type () from ./solaris/kstat.so #23 0xff261594 in ks_record () from ./solaris/kstat.so #24 0x0003ca10 in call_cfunc () #25 0x0002a38c in rb_call0 () #26 0x0002b27c in rb_call () #27 0x00022950 in rb_eval () #28 0x00022708 in rb_eval () #29 0x00022708 in rb_eval () #30 0x00022708 in rb_eval () #31 0x00027a1c in rb_yield_0 () #32 0x00021978 in rb_eval () #33 0x00021a44 in rb_eval () #34 0x00027a1c in rb_yield_0 () #35 0x00021978 in rb_eval () #36 0x00022278 in rb_eval () #37 0x00021d2c in rb_eval () #38 0x0002ab0c in rb_call0 () #39 0x0002b27c in rb_call () ---Type to continue, or q to quit--- #40 0x00022c1c in rb_eval () #41 0x00021380 in rb_eval () #42 0x0002ab0c in rb_call0 () #43 0x0002b27c in rb_call () #44 0x00022c1c in rb_eval () #45 0x00021380 in rb_eval () #46 0x0002ab0c in rb_call0 () #47 0x0002b27c in rb_call () #48 0x0002b418 in rb_f_send () #49 0x0003c9f0 in call_cfunc () #50 0x0002a38c in rb_call0 () #51 0x0002b27c in rb_call () #52 0x00022c1c in rb_eval () #53 0x00021a44 in rb_eval () #54 0x00021d2c in rb_eval () #55 0x0002ab0c in rb_call0 () #56 0x0002b27c in rb_call () #57 0x00022950 in rb_eval () #58 0x000329ac in block_pass () #59 0x000210c8 in rb_eval () #60 0x00027a1c in rb_yield_0 () #61 0x00027fd0 in rb_yield () #62 0x000d853c in rb_ary_each () #63 0x0003ca10 in call_cfunc () #64 0x0002a38c in rb_call0 () #65 0x0002b27c in rb_call () #66 0x00022950 in rb_eval () #67 0x00021380 in rb_eval () #68 0x0002ab0c in rb_call0 () #69 0x0002b27c in rb_call () #70 0x00022950 in rb_eval () #71 0x000329ac in block_pass () #72 0x000210c8 in rb_eval () #73 0x00027a1c in rb_yield_0 () #74 0x00027fd0 in rb_yield () #75 0x000d853c in rb_ary_each () #76 0x0003ca10 in call_cfunc () #77 0x0002a38c in rb_call0 () #78 0x0002b27c in rb_call () #79 0x00022950 in rb_eval () ---Type to continue, or q to quit--- #80 0x00021380 in rb_eval () #81 0x0002ab0c in rb_call0 () #82 0x0002b27c in rb_call () #83 0x00022950 in rb_eval () #84 0x00021380 in rb_eval () #85 0x0002ab0c in rb_call0 () #86 0x0002b27c in rb_call () #87 0x00022950 in rb_eval () #88 0x00022278 in rb_eval () #89 0x0002ab0c in rb_call0 () #90 0x0002b27c in rb_call () #91 0x00022c60 in rb_eval () #92 0x00022278 in rb_eval () #93 0x0002ab0c in rb_call0 () #94 0x0002b27c in rb_call () #95 0x00022950 in rb_eval () #96 0x00022278 in rb_eval () #97 0x0002ab0c in rb_call0 () #98 0x0002b27c in rb_call () #99 0x00022950 in rb_eval () #100 0x00022708 in rb_eval () #101 0x0002ab0c in rb_call0 () #102 0x0002b27c in rb_call () #103 0x00022950 in rb_eval () #104 0x0002ab0c in rb_call0 () #105 0x0002b27c in rb_call () #106 0x00022950 in rb_eval () #107 0x00022ac0 in rb_eval () #108 0x00027a1c in rb_yield_0 () #109 0x00031e98 in proc_invoke () #110 0x0002f9a0 in call_end_proc () #111 0x0002fddc in rb_exec_end_proc () #112 0x0001c6c8 in ruby_finalize_0 () #113 0x0001c768 in ruby_cleanup () #114 0x0001cab4 in ruby_stop () #115 0x0001cb4c in ruby_run () #116 0x00019870 in main () Any ideas? Thanks. Dan