Repository navigation
rive_native 0.2.0-dev.3: dispose clears session state before detach, retaining screen-target recorders #660
Description
Submission checklist
- I have confirmed the issue is present in the latest version of the
riveFlutter package - I have searched the documentation and forums and could not find an answer
- I have searched existing issues and this is not a duplicate
Description
The published rive_native 0.2.0-dev.3 source contains an unreachable deferred-session detach in _NativeRenderTexture.dispose() (lib/src/rive_native_ffi.dart, around line 203).
_rendererPtr is set to nullptr and _appliedSessionAddress to 0 before the conditional that calls _textureUseDeferredSession(_rendererPtr, nullptr). That conditional can therefore never succeed.
For a rendered texture attached to a deferred session that remains alive, normal disposal falls through to delayed native host destruction. DeferredTextureHost::~DeferredTextureHost() calls detach(this) but intentionally does not release the screen target. The normal release path is useDeferredSession(nullptr) -> leaveDeferredSession() -> releaseScreenTarget().
Consequently, the session retains the target's entry in m_screenRenderers, its target ID is not returned to m_freeScreenTargets, and attachedTargetCount() can stay overstated as textures are replaced.
Expected behavior: detach on the recording thread while the renderer/session state is still valid, using the existing native drain-and-release path, then clear the Dart pointer and session marker before scheduling platform removal.
This is a source-level report. I confirmed the control-flow defect in the unmodified published archive and checked the native ownership path; I am not claiming a new device reproduction, quantified memory growth, or an OOM/ANR caused by this particular defect.
Reproduction steps / code
Source-level reproduction:
- Download the exact published archive: https://pub.dev/api/archives/rive_native-0.2.0-dev.3.tar.gz
- Inspect
_NativeRenderTexture.dispose()inlib/src/rive_native_ffi.dart:
_disposed = true;
_rendererPtr = nullptr;
_appliedSessionAddress = 0;
// listener removal and attachment bookkeeping
if (_appliedSessionAddress != 0 && _rendererPtr != nullptr) {
_textureUseDeferredSession(_rendererPtr, nullptr);
}
_rendererPtr = nullptr;
_appliedSessionAddress = 0;The detach guard is always false, regardless of the state when dispose began.
- Inspect
native/src/deferred_host.cpp: the destructor only callsdetach(this);leaveDeferredSession()callsreleaseScreenTarget(m_screenTarget). Inruntime/renderer/include/rive/renderer/cmd/deferred_session.hpp, that release erases the recorder and recycles the target ID.
Minimal proposed fix: remove the first _rendererPtr = nullptr and _appliedSessionAddress = 0 assignments. Keep the guarded detach and the later assignments, so native drain/release runs on the recording thread before Dart drops the addresses.
A downstream patch using this ordering matches the original archive and is idempotent. Runtime validation should repeatedly create, draw and dispose textures sharing a surviving deferred session and check that target/recorder counts return to baseline. That device validation has not been performed for this report.
Upload your reproduction files / stack trace
No response
Source .riv / .rev file
No response
Screenshots / video
No response
Rive Flutter package version
rive 0.15.0-dev.3 / rive_native 0.2.0-dev.3 (latest prerelease)
Flutter version
Flutter 3.47.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 6a19cca564 (13 days ago) • 2026-09-17 14:13:22 -0400
Engine • hash ab598368592da0064197e2bc15c7f5b0a2c6bb1f (revision af7e796e16) (13 days ago) • 2026-09-16 18:35:09.000Z
Tools • Dart 3.13.4 • DevTools 2.60.0
Device
Apple Silicon Mac: source inspection and patch-tool tests only; no new device reproduction
OS version
macOS 27.0 (inspection host); shared native deferred-texture path
Additional context
Verified against the unmodified published archive, SHA-256: 0acff64554fc0973a6624daa0b0c0261ec00cde744df4b9e3daea2fa8a7b85a8.
The minimal reorder uses the existing native synchronization. Synchronous detach can still wait for queued GPU work; this report does not establish its device performance.
The latest prerelease versions were checked on 2026-09-30; this report concerns the exact dev.3 source.
Activity