[GH-ISSUE #5277] [Bug] Rizin first close fails when a detached short-lived inferior exits #3222

Closed
opened 2026-10-31 00:38:00 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @gensokyo-dev on GitHub (Oct 19, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5277

Before submitting

  • Searched open and closed issues; related lifecycle tracker #4227, separate process-token race #4322.
  • No credentials or sensitive target data included.

Area

Process capture or runtime observation

Observed behavior

Actual stdio MCP with Rizin 0.9.1: starting /usr/bin/true and immediately closing the session returns cleanup_incomplete on the first close. Explicit retry succeeds. This also occurred during a separate main 2dd5effe2 history audit; it remains reproducible on current main 1b3ac9424 after #5246.

Reproduction

Executed on Linux with an owned, durable PTY kept alive through cleanup:

  1. start_rizin_debug_session {"path":"/usr/bin/true","inferior_tty":"/dev/pts/<owned-terminal>"}.
  2. close_rizin_debug_session {"session_id":"<returned-id>"} → error below.
  3. Same close request → success, {"target_state":"unknown"}.

Latest minimal attempt: 1/1 first-close failures, then 1/1 successful explicit retries. No intervening target commands. The earlier main observation included four completed output commands and the same first-close failure. Owned process-family cleanup verified after recovery; OOM kills 0, 2 GiB hard limit.

Expected behavior

If the previously identified inferior exits during verified detach, recognize its proven end and close the owned debugger on the first call. Preserve failure/unknown handling when identity, permission, protocol or live-target TTY checks remain unresolved. Do not infer target ownership from a PID or path alone.

Impact and scope

A completed task needs an extra cleanup call and initially reports failure. Observed on this Linux/Rizin/coreutils combination; broader frequency and other engines/platforms are NOT_ENOUGH_INFO. No lost command Evidence or surviving process family was observed after retry. This report does not claim a hang or OOM.

REA version

1b3ac94242882e0fbf9c717806646c729abd8b91 (current main); earlier observation 2dd5effe2a641e354ad273138d0906a759fab9c3.

Runtime and platform

Node 24.18.0; Linux 6.1.0-53-cloud-amd64 x86-64; official Rizin 0.9.1 Linux static release, executable SHA-256 ab5614cf137608cffc5a3f4f471a91c995cfa7c0c35465bfb73876e5b95561ba.

Target and artifact context

Debian /usr/bin/true, ELF x86-64; SHA-256 c79bf44242829108e323378531f4ac839513ca1fba45efd6583643526e1e9fd2. The debugger launches this benign short-lived target; no attach to an existing process.

Interface

MCP

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

{
  "error": {
    "code": "cleanup_incomplete",
    "category": "unsupported_provider",
    "message": "This analysis is unavailable for the current target. Choose another analysis or target.",
    "retryable": false,
    "remediation": {
      "action": "This analysis is unavailable for the current target. Choose another analysis or target."
    },
    "details": {
      "provider_id": "rizin",
      "operation": "close_rizin_debug_session",
      "reason": "The owned Rizin process could not be confirmed stopped: Owned Rizin debugger inferior detach could not be verified: ENOENT: no such file or directory, open '/proc/1790690/stat'",
      "cleanup": "incomplete",
      "resources": [
        "b6a02503-5807-4e41-9349-2d3a4827ca27"
      ],
      "cleanup_reason": "Owned Rizin debugger inferior detach could not be verified: ENOENT: no such file or directory, open '/proc/1790690/stat'",
      "execution_failure": "capability_unavailable"
    }
  }
}

Collected through the actual SDK stdio transport, not a simulated provider. Earlier observation.

Typed outcome or recovery expected

Successful existing close result after proving the original inferior ended; otherwise retain the owned debugger and a meaningful retryable cleanup state. No new target-state assertion is required.

Analysis or suspected cause

Source-derived: #detachInferiorUnlocked confirms an empty native descriptor inventory after o-, then unconditionally reads /proc/<pid>/stat and output descriptors again. Hypothesis: the detached true exits before these post-detach checks. The precise failing read is not yet instrumented. The shared verifyOwnedInferiorsEnded already distinguishes a previously identified process ending from an unknown identity; investigate reuse instead of retries or weaker TTY checks.

Additional context

Last known good / first bad commit: NOT_ENOUGH_INFO. Initial bug observed independently of #5246; no cleanup code was changed there. Next checks: deterministic exit-during-detach regression, malformed/permission/PID-reuse controls, and real first-close plus live-inferior durable-output verification.

Originally created by @gensokyo-dev on GitHub (Oct 19, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5277 ### Before submitting - [x] Searched open and closed issues; related lifecycle tracker #4227, separate process-token race #4322. - [x] No credentials or sensitive target data included. ### Area Process capture or runtime observation ### Observed behavior Actual stdio MCP with Rizin 0.9.1: starting `/usr/bin/true` and immediately closing the session returns `cleanup_incomplete` on the first close. Explicit retry succeeds. This also occurred during a separate main `2dd5effe2` history audit; it remains reproducible on current main `1b3ac9424` after #5246. ### Reproduction Executed on Linux with an owned, durable PTY kept alive through cleanup: 1. `start_rizin_debug_session {"path":"/usr/bin/true","inferior_tty":"/dev/pts/<owned-terminal>"}`. 2. `close_rizin_debug_session {"session_id":"<returned-id>"}` → error below. 3. Same close request → success, `{"target_state":"unknown"}`. Latest minimal attempt: 1/1 first-close failures, then 1/1 successful explicit retries. No intervening target commands. The earlier main observation included four completed output commands and the same first-close failure. Owned process-family cleanup verified after recovery; OOM kills 0, 2 GiB hard limit. ### Expected behavior If the previously identified inferior exits during verified detach, recognize its proven end and close the owned debugger on the first call. Preserve failure/unknown handling when identity, permission, protocol or live-target TTY checks remain unresolved. Do not infer target ownership from a PID or path alone. ### Impact and scope A completed task needs an extra cleanup call and initially reports failure. Observed on this Linux/Rizin/coreutils combination; broader frequency and other engines/platforms are NOT_ENOUGH_INFO. No lost command Evidence or surviving process family was observed after retry. This report does not claim a hang or OOM. ### REA version `1b3ac94242882e0fbf9c717806646c729abd8b91` (current main); earlier observation `2dd5effe2a641e354ad273138d0906a759fab9c3`. ### Runtime and platform Node 24.18.0; Linux 6.1.0-53-cloud-amd64 x86-64; official Rizin 0.9.1 Linux static release, executable SHA-256 `ab5614cf137608cffc5a3f4f471a91c995cfa7c0c35465bfb73876e5b95561ba`. ### Target and artifact context Debian `/usr/bin/true`, ELF x86-64; SHA-256 `c79bf44242829108e323378531f4ac839513ca1fba45efd6583643526e1e9fd2`. The debugger launches this benign short-lived target; no attach to an existing process. ### Interface MCP ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence ```json { "error": { "code": "cleanup_incomplete", "category": "unsupported_provider", "message": "This analysis is unavailable for the current target. Choose another analysis or target.", "retryable": false, "remediation": { "action": "This analysis is unavailable for the current target. Choose another analysis or target." }, "details": { "provider_id": "rizin", "operation": "close_rizin_debug_session", "reason": "The owned Rizin process could not be confirmed stopped: Owned Rizin debugger inferior detach could not be verified: ENOENT: no such file or directory, open '/proc/1790690/stat'", "cleanup": "incomplete", "resources": [ "b6a02503-5807-4e41-9349-2d3a4827ca27" ], "cleanup_reason": "Owned Rizin debugger inferior detach could not be verified: ENOENT: no such file or directory, open '/proc/1790690/stat'", "execution_failure": "capability_unavailable" } } } ``` Collected through the actual SDK stdio transport, not a simulated provider. [Earlier observation](https://github.com/morluto/rea/issues/4227#issuecomment-6273199435). ### Typed outcome or recovery expected Successful existing close result after proving the original inferior ended; otherwise retain the owned debugger and a meaningful retryable cleanup state. No new target-state assertion is required. ### Analysis or suspected cause Source-derived: [`#detachInferiorUnlocked`](https://github.com/morluto/rea/blob/1b3ac94242882e0fbf9c717806646c729abd8b91/src/rizin/RizinDebugSessionManager.ts#L1155) confirms an empty native descriptor inventory after `o-`, then unconditionally reads `/proc/<pid>/stat` and output descriptors again. Hypothesis: the detached `true` exits before these post-detach checks. The precise failing read is not yet instrumented. The shared `verifyOwnedInferiorsEnded` already distinguishes a previously identified process ending from an unknown identity; investigate reuse instead of retries or weaker TTY checks. ### Additional context Last known good / first bad commit: NOT_ENOUGH_INFO. Initial bug observed independently of #5246; no cleanup code was changed there. Next checks: deterministic exit-during-detach regression, malformed/permission/PID-reuse controls, and real first-close plus live-inferior durable-output verification.
bsakaguchi 2026-10-31 00:38:00 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3222
No description provided.