Skip to content

Commit ff782dc

Browse files
committed
fix(napi): don't touch async work after its complete callback
A complete callback may free the work with napi_delete_async_work, as Node allows and napi-rs does, so read env, complete and data before calling it.
1 parent f8d2844 commit ff782dc

1 file changed

Lines changed: 14 additions & 10 deletions

File tree

‎runtime/src/node_api.rs‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -577,18 +577,22 @@ struct AsyncWork {
577577
}
578578

579579
impl AsyncWork {
580-
/// JS thread.
580+
/// JS thread. `complete` may free the work (`napi_delete_async_work`), as Node allows and
581+
/// napi-rs does, so nothing reads `work` after calling it.
581582
unsafe fn complete(work: *mut AsyncWork) {
582-
let work = &*work;
583-
let status = if work.state.swap(WORK_IDLE, Ordering::AcqRel) == WORK_CANCELLED {
584-
NAPI_CANCELLED
585-
} else {
586-
NAPI_OK
583+
let (env, complete, data) = {
584+
let work = &*work;
585+
let status = if work.state.swap(WORK_IDLE, Ordering::AcqRel) == WORK_CANCELLED {
586+
NAPI_CANCELLED
587+
} else {
588+
NAPI_OK
589+
};
590+
(work.env, work.complete.map(|complete| (complete, status)), work.data)
587591
};
588-
if let Some(complete) = work.complete {
589-
let _scope = HandleScope::open(work.env);
590-
complete(work.env, status, work.data);
591-
report_pending(work.env);
592+
if let Some((complete, status)) = complete {
593+
let _scope = HandleScope::open(env);
594+
complete(env, status, data);
595+
report_pending(env);
592596
}
593597
}
594598
}

0 commit comments

Comments
 (0)