@@ -175,6 +175,56 @@ bio_bwrite0(VALUE args)
175175 }
176176}
177177
178+ struct call0_args {
179+ VALUE (* func )(VALUE );
180+ VALUE args ;
181+ VALUE ret ;
182+ };
183+
184+ static VALUE
185+ do_nothing (VALUE _ )
186+ {
187+ return Qnil ;
188+ }
189+
190+ static VALUE
191+ call_protect1 (VALUE args_ )
192+ {
193+ struct call0_args * args = (void * )args_ ;
194+ rb_set_errinfo (Qnil );
195+ args -> ret = args -> func (args -> args );
196+ return Qnil ;
197+ }
198+
199+ static VALUE
200+ call_protect0 (VALUE args_ )
201+ {
202+ /*
203+ * At this point rb_errinfo() may be set by another callback called from
204+ * the same OpenSSL function (e.g., SSL_accept()).
205+ *
206+ * Abusing rb_ensure() to temporarily save errinfo and restore it after
207+ * the BIO callback successfully returns.
208+ */
209+ rb_ensure (do_nothing , Qnil , call_protect1 , args_ );
210+ return Qnil ;
211+ }
212+
213+ static VALUE
214+ call_protect (VALUE (* func )(VALUE ), VALUE args , int * state )
215+ {
216+ /*
217+ * FIXME: should check !NIL_P(rb_ivar_get(ssl_obj, ID_callback_state))
218+ * instead to see if a tag jump is pending or not.
219+ */
220+ int pending = !NIL_P (rb_errinfo ());
221+ struct call0_args call0_args = { func , args , Qfalse };
222+ rb_protect (call_protect0 , (VALUE )& call0_args , state );
223+ if (pending && * state )
224+ rb_warn ("exception ignored in BIO callback: pending=%d" , pending );
225+ return call0_args .ret ;
226+ }
227+
178228static int
179229bio_bwrite (BIO * bio , const char * data , int dlen )
180230{
@@ -185,7 +235,7 @@ bio_bwrite(BIO *bio, const char *data, int dlen)
185235 if (ctx -> state )
186236 return -1 ;
187237
188- VALUE ok = rb_protect (bio_bwrite0 , (VALUE )& args , & state );
238+ VALUE ok = call_protect (bio_bwrite0 , (VALUE )& args , & state );
189239 if (state ) {
190240 ctx -> state = state ;
191241 return -1 ;
@@ -250,7 +300,7 @@ bio_bread(BIO *bio, char *data, int dlen)
250300 if (ctx -> state )
251301 return -1 ;
252302
253- VALUE ok = rb_protect (bio_bread0 , (VALUE )& args , & state );
303+ VALUE ok = call_protect (bio_bread0 , (VALUE )& args , & state );
254304 if (state ) {
255305 ctx -> state = state ;
256306 return -1 ;
@@ -280,7 +330,7 @@ bio_ctrl(BIO *bio, int cmd, long larg, void *parg)
280330 case BIO_CTRL_EOF :
281331 return ctx -> eof ;
282332 case BIO_CTRL_FLUSH :
283- rb_protect (bio_flush0 , (VALUE )ctx , & state );
333+ call_protect (bio_flush0 , (VALUE )ctx , & state );
284334 ctx -> state = state ;
285335 return !state ;
286336 default :
0 commit comments