Skip to content

Commit e03d153

Browse files
samuel-williams-shopifyioquatix
authored andcommitted
Fix blocking_operation_wait use-after-free bug.
1 parent 108d4ac commit e03d153

File tree

6 files changed

+350
-51
lines changed

6 files changed

+350
-51
lines changed

include/ruby/fiber/scheduler.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +394,54 @@ VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io);
394394
*/
395395
VALUE rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname);
396396

397+
// The state of the blocking operation execution.
397398
struct rb_fiber_scheduler_blocking_operation_state {
398399
void *result;
399400
int saved_errno;
400401
};
401402

403+
// The opaque handle for the blocking operation.
404+
typedef struct rb_fiber_scheduler_blocking_operation rb_fiber_scheduler_blocking_operation_t;
405+
406+
/**
407+
* Extract the blocking operation handle from a BlockingOperationRuby object.
408+
*
409+
* This function safely extracts the opaque handle from a BlockingOperation VALUE
410+
* while holding the GVL. The returned pointer can be passed to worker threads
411+
* and used with rb_fiber_scheduler_blocking_operation_execute.
412+
*
413+
* @param[in] self The BlockingOperation VALUE to extract from
414+
* @return The opaque struct pointer on success, NULL on error
415+
* @note Experimental.
416+
*/
417+
rb_fiber_scheduler_blocking_operation_t *rb_fiber_scheduler_blocking_operation_extract(VALUE self);
418+
419+
/**
420+
* Execute blocking operation from handle (GVL not required).
421+
*
422+
* This function executes a blocking operation using the opaque handle
423+
* obtained from rb_fiber_scheduler_blocking_operation_extract.
424+
* It can be called from native threads without holding the GVL.
425+
*
426+
* @param[in] blocking_operation The opaque handle.
427+
* @return 0 on success, -1 on error.
428+
* @note Experimental. Can be called from any thread without holding the GVL
429+
*/
430+
int rb_fiber_scheduler_blocking_operation_execute(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
431+
432+
/**
433+
* Cancel a blocking operation.
434+
*
435+
* This function cancels a blocking operation. If the operation is queued,
436+
* it just marks it as cancelled. If it's executing, it marks it as cancelled
437+
* and calls the unblock function to interrupt the operation.
438+
*
439+
* @param blocking_operation The opaque struct pointer
440+
* @return 1 if unblock function was called, 0 if just marked cancelled, -1 on error
441+
* @note Experimental.
442+
*/
443+
int rb_fiber_scheduler_blocking_operation_cancel(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
444+
402445
/**
403446
* Defer the execution of the passed function to the scheduler.
404447
*

inits.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ rb_call_inits(void)
6363
CALL(ISeq);
6464
CALL(Thread);
6565
CALL(signal);
66+
CALL(Cont);
6667
CALL(Fiber_Scheduler);
6768
CALL(process);
68-
CALL(Cont);
6969
CALL(Rational);
7070
CALL(Complex);
7171
CALL(MemoryView);

0 commit comments

Comments
 (0)