@@ -467,6 +467,19 @@ static int hiredis_wait_readable(int fd, const struct timeval *timeout, int *iss
467
467
return 0 ;
468
468
}
469
469
470
+ struct fd_select {
471
+ rb_fdset_t * write_fds ;
472
+ struct timeval * timeout ;
473
+ int max ;
474
+ int return_value ;
475
+ };
476
+
477
+ static VALUE protected_writable_select (VALUE _args ) {
478
+ struct fd_select * args = (struct fd_select * )_args ;
479
+ args -> return_value = rb_thread_fd_select (args -> max , NULL , args -> write_fds , NULL , args -> timeout );
480
+ return Qnil ;
481
+ }
482
+
470
483
static int hiredis_wait_writable (int fd , const struct timeval * timeout , int * isset ) {
471
484
struct timeval to ;
472
485
struct timeval * toptr = NULL ;
@@ -483,7 +496,18 @@ static int hiredis_wait_writable(int fd, const struct timeval *timeout, int *iss
483
496
toptr = & to ;
484
497
}
485
498
486
- if (rb_thread_fd_select (fd + 1 , NULL , & fds , NULL , toptr ) < 0 ) {
499
+ struct fd_select args = {
500
+ .max = fd + 1 ,
501
+ .write_fds = & fds ,
502
+ .timeout = toptr ,
503
+ };
504
+ int status ;
505
+
506
+ (void )rb_protect (protected_writable_select , (VALUE )& args , & status );
507
+
508
+ // Error in case an exception arrives in rb_thread_fd_select()
509
+ // (e.g. from Thread.raise)
510
+ if (status || args .return_value < 0 ) {
487
511
rb_fd_term (& fds );
488
512
return -1 ;
489
513
}
@@ -501,7 +525,6 @@ static VALUE hiredis_connect_finish(hiredis_connection_t *connection, redisConte
501
525
redisFree (context );
502
526
rb_raise (rb_eRuntimeError , "HiredisConnection is already connected, must be a bug" );
503
527
}
504
- connection -> context = context ;
505
528
506
529
if (context -> err ) {
507
530
redis_raise_error_and_disconnect (context , rb_eRedisClientCannotConnectError );
@@ -536,6 +559,7 @@ static VALUE hiredis_connect_finish(hiredis_connection_t *connection, redisConte
536
559
537
560
context -> reader -> fn = & reply_functions ;
538
561
redisSetPushCallback (context , NULL );
562
+ connection -> context = context ;
539
563
return Qtrue ;
540
564
}
541
565
@@ -601,9 +625,14 @@ static VALUE hiredis_reconnect(VALUE self, VALUE is_unix, VALUE ssl_param) {
601
625
return Qfalse ;
602
626
}
603
627
604
- hiredis_reconnect_nogvl (connection -> context );
628
+ // Clear context on the connection, since the nogvl call can raise an
629
+ // exception after the redisReconnect() call succeeds and leave the
630
+ // connection in a half-initialized state.
631
+ redisContext * context = connection -> context ;
632
+ connection -> context = NULL ;
633
+ hiredis_reconnect_nogvl (context );
605
634
606
- VALUE success = hiredis_connect_finish (connection , connection -> context );
635
+ VALUE success = hiredis_connect_finish (connection , context );
607
636
608
637
if (RTEST (success )) {
609
638
if (!RTEST (is_unix )) {
0 commit comments