# ✅ Peer Review Report: M2 PTY _exit Syscall Symbol Correction (Commit f0e2bd2) **Job**: `cc09bae5` · **Reviewer**: Reviewer B (Cline, `canary-projects-multi-agent-mux-reviewer-cline`) **Review Target**: Commit `f0e2bd2` — "fix(ui): correct libc symbol lookup for direct _exit syscall to achieve async-signal-safety" **Prior Reviews**: - Job `66ec158f` (b7901bc) → 3 BLOCKING 결함 지적 - Job `fcf4c9d0` (f52f6eb) → DEFECT 1/2 해결, DEFECT 3 미해결 - Job `7448cb2f` (7781e79) → async-signal-safety/waitpid 해결, DEFECT 3 미해결 (3회차) - Job `ef0b32ff` (7f1a7e5) → **DEFECT 3 해결 (4회차) + 모든 결함 PASS** — 본 커밋은 ef0b32ff 리뷰의 NON-BLOCKING 관찰 #1 정밀 수정 **Plan Reference**: `.agents/reports/canary-projects-multi-agent-mux-planner-reviewer-claude/report-final.md` (Rev.3, §6.7 PTY 메커니즘 / §10 DoD) **Review Scope**: 브리프가 명시한 `cExit` lookup 심볼 오타 수정 (`'exit'` → `'_exit'`) 검증 + 회귀 확인 **Method**: 라인 단위 diff 분석 + `dart analyze`/`flutter analyze`/`dart test` + **`_exit` 심볼 glibc resolve实证** + TMUX env 격리 회귀实证 --- ## 1. 커밋 개요 커밋 `f0e2bd2`는 이전 리뷰(ef0b32ff)의 NON-BLOCKING 관찰 #1을 정밀 수정. 1개 파일, +1/-1행 (단일 라인 변경). **변경 내용** (`pty_session.dart:111`): ```diff - final cExit = libc.lookupFunction<_exit_c, _exit_dart>('exit'); + final cExit = libc.lookupFunction<_exit_c, _exit_dart>('_exit'); ``` --- ## 2. 수정 항목 교차 검증 ### 2.1 이전 리뷰 관찰 (ef0b32ff, NON-BLOCKING #1) > **`cExit` lookup 이름 (정확성)**: 라인 111 `lookup('exit')`는 C `exit()`를 바인딩 (async-signal-unsafe, atexit handlers 실행). 브리프가 "libc exit syscall"이라고 서술했으나, 진정한 async-signal-safe는 `lookup('_exit')` 또는 `lookup('_Exit')`. 단, 자식이 fork 직후이므로 Dart 런타임 atexit handlers가 미등록 상태이며, 기능적으로 자식 종료를 달성하므로 실질적 영향 없음. 향후 정확성을 위해 `_exit` 권장. ### 2.2 수정 검증 **diff 분석**: 라인 111에서 `lookup('exit')` → `lookup('_exit')`로 정확히 1행 수정. 다른 라인 무변경 ✅. **C `exit()` vs `_exit()` 구분**: - `exit(int status)` (stdlib.h): async-signal-**unsafe** — `atexit()` 등록 핸들러 실행, `stdio` 버퍼 flush, `_exit()` 최종 호출 - `_exit(int status)` (unistd.h): async-signal-**safe** — 커널 syscall 직접 호출, 버퍼 flush/handlers 미실행 POSIX async-signal-safety 규칙에 따르면, fork 후 exec 실패 시 자식에서 호출할 수 있는 함수는 async-signal-safe 목록에 있는 함수만. `_exit()`는 이 목록에 포함되나, `exit()`는 포함되지 않음. 본 수정으로 자식 분기의 예외 퇴장 경로(`cExit(-1)` at 라인 192, `cExit(-2)` at 라인 211)가 진정한 async-signal-safe `_exit` syscall을 사용하게 됨. **FFI 시그니처 일관성**: typedef `_exit_c = ffi.Void Function(ffi.Int32 status)` / `_exit_dart = void Function(int status)`는 C `_exit(int)` 시그니처와 정확히 일치 ✅. 변경 전에도 시그니처는 `_exit` 기준이었으나 lookup 이름만 `exit`였던 불일치가 해결됨. --- ## 3. `_exit` 심볼 glibc resolve实证 **검증 방법**: `nm -D /lib/x86_64-linux-gnu/libc.so.6`로 glibc에서 `_exit` 심볼 존재 확인 + Dart FFI `lookupFunction<_exit_c, _exit_dart>('_exit')` 실행实证. **결과 1 — glibc 심볼 확인**: ``` $ nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep -w '_exit' 00000000000f7480 T _exit@@GLIBC_2.2.5 ``` `T` (Text segment, exported symbol) — `_exit`가 glibc에 존재하며 export됨 ✅. **결과 2 — Dart FFI lookup实证**: ``` SUCCESS: _exit symbol resolved from libc.so.6 - async-signal-safe exit syscall available (lookupFunction throws if symbol not found, so reaching here means _exit is bound) ``` `lookupFunction<_exit_c, _exit_dart>('_exit')`가 예외 없이 성공 — 런타임에 `_exit` 심볼이 올바르게 바인딩됨을实证 ✅. `lookupFunction`은 심볼을 찾지 못하면 `ArgumentError`를 throw하므로, 정상 실행 자체가 resolve 성공의 증거. **평가**: ✅ `lookup('_exit')`가 glibc의 `_exit@@GLIBC_2.2.5` 심볼을 올바르게 바인딩. 런타임에 자식 분기의 `cExit(-1)`/`cExit(-2)` 호출이 진정한 async-signal-safe `_exit` syscall을 기동함. --- ## 4. 정적 분석 및 회귀 검증 | 항목 | 검증 방법 | 결과 | |------|----------|------| | `dart analyze` (mam_pty) | 실행 | ✅ No issues found! | | `flutter analyze` (mam_desktop) | 실행 | ✅ No issues found! | | M1 회귀 (`dart test` mam_core) | 실행 | ✅ 3/3 All tests passed | | 런타임 PTY 동작 (`dart test` echo) | 실행 | ✅ echo `hello-pty-ok` 출력 정상 | | DEFECT 3 TMUX env 격리 (회귀) | 런타임实证 (TMUX 설정 + printenv) | ✅ PASS — 자식 printenv 빈 출력 (회귀 없음) | | `_exit` 심볼 glibc resolve | `nm -D` + Dart FFI lookup实证 | ✅ `_exit@@GLIBC_2.2.5` 바인딩 성공 | | 기존 스크립트 회귀 | git diff --stat | ✅ status.sh 외 기존 스크립트 무변경 | **전체 테스트 실행 결과** (부모에 `TMUX=fake-server,12345,0 TMUX_PANE=%5` 설정): ``` 00:00 +0: test/pty_runtime_test.dart: PtySession runtime execution resolves process output PTY Runtime stdout verified: hello-pty-ok 00:00 +1: test/pty_runtime_test.dart: PtySession strips TMUX/TMUX_PANE from child environment printenv TMUX TMUX_PANE output: [] 00:00 +2: All tests passed! ``` 이전 리뷰(ef0b32ff)에서 PASS 판정된 모든 기능이 회귀 없이 유지됨: - DEFECT 1 (/proc/self/fd 경로): ✅ 유지 - DEFECT 2 (자식 stdio PTY 연결): ✅ 유지 - DEFECT 3 (TMUX env 격리, unsetenv): ✅ 유지 (회귀 없음) - async-signal-safety: ✅ 유지 + `_exit` 정확성 향상 - waitpid zombie reaping (blocking): ✅ 유지 - non-blocking master fd (fcntl): ✅ 유지 --- ## 5. AGENTS.md 원칙 검증 - **Surgical Changes (§3)**: 단일 라인 수정 (`'exit'` → `'_exit'`) — 이전 리뷰 관찰에 정확히 대응하는 최소 변경 ✅. 다른 코드/포맷/주석 무변경. "Every changed line should trace directly to the user's request" — 본 수정은 1행이며 리뷰 관찰 #1에 직접 추적됨. - **Simplicity First (§2)**: 단일 라인 정밀 수정 — 더 단순할 수 없는 최소 변경 ✅. - **Goal-Driven Execution (§4)**: 본 수정의 성공 기준은 "async-signal-safe `_exit` syscall 바인딩" → `nm -D` + Dart FFI lookup实证으로 검증 완료 ✅. - **Think Before Coding (§1)**: 이전 리뷰(ef0b32ff)에서 `exit()` vs `_exit()`의 async-signal-safety 차이를 명확히 지적했으며, 주 개발자가 이를 정확히 이해하고 수정 — §1 원칙 이행. --- ## 6. 종합 평가 커밋 `f0e2bd2`는 이전 리뷰(ef0b32ff)의 NON-BLOCKING 관찰 #1을 **정확히 단일 라인으로 해결**: ### 수정 항목 — 해결 1. ✅ **`cExit` lookup 심볼 정확성**: `lookup('exit')` → `lookup('_exit')`로 수정. C `exit()` (async-signal-unsafe, atexit handlers 실행) 대신 C `_exit()` (async-signal-safe, 커널 syscall 직접 호출)를 바인딩. 자식 분기의 예외 퇴장 경로(`cExit(-1)` slave open 실패, `cExit(-2)` execvp 실패)가 진정한 async-signal-safe `_exit` syscall을 사용. ### 검증 결과 - `dart analyze`: No issues found ✅ - `flutter analyze`: No issues found ✅ - M1 회귀: 3/3 All tests passed ✅ - 런타임 PTY echo: 정상 동작 ✅ - 런타임 TMUX env 격리: ✅ PASS (회귀 없음) - **`_exit` 심볼 glibc resolve实证**: ✅ `_exit@@GLIBC_2.2.5` 바인딩 성공 (nm -D + Dart FFI lookup) - 기존 스크립트 회귀: 없음 ✅ ### 전체 리뷰 이력 (5회차 누적) | 회차 | 커밋 | 판정 | 핵심 | |------|------|------|------| | 1 (66ec158f) | b7901bc | NOT PASS | 3 BLOCKING 결함 지적 | | 2 (fcf4c9d0) | f52f6eb | NOT PASS | DEFECT 1/2 해결, DEFECT 3 미해결 | | 3 (7448cb2f) | 7781e79 | NOT PASS | async-signal-safety/waitpid 해결, DEFECT 3 미해결 | | 4 (ef0b32ff) | 7f1a7e5 | **PASS** | DEFECT 3 해결 (unsetenv), 모든 결함 해결 | | 5 (본 리뷰) | f0e2bd2 | **PASS** | NON-BLOCKING 관찰 #1 정밀 수정 (_exit 심볼) | ef0b32ff에서 PASS 판정된 모든 기능이 회귀 없이 유지되며, 추가로 `_exit` syscall 바인딩 정확성이 향상됨. M2 마일스톤(Desktop PTY 연동 + attach terminal tab)의 모든 핵심 계약(§6.7 PTY 메커니즘, §10 DoD)이 런타임实证으로 검증됨. 정적 분석과 런타임实证 테스트가 모두 통과. [VERDICT: PASS]