8.5 KiB
✅ 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: 브리프가 명시한cExitlookup 심볼 오타 수정 ('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):
- 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)
cExitlookup 이름 (정확성): 라인 111lookup('exit')는 Cexit()를 바인딩 (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
_exitsyscall 바인딩" →nm -D+ Dart FFI lookup实证으로 검증 완료 ✅. - Think Before Coding (§1): 이전 리뷰(ef0b32ff)에서
exit()vs_exit()의 async-signal-safety 차이를 명확히 지적했으며, 주 개발자가 이를 정확히 이해하고 수정 — §1 원칙 이행.
6. 종합 평가
커밋 f0e2bd2는 이전 리뷰(ef0b32ff)의 NON-BLOCKING 관찰 #1을 정확히 단일 라인으로 해결:
수정 항목 — 해결
- ✅
cExitlookup 심볼 정확성:lookup('exit')→lookup('_exit')로 수정. Cexit()(async-signal-unsafe, atexit handlers 실행) 대신 C_exit()(async-signal-safe, 커널 syscall 직접 호출)를 바인딩. 자식 분기의 예외 퇴장 경로(cExit(-1)slave open 실패,cExit(-2)execvp 실패)가 진정한 async-signal-safe_exitsyscall을 사용.
검증 결과
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]