From: Peter Zotov Date: 2011-02-07T14:45:35+09:00 Subject: Re: rb_raise() causes segmentfault on xxxxx_alloc() function On Mon, 7 Feb 2011 11:32:17 +0900 IƱaki Baz Castillo wrote: > Hi, my C extension uses rb_define_alloc_func(cResolver, > Resolver_alloc) to initialite the C library. If something goes wrong > in that initialization I want to raise an exception but using > rb_raise() within Resolver_alloc() produces a segmentfault. > > The function is very easy: > > ------------------------------------------------------------------- > VALUE Resolver_alloc(VALUE klass) > { > struct dns_ctx *dns_context; > VALUE obj; > > if (dns_init(NULL, 0) < 0) > rb_raise(rb_eStandardError, "udns dns_init failed"); > > if (!(dns_context = dns_new(NULL))) > rb_raise(rb_eStandardError, "udns dns_new failed"); > > obj = Data_Wrap_Struct(klass, NULL, Resolver_free, dns_context); > return obj; > } > ------------------------------------------------------------------- > > > In order to force the error I change the dns_init line as follows: > > if (dns_init(NULL, 0) == 0) > > and get a segmentfault. Is not allowed to raise an exception in the > alloc function of a class? > > Thanks. > > I'm not exactly sure how this mechanism works (and udns too), but I'd suggest: a) If a C library needs an one-time initialization, implement that as a class method of your Resolver class and call either on library loading or on first use of the library (by defining a flag). b) If a C library needs an initialization for each instance of the object, just define initialize function for the class and do all the initialization there; if you strictly need to do that in *_alloc function(), try returning Qnil (I am not quite sure it will work at all, but at least it's worth trying), or set a flag in the structure you are returning. Either way will let you to determine whether to raise an exception or not in the place where it's perfectly safe to do that (the initialize function). It looks to me that you need both approaches here. -- WBR, Peter Zotov