Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions dash-spv-ffi/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,14 @@ impl FFIDashSpvClient {
return;
};
let callbacks = self.event_callbacks.lock().unwrap();
// Prevent flooding the UI/main thread by limiting events per drain call.
// Remaining events stay queued and will be drained on the next tick.
let max_events_per_call: usize = 500;
let mut processed: usize = 0;
loop {
if processed >= max_events_per_call {
break;
}
match rx.try_recv() {
Ok(event) => match event {
dash_spv::types::SpvEvent::BalanceUpdate {
Expand Down Expand Up @@ -354,6 +361,7 @@ impl FFIDashSpvClient {
break;
}
}
processed += 1;
}
}
}
Expand Down Expand Up @@ -804,8 +812,8 @@ pub unsafe extern "C" fn dash_spv_ffi_client_sync_to_tip_with_progress(
SyncStage::Complete | SyncStage::Failed(_)
);

// Create FFI progress
let ffi_progress = Box::new(FFIDetailedSyncProgress::from(progress));
// Create FFI progress (stack-allocated to avoid double-free issues)
let mut ffi_progress = FFIDetailedSyncProgress::from(progress);

// Call the callback using the registry
{
Expand All @@ -822,7 +830,24 @@ pub unsafe extern "C" fn dash_spv_ffi_client_sync_to_tip_with_progress(
// SAFETY: The callback and user_data are safely stored in the registry
// and accessed through thread-safe mechanisms. The registry ensures
// proper lifetime management without raw pointer passing across threads.
callback(ffi_progress.as_ref(), *user_data);
callback(&ffi_progress, *user_data);

// Free any heap-allocated strings inside the progress struct
// to avoid leaking per-callback allocations (e.g., stage_message).
// Move stage_message out of the struct to avoid double-free.
unsafe {
// Move stage_message out of the struct (not using ptr::read to avoid double-free)
let stage_message = std::mem::replace(
&mut ffi_progress.stage_message,
crate::types::FFIString {
ptr: std::ptr::null_mut(),
length: 0,
},
);
// Destroy stage_message allocated in FFIDetailedSyncProgress::from
crate::types::dash_spv_ffi_string_destroy(stage_message);
// ffi_progress will be dropped normally here; no Drop impl exists
}
}
}
}
Expand Down
Loading