[GH-ISSUE #8023] [Bug] A GDB console command whose output is one MI line over 16 MiB ends the session with no way to detach, kill or close it #4659

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

Originally created by @Rinkia on GitHub (Oct 29, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8023

Before submitting

  • I searched the open and closed issues for a related report (MI line, protocol limit, gdb cleanup_incomplete, "GDB MI state is not synchronized", gdb output limit). Related but different: #5761 (closed, shell output without a trailing newline timed out), #6661 (closed, queued console follower blocked close).
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Debugging (GDB sessions)

Observed behavior

In a persistent GDB session, print of a large value with set print elements 0 makes GDB emit a single ~"..." console record longer than 16 MiB. REA's MI reader then fails the session (GdbSessionManager.ts, "GDB emitted an MI line exceeding the 16777216 byte (16 MiB) protocol limit"). From that point:

  • The failing gdb_console call and every later call on that session, including kill, detach and print, return cleanup_incomplete with the message "This analysis is unavailable for the current target. Choose another analysis or target." The reason in details is accurate, but the top-level message and remediation don't describe the situation.
  • close_gdb_session fails with the same code: "Owned GDB inferior detach could not be verified: GDB MI state is not synchronized; inferior state is unknown." This happens even though a verified inferior_tty was set, and gdb_session_status still reports inferior_tty_verified: true.
  • The GDB process and the stopped inferior stay alive as long as the MCP server runs. A new start_gdb_session in the same server succeeds, so the leftover pair isn't obvious.
  • When stdin closes, the server logs "REA could not close cleanly. End the REA process before starting it again." and doesn't exit on SIGTERM. Only SIGKILL ends it. GDB then finishes writing and exits.

docs/reverse-engineering-tools.md says command output "is retained up to 16 MiB and explicitly marked when truncated". That holds for many records (output_truncated and the cap limitation), but not for one record over the line limit. The GDB section doesn't mention that a single long line ends the session.

Reproduction

Self-written probe, built in a Linux x64 container (--network none, --cap-add SYS_PTRACE), Ubuntu 24.04, GNU gdb 15.1, rea-agents@6.8.0 and main at 45cc93596. Both give the same result.

/* utf8.c */
#include <stdio.h>
unsigned char bad[] = { 'o', 'k', 0xff, 0 };
int big[4000000];
__attribute__((noinline)) void stop_here(void) { puts("probe"); }
int main(void) { for (int i = 0; i < 4000000; i++) big[i] = i; stop_here(); return 0; }

gcc -g -O0 -o /p/utf8 utf8.c, then over MCP:

start_gdb_session {"inferior_tty":"/dev/pts/0"}
gdb_console "set print elements 0"
gdb_console "set print repeats 0"
gdb_console "set max-value-size unlimited"
gdb_console "file /p/utf8"
gdb_console "break stop_here"
gdb_console "run"            -> stopped at breakpoint, fine
gdb_console "print big"      -> cleanup_incomplete (MI line over 16 MiB)
gdb_console "kill"           -> cleanup_incomplete
close_gdb_session            -> cleanup_incomplete

ps afterwards shows gdb --nx --quiet --interpreter=mi3 (state S) and /p/utf8 (state t) still present under the server.

Plain gdb -batch with the same commands prints the array (about 30 MB on one line) and continues.

Expected behavior

One oversized record shouldn't cost the session. MI records end at LF, so the reader could drop the rest of that line until the next newline, mark the command output_truncated with a limitation that names the line limit, and keep the session usable. If REA keeps failing closed instead, the session should still offer a way out. For example, close could terminate the directly owned GDB process (the inferior's fate then follows ptrace detach-on-exit, which close can report as unknown). The top-level error message should say the session was lost because of the line limit.

Impact and scope

The persistent GDB session tools on Linux. Reaching it requires a single console record over 16 MiB, which print produces once print elements is unlimited (GDB's default of 200 elements keeps it small), for example when dumping a large buffer. I didn't check other sources of long lines, and I didn't check the Rizin debug session, which documents its own 16 MiB frame cap.

Originally created by @Rinkia on GitHub (Oct 29, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8023 ### Before submitting - [x] I searched the open and closed issues for a related report (MI line, protocol limit, gdb cleanup_incomplete, "GDB MI state is not synchronized", gdb output limit). Related but different: #5761 (closed, shell output without a trailing newline timed out), #6661 (closed, queued console follower blocked close). - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Debugging (GDB sessions) ### Observed behavior In a persistent GDB session, `print` of a large value with `set print elements 0` makes GDB emit a single `~"..."` console record longer than 16 MiB. REA's MI reader then fails the session (`GdbSessionManager.ts`, "GDB emitted an MI line exceeding the 16777216 byte (16 MiB) protocol limit"). From that point: - The failing `gdb_console` call and every later call on that session, including `kill`, `detach` and `print`, return `cleanup_incomplete` with the message "This analysis is unavailable for the current target. Choose another analysis or target." The reason in `details` is accurate, but the top-level message and remediation don't describe the situation. - `close_gdb_session` fails with the same code: "Owned GDB inferior detach could not be verified: GDB MI state is not synchronized; inferior state is unknown." This happens even though a verified `inferior_tty` was set, and `gdb_session_status` still reports `inferior_tty_verified: true`. - The GDB process and the stopped inferior stay alive as long as the MCP server runs. A new `start_gdb_session` in the same server succeeds, so the leftover pair isn't obvious. - When stdin closes, the server logs "REA could not close cleanly. End the REA process before starting it again." and doesn't exit on SIGTERM. Only SIGKILL ends it. GDB then finishes writing and exits. `docs/reverse-engineering-tools.md` says command output "is retained up to 16 MiB and explicitly marked when truncated". That holds for many records (`output_truncated` and the cap limitation), but not for one record over the line limit. The GDB section doesn't mention that a single long line ends the session. ### Reproduction Self-written probe, built in a Linux x64 container (`--network none`, `--cap-add SYS_PTRACE`), Ubuntu 24.04, GNU gdb 15.1, `rea-agents@6.8.0` and `main` at `45cc93596`. Both give the same result. ```c /* utf8.c */ #include <stdio.h> unsigned char bad[] = { 'o', 'k', 0xff, 0 }; int big[4000000]; __attribute__((noinline)) void stop_here(void) { puts("probe"); } int main(void) { for (int i = 0; i < 4000000; i++) big[i] = i; stop_here(); return 0; } ``` `gcc -g -O0 -o /p/utf8 utf8.c`, then over MCP: ``` start_gdb_session {"inferior_tty":"/dev/pts/0"} gdb_console "set print elements 0" gdb_console "set print repeats 0" gdb_console "set max-value-size unlimited" gdb_console "file /p/utf8" gdb_console "break stop_here" gdb_console "run" -> stopped at breakpoint, fine gdb_console "print big" -> cleanup_incomplete (MI line over 16 MiB) gdb_console "kill" -> cleanup_incomplete close_gdb_session -> cleanup_incomplete ``` `ps` afterwards shows `gdb --nx --quiet --interpreter=mi3` (state `S`) and `/p/utf8` (state `t`) still present under the server. Plain `gdb -batch` with the same commands prints the array (about 30 MB on one line) and continues. ### Expected behavior One oversized record shouldn't cost the session. MI records end at LF, so the reader could drop the rest of that line until the next newline, mark the command `output_truncated` with a limitation that names the line limit, and keep the session usable. If REA keeps failing closed instead, the session should still offer a way out. For example, close could terminate the directly owned GDB process (the inferior's fate then follows ptrace detach-on-exit, which close can report as unknown). The top-level error message should say the session was lost because of the line limit. ### Impact and scope The persistent GDB session tools on Linux. Reaching it requires a single console record over 16 MiB, which `print` produces once `print elements` is unlimited (GDB's default of 200 elements keeps it small), for example when dumping a large buffer. I didn't check other sources of long lines, and I didn't check the Rizin debug session, which documents its own 16 MiB frame cap.
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#4659
No description provided.