Skip to content

Refactor Dart API to check for nullptr. - #3329

Merged
csukuangfj merged 2 commits into
k2-fsa:masterfrom
csukuangfj:fix-dart
Mar 17, 2026
Merged

csukuangfj merged 2 commits into
k2-fsa:masterfrom
csukuangfj:fix-dart

Conversation

@csukuangfj

@csukuangfj csukuangfj commented Mar 17, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Enhanced stability across audio processing and speech recognition features by adding protective validation checks to prevent crashes from uninitialized components or invalid memory references.
    • Improved error handling to gracefully manage edge cases and provide clearer error messages when operations are invoked before proper initialization.
    • Strengthened safety guards on critical operations to ensure robust handling of null pointers and invalid states.

@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Mar 17, 2026
@coderabbitai

coderabbitai Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This pull request adds defensive null-checks and initialization guards across 14 Dart binding files in the Flutter sherpa-onnx package, ensuring SherpaOnnxBindings is initialized and native pointers are valid before dereferencing them in methods like free, createStream, compute, and other lifecycle operations.

Changes

Cohort / File(s) Summary
Audio Processing
flutter/sherpa_onnx/lib/src/audio_tagging.dart, offline_stream.dart, online_stream.dart
Added initialization checks and null-pointer guards to free, createStream, and data-processing methods; validates bindings exist before invoking native calls.
Recognition Engines
flutter/sherpa_onnx/lib/src/offline_recognizer.dart, online_recognizer.dart, keyword_spotter.dart, spoken_language_identification.dart
Added runtime guards across lifecycle methods (free, createStream, decode, getResult, isReady) to ensure SherpaOnnxBindings is initialized and pointers are non-null; throws on missing initialization, returns safe defaults when pointers are null.
Denoising
flutter/sherpa_onnx/lib/src/offline_speech_denoiser.dart, online_speech_denoiser.dart
Added initialization and null-pointer guards to factory, run, flush, reset, and free; updated sampleRate and frameShiftInSamples getters to block-bodied versions with defensive checks; improved output sample extraction logic.
Punctuation
flutter/sherpa_onnx/lib/src/offline_punctuation.dart, online_punctuation.dart
Added initialization checks and null-pointer guards to free and addPunct methods; returns empty string when pointer is null, throws on uninitialized bindings.
Speaker Identification
flutter/sherpa_onnx/lib/src/speaker_identification.dart
Added extensive initialization and null-pointer guards across SpeakerEmbeddingExtractor and SpeakerEmbeddingManager; updated numSpeakers and allSpeakerNames getters to block-bodied versions with initialization and null checks.
Text-to-Speech
flutter/sherpa_onnx/lib/src/tts.dart
Added initialization checks and null-pointer guards to free, generate, generateWithCallback, and generateWithConfig; converted sampleRate and numSpeakers getters to guarded block-bodied versions; updated callback handling for native interop.
Voice Activity Detection
flutter/sherpa_onnx/lib/src/vad.dart
Added initialization checks and null-pointer guards to CircularBuffer (destroy, push, get, size, head) and VoiceActivityDetector (free, acceptWaveform, isEmpty, isDetected, pop, clear, front, reset, flush); front returns empty SpeechSegment when ptr is null.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

size:L

Poem

🐰 Guards and checks, so wise and keen,
Null pointers cease to cause a scene,
Each binding verified with care,
No crashes left unaware,
Safety whispered through the code!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Refactor Dart API to check for nullptr' accurately captures the main objective of the changeset, which adds comprehensive null-pointer checks and initialization guards across all Dart API files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the Dart API by integrating robust null pointer checks and improved error handling mechanisms. The changes aim to enhance the stability and reliability of the sherpa-onnx Flutter bindings by preventing operations on uninitialized or invalid native pointers, thereby making the API more resilient and easier to debug for consumers.

Highlights

  • Enhanced Null Safety Checks: Implemented comprehensive null pointer checks across various Dart API methods that interact with native code. This ensures that operations are only attempted when the underlying native resources are properly initialized and valid.
  • Improved Error Handling: Introduced explicit exception throwing (e.g., 'Please initialize sherpa-onnx first' or 'Failed to create stream') when native bindings or pointers are null, providing clearer feedback to developers about initialization issues or invalid states.
  • Defensive Programming: Added early exit conditions (e.g., returning empty lists or default objects) in methods when ptr or stream.ptr are null, preventing potential crashes and ensuring more robust application behavior.
Changelog
  • flutter/sherpa_onnx/lib/src/audio_tagging.dart
    • Added null checks for native function bindings and instance pointers in free, createStream, and compute methods.
  • flutter/sherpa_onnx/lib/src/keyword_spotter.dart
    • Introduced null checks for native function bindings and instance pointers in free, createStream, isReady, getResult, decode, and reset methods.
  • flutter/sherpa_onnx/lib/src/offline_punctuation.dart
    • Implemented null checks for native function bindings and instance pointers in free and addPunct methods.
  • flutter/sherpa_onnx/lib/src/offline_recognizer.dart
    • Added null checks for native function bindings and instance pointers in free, setConfig, createStream, decode, and getResult methods.
  • flutter/sherpa_onnx/lib/src/offline_speaker_diarization.dart
    • Incorporated null checks for native function bindings and instance pointers in free, process, and processWithCallback methods.
  • flutter/sherpa_onnx/lib/src/offline_speech_denoiser.dart
    • Added null checks for native function bindings and instance pointers in the factory constructor, free, run, and sampleRate getter. Refined run method to handle null DenoisedAudio samples gracefully.
  • flutter/sherpa_onnx/lib/src/offline_stream.dart
    • Implemented null checks for native function bindings and instance pointers in free and acceptWaveform methods.
  • flutter/sherpa_onnx/lib/src/online_punctuation.dart
    • Introduced null checks for native function bindings and instance pointers in free and addPunct methods.
  • flutter/sherpa_onnx/lib/src/online_recognizer.dart
    • Added null checks for native function bindings and instance pointers in free, createStream, isReady, getResult, reset, decode, and isEndpoint methods.
  • flutter/sherpa_onnx/lib/src/online_speech_denoiser.dart
    • Incorporated null checks for native function bindings and instance pointers in the factory constructor, free, run, flush, reset, sampleRate getter, and frameShiftInSamples getter. Adjusted run and flush methods to handle null DenoisedAudio samples.
  • flutter/sherpa_onnx/lib/src/online_stream.dart
    • Implemented null checks for native function bindings and instance pointers in free, acceptWaveform, and inputFinished methods.
  • flutter/sherpa_onnx/lib/src/speaker_identification.dart
    • Added null checks for native function bindings and instance pointers across SpeakerEmbeddingExtractor and SpeakerEmbeddingManager methods and getters, including free, createStream, isReady, compute, add, addMulti, contains, remove, search, verify, numSpeakers, and allSpeakerNames.
  • flutter/sherpa_onnx/lib/src/spoken_language_identification.dart
    • Introduced null checks for native function bindings and instance pointers in free, createStream, and compute methods.
  • flutter/sherpa_onnx/lib/src/tts.dart
    • Implemented null checks for native function bindings and instance pointers in free, generate, generateWithCallback, generateWithConfig, sampleRate getter, and numSpeakers getter.
  • flutter/sherpa_onnx/lib/src/vad.dart
    • Added null checks for native function bindings and instance pointers across CircularBuffer and VoiceActivityDetector methods and getters, including free, push, get, pop, reset, size, head, acceptWaveform, isEmpty, isDetected, clear, front, and flush.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the Dart API to add checks for nullptr before using native pointers, which is a great improvement for robustness. However, the error handling for these null pointer checks is inconsistent across the codebase. In some cases, an exception is thrown, while in many others, the function fails silently by returning a default or empty value. This inconsistency can hide bugs and make debugging difficult. My review focuses on making this error handling consistent by throwing exceptions when an object is used after it has been freed. I've also pointed out opportunities to reduce code duplication for binding initialization checks and to use more specific exception messages.

Comment on lines +213 to +215
if (ptr == nullptr || stream.ptr == nullptr) {
return <AudioEvent>[];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

For consistency with other methods like createStream that throw exceptions on invalid state, this method should also throw an exception instead of returning an empty list. Using an object that has been freed is a programmer error and should be surfaced as an exception to avoid hiding potential bugs.

Suggested change
if (ptr == nullptr || stream.ptr == nullptr) {
return <AudioEvent>[];
}
if (ptr == nullptr || stream.ptr == nullptr) {
throw Exception('AudioTagging or stream has been freed and cannot be used.');
}

Comment on lines +228 to +230
if (ptr == nullptr || stream.ptr == nullptr) {
return false;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using a freed object (ptr or stream.ptr is nullptr) should result in an exception rather than a silent failure. This helps in identifying incorrect API usage early. Please throw an exception here for consistency with methods like createStream.

Suggested change
if (ptr == nullptr || stream.ptr == nullptr) {
return false;
}
if (ptr == nullptr || stream.ptr == nullptr) {
throw Exception('KeywordSpotter or stream has been freed and cannot be used.');
}

Comment on lines +243 to +245
if (ptr == nullptr || stream.ptr == nullptr) {
return KeywordResult(keyword: '');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Returning a default value when the object has been freed can hide bugs. It's better to throw an exception to signal that the object is in an invalid state and cannot be used.

Suggested change
if (ptr == nullptr || stream.ptr == nullptr) {
return KeywordResult(keyword: '');
}
if (ptr == nullptr || stream.ptr == nullptr) {
throw Exception('KeywordSpotter or stream has been freed and cannot be used.');
}

Comment on lines +268 to +270
if (ptr == nullptr || stream.ptr == nullptr) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This method should throw an exception if ptr or stream.ptr is nullptr, instead of returning silently. This ensures consistent error handling for invalid object states.

Suggested change
if (ptr == nullptr || stream.ptr == nullptr) {
return;
}
if (ptr == nullptr || stream.ptr == nullptr) {
throw Exception('KeywordSpotter or stream has been freed and cannot be used.');
}

Comment on lines +279 to +281
if (ptr == nullptr || stream.ptr == nullptr) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

To maintain consistency in error handling, please throw an exception here if the object or stream has been freed, instead of failing silently.

Suggested change
if (ptr == nullptr || stream.ptr == nullptr) {
return;
}
if (ptr == nullptr || stream.ptr == nullptr) {
throw Exception('KeywordSpotter or stream has been freed and cannot be used.');
}

Comment on lines +412 to +414
if (ptr == nullptr) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

For consistency and robustness, please throw an exception here if the VAD is used after being freed.

Suggested change
if (ptr == nullptr) {
return;
}
if (ptr == nullptr) {
throw Exception('VoiceActivityDetector has been freed and cannot be used.');
}

Comment on lines +423 to +425
if (ptr == nullptr) {
return SpeechSegment(samples: Float32List(0), start: 0);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Returning a default SpeechSegment for a freed VAD instance can hide bugs. It's safer to throw an exception to signal an invalid state.

Suggested change
if (ptr == nullptr) {
return SpeechSegment(samples: Float32List(0), start: 0);
}
if (ptr == nullptr) {
throw Exception('VoiceActivityDetector has been freed and cannot be used.');
}

Comment on lines +448 to +450
if (ptr == nullptr) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This method should throw an exception if the VAD has been freed, rather than returning silently. This helps in catching lifecycle management issues.

Suggested change
if (ptr == nullptr) {
return;
}
if (ptr == nullptr) {
throw Exception('VoiceActivityDetector has been freed and cannot be used.');
}

Comment on lines +459 to +461
if (ptr == nullptr) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

For consistency and robustness, please throw an exception here if the VAD is used after being freed.

Suggested change
if (ptr == nullptr) {
return;
}
if (ptr == nullptr) {
throw Exception('VoiceActivityDetector has been freed and cannot be used.');
}

Comment on lines +193 to +195
if (ptr == nullptr) {
throw Exception("Failed to create offline stream");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The exception message "Failed to create offline stream" is also used on line 202, but these two checks handle different error conditions. Using distinct messages would improve clarity and make debugging easier.

For example, here the error is that the AudioTagging instance itself is invalid. A more specific message could be:
throw Exception("AudioTagging instance is not valid. Cannot create stream.");

And for the check on line 202, where the native call fails:
throw Exception("Native offline stream creation failed.");

@gemini-code-assist

Copy link
Copy Markdown

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@csukuangfj
csukuangfj merged commit 250447e into k2-fsa:master Mar 17, 2026
1 check was pending
@csukuangfj
csukuangfj deleted the fix-dart branch March 17, 2026 04:48
csukuangfj pushed a commit that referenced this pull request Aug 10, 2026
Config-invalid (e.g. missing model files) makes native factory return null;
first method call then SIGSEGVs. require(ptr != 0L) in all binding classes
and streams, mirroring Java binding and Dart PR #3329.

Co-authored-by: Anna Medonosova <anna.medonosova@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant