-
Notifications
You must be signed in to change notification settings - Fork 19
Fix segmentation fault in callbacks #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix segmentation fault in callbacks #34
Conversation
Moved all event callback closures in SpeechRecognizer and SpeechSynthesizer into dedicated internal CallbackBag structs, boxed on the heap. This ensures the main structs can be freely moved while callbacks remain at a stable memory address, improving safety and FFI compatibility.
|
wow, you are productive :) let's address PR31 first, there are two pending items before I can merge. can you have a look? 32 should be easy then. le't s address this one afterwards |
Hi @adambezecny , |
Introduced CallbackBag struct to encapsulate callback management in PushAudioOutputStream. Updated callback registration and invocation logic to use CallbackBag, improving separation of concerns and error handling for undefined callbacks.
|
yeap, sorry I did forget to submit review for pr 31, did it know. can you have a look? thanks |
Introduced CallbackBag struct to encapsulate callback management in PullAudioInputStream. Updated callback registration and FFI callback functions to use CallbackBag, improving separation of concerns and safety when accessing callbacks.
Refactored the field name 'callbacks' to 'callback_bag' in PushAudioOutputStream, SpeechRecognizer, and SpeechSynthesizer structs for clarity and consistency. Updated all references and usages accordingly.
Moved common test utilities to a new common.rs module and updated integration_test.rs to use it, reducing code duplication. Added new test files for pull input, push output, recognizer, and synthesizer segfault scenarios to improve coverage and isolate specific audio stream behaviors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes segmentation faults in callback handling by refactoring how event callback closures are managed across multiple speech SDK components. Instead of storing callback closures directly in the main structs, a new internal CallbackBag struct is introduced and boxed to ensure callbacks remain at stable heap addresses when the main structs are moved.
- Introduces
CallbackBagstructs forSpeechRecognizer,SpeechSynthesizer,PullAudioInputStream, andPushAudioOutputStream - Updates callback registration to use stable heap-allocated callback storage
- Adds comprehensive test coverage for segmentation fault scenarios across all affected components
Reviewed Changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/speech/speech_recognizer.rs |
Refactors callback storage using boxed CallbackBag to prevent segfaults |
src/speech/speech_synthesizer.rs |
Implements callback bag pattern for synthesizer event callbacks |
src/audio/pull_audio_input_stream.rs |
Updates callback handling with stable heap allocation for input streams |
src/audio/push_audio_output_stream.rs |
Applies callback bag pattern to output stream callbacks |
tests/recognizer_segfault_test.rs |
Adds test case for speech recognizer callback stability |
tests/synthesizer_segfault_test.rs |
Adds test case for speech synthesizer callback stability |
tests/pull_input_segfault_test.rs |
Adds test case for pull input stream callback stability |
tests/push_output_segfault_test.rs |
Adds test case for push output stream callback stability |
tests/common.rs |
Introduces shared test utilities for speech recognition and synthesis |
tests/integration_test.rs |
Refactors existing tests to use new common utilities |
Cargo.toml |
Removes unused rust-embed dependency and cleans up formatting |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
hi @wangfu91 give me more time to review please, I am extremely busy lately, really no time for this. I will try to start reviewing in 1-2 weeks from now. sorry :( |
|
Hi @adambezecny , |
|
hi @wangfu91 probably will have not much time to review this week but I already started to be looking into it :) one fundamental question so far: why to create separate boxed struct for callbacks rather then simply pinning callback attributes? please bear in mind my rust is very rusty, not actively using it for long time, so pardon me if the question is stupid. But I think by pinning the inner callback attributes you could save yourself from such massive refactoring. Also if I remember correctly boxing comes with cost since it forces data to be allocated on heap rather than stack. I am also struggling to understand how boxing can prevent dangling pointer. Boxed data can still be moved right, leaving the C pointer not valid any more. Is this somehow enforcing pinning implicitly? |
|
Hi @adambezecny Thank you for taking the time to look at this! These are excellent questions. Let me try to explain the reasoning behind this approach.
This is a great question. The main reason is that pinning in Rust doesn't work on individual fields of a movable struct. Pinning guarantees that the memory of the pinned object will not be moved. If we wanted to make the callback's address stable, we would have to pin the entire The
Yes,
You are right that a
When we move a This way, the |
adambezecny
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
| /// By creating a separate struct, and then boxing this struct inside our SpeechRecognizer, | ||
| /// we can ensure the SpeechRecognizer itself can be moved freely by end users, | ||
| /// and the callbacks will remain at a fixed memory address on the heap. | ||
| struct CallbackBag { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wangfu91
one fundamental question so far: why to create separate boxed struct for callbacks rather then simply pinning callback attributes? please bear in mind my rust is very rusty, not actively using it for long time, so pardon me if the question is stupid. But I think by pinning the inner callback attributes you could save yourself from such massive refactoring. Also if I remember correctly boxing comes with cost since it forces data to be allocated on heap rather than stack.
I am also struggling to understand how boxing can prevent dangling pointer. Boxed data can still be moved right, leaving the C pointer not valid any more. Is this somehow enforcing pinning implicitly?
|
this is excellent work, I am kind of speechless. Thank you for all the effort you are putting into this. Thanks to all your contributions this library got so much better after I stopped actively contributing to it on regular basis. Really appreciated! thanks :-) |
|
published v1.3.0 with latest code |
|
Hi Adam, |
This PR fixes #33, it refactors how event callback closures are managed in both the
SpeechRecognizerandSpeechSynthesizerstructs.Instead of storing callback closures directly in these structs, a new internal
CallbackBagstruct is introduced and boxed, ensuring that callbacks reside at a stable heap address.This change improves memory safety and allows the main structs to be moved freely without invalidating callback pointers.
Checklist:
SpeechRecognizer& add testsSpeechSynthesizer& add testsPullAudioInputStream& add testsPushAudioOutputStream& add tests