deadline超過時にRST_STREAM(CANCEL)でstreamのみ閉じてpersistent connectionを温存 - #29
Conversation
- cancel_grpc_call_stream()を追加し、unaryのsocket timeout分岐をmark_connection_deadから置き換え - streaming cancel経路が期限切れcall deadlineでRSTを書けていなかった潜在バグを修正 (RST書き込みは50ms grace deadline) - persistent connection reuse時にsetup_deadline_abs_usを採用コールのdeadlineへ更新 (期限切れdeadline残留による後続コール即ETIMEDOUTを解消) - wire.frame_outトレースにRST_STREAMのerror_codeを追加 - PHPT 033: timeout後のRST_STREAM(CANCEL)ワイヤ観測と同一persistent connection再利用を固定 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- REVIEW-20260711-001 (High): setup_deadline_abs_usをconnection setup完了時に0へクリアし、reuse時のdeadline上書きを撤回。connection-scopedなwrite fallbackが他コールの期限切れdeadlineを借用して並行streamを殺すscope違反を解消 - REVIEW-20260711-002 (Medium): RST送出成功で接続を温存する場合にconnection側のlast_error_detail / last_io_errno / last_ssl_errorをクリアし、後続コールのstatus detailsへの漏れを防止 - REVIEW-20260711-003 (Low): grace deadlineが「pending frame一式のflush上限」であることをコメントとissue Decision Logに明記 - REVIEW-20260711-004 (Low): locally_cancelled flagを追加し、自送出RSTでmid-messageに閉じたstreamのtruncated-body誤判定(malformed_response_frame偽陽性)を除外 - REVIEW-20260711-005 (Low): PHPT 033のtimeout/delayマージンを300ms/2000msへ拡大し、RST_STREAMのstream帰属assertionを追加 - REVIEW-20260711-006 (DD): SPEC §4.2のreuse安全性根拠をnghttp2 closed-stream処理主体に書き分け - PHPT 033に並行ケースを追加: deadlineなしin-flight streamingが同一connection上の別コールのdeadline超過を生き延びることを固定 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…D 1 → 全件Fixed、再レビューall clear) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
敵対的レビュー結果です。元 issue の scope 内で、merge 前に High 1件 / Medium 1件の対応を推奨します。あわせて回帰テストの Low 1件があります。 High — RST flush失敗後は dead/fatal session を全ownerでterminalにする対象: このflushがpartial/failedになるとconnectionはdeadになりますが、同じconnectionを保持する別のserver-streaming callは、次のpullで dead/fatal-session後は全ownerからsocket/nghttp2 I/Oを禁止してterminalへ遷移させ、RST submit・0-byte/partial flush失敗をfault injectionで固定してください。 Medium — 64KiB backlog時のconnection reuse保証を満たすか、仕様を限定する対象: cancel済みstreamのresponse DATAが64KiB到着済みのケースでは、RST送出後のpreflightが65,536 bytesを読んだ時点で上限に達し、EAGAIN boundaryを確認せずconnectionをdrainingにします。 未読bytes中のGOAWAYを処理してから新規HEADERSを許すbounded adoptionを実装するか、reuseをbest-effortと明記してcap fallbackをテストしてください。現記述は実装の保証範囲を超えています。 Low — survivorをtimeout RST後までactiveに残す対象: 3 messagesを100ms間隔で送る現在の条件では、残りのDATA/trailersが約200msで処理され、300ms deadlineのRSTより約100ms先にsurvivorがcloseしています。そのため、RST時点のmultiplex、RST後のread/WINDOW_UPDATE、deadline scopeの非漏洩を検証できていません。survivorのdelayをdeadlineより長くし、terminal HEADERSがRSTより後であること、survivor宛RSTがないこと、最終 補足: |
…t明記 / multiplexテスト強化 - REVIEW-20260711-007 (High): connection_io_allowed()を追加し、server streaming pullループ先頭でdead connectionをterminal化。send_pending_h2_frames_with_deadlineにもdead時の早期エラーreturnを追加し、partial frame後のsession再駆動とdeadlineなしcallのhangを防止。drainingはGOAWAY admit済みstreamの完走を許す - REVIEW-20260711-008 (Medium): SPEC §4.2にreuseがbest-effortであること(preflight drain cap 64KiB超過時はdraining→新規接続fallback)を明記。PHPT 035でbacklog超過時のfallback安全性(follow-up OK / persistent_reused=false / preface 2本)を固定 - REVIEW-20260711-009 (Low): PHPT 033 part 4のsurvivor delayを700msへ拡大し、survivor宛RSTなし・terminal HEADERSが並行RST後・全message受信OKをワイヤ順序でassert - fixture :50066追加 (1本目のstreamへmessage送出後保持、2本目のrequestでTCP切断): PHPT 034でdead-under-another-owner不変条件(dead後のwire I/Oゼロ)を固定 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3件とも妥当と判断し、0480479 で対応しました。レビュー記録は High — dead/fatal sessionの全owner terminal化 → 対応指摘どおり、streaming pullループは fault injection について: RST submit失敗・partial flush失敗を現行harnessで決定的に再現する手段がない(socket buffer詰まり依存)ため、fixture Medium — 64KiB backlog時のreuse保証 → 仕様を限定(選択肢b)実測どおり、backlogがdrain cap(64KiB / 64 iterations)を超えるとEAGAIN境界に達せずdraining → 新規接続になります。bounded adoption(未読GOAWAY処理後のadmit)は本PRのスコープ(deadline時の接続温存)を超えるため実装せず、SPEC §4.2 に reuseはbest-effort であることとcap fallback挙動を明記しました。PHPT 035(64KiB×200 messages + user cancel → follow-upがSTATUS_OK / Low — survivorをRST後まで生存 → 対応survivor delayを700msへ拡大し(trailersは並行RSTの約1秒後)、トレースで (1) survivor宛 検証
🤖 Generated with Claude Code |
|
再レビューしました(HEAD ただし、以下 High 2 / Medium 2 が残るため、現時点では REQUEST_CHANGES 相当です。 [High] nghttp2 fatal return後はcleanupでもsessionへ触れないでください新しいcancel helperで [High] draining上のadmit済みstreamも解放前にRSTで閉じてください
[Medium] shared connection deathはsurvivorにもUNAVAILABLEとして記録してください新guardは [Medium] PHPT 035でcap超backlogをcancel前に同期してください最初の64KiB message直後にcancelしても、追加の64KiB超がclient socketへ到着済みとは限りません( 検証: PHPT 033/034 targeted PASS、PHPT 035 FAIL↔PASSを独立再現、 |
…connection break=UNAVAILABLE / drain capのini化 - REVIEW-20260711-010 (High): unregister_grpc_call_streamでdead connectionのnghttp2_session_set_stream_user_dataをskipし、fatal後のcleanupをlocal bookkeepingのみに (dead接続はsend/recvゲートで二度と駆動されず、nghttp2_session_delはstream callbackを呼ばないため安全) - REVIEW-20260711-011 (High): cancel_grpc_call_stream / streaming cancel / destroyのgateをconnection_usableからconnection_io_allowedへ統一。draining接続のadmit済みstreamもRST_STREAMでcloseしてからcall stateを解放し、nghttp2のdata provider経由UAFを防止。fixture :50067 + PHPT 036でGOAWAY(MaxInt32)後のcancelがワイヤにRSTを出すことを固定 - REVIEW-20260711-012 (Medium): grpc_call.connection_brokenを追加し、shared connection deathをsurvivorへsnapshotしてUNAVAILABLEに分類 (wire status / deadline / cancel / resetが優先)。PHPT 034はexact UNAVAILABLE + details non-empty、C unitに優先順位テストを追加 - REVIEW-20260711-013 (Medium): PHPT 035を決定的化。kernel TCP receive window(~64KiB)がproduction cap(64KiB)超のbacklog滞留を物理的に許さないため、grpc_lite.preflight_drain_max_bytes ini (default 65536)を導入し、SO_SNDBUF縮小によるACK barrier (fixture :50068/:50069のarm/floodプロトコル) + cap=16KiB指定でcap fallbackを検証。cap到達をトレースでassertしてからfresh connectionを期待 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第二パスの4件、すべて妥当と判断し b13362b で対応しました。レビュー記録は REVIEW-20260711-010〜013 として追記しています。 [High] nghttp2 fatal後のsession API → 対応指摘どおりです。 fault injectionについて: nghttp2 API呼び出しの失敗を決定的に注入する仕組みが現行harnessになく(NOMEM/CALLBACK_FAILUREはsocket詰まり・メモリ枯渇依存)、今回は「dead ⇒ 以後 [High] draining上のadmit済みstreamのclose → 対応指摘どおりUAF経路でした。 [Medium] survivorのstatus → UNAVAILABLE
[Medium] PHPT 035のbarrier → 対応 (調査結果込み)barrierを実装する過程で根本原因を特定しました: default kernel設定( そこで cap を 検証
🤖 Generated with Claude Code |
|
再レビューしました(HEAD ただし、以下 High 1 / Medium 1 / Low 2 が残るため、現時点ではREQUEST_CHANGES相当です。 [High] fatal nghttp2 returnを全call siteでdeadへ遷移させてくださいdead後のunregisterをlocal-onlyにした点は直っていますが、「fatal経路はすべて
[Medium] same-pullのconnection breakもUNAVAILABLEへ写像してください
[Low]
|
…break=UNAVAILABLE / drain cap read上限化 / UAF shapeのsanitizer固定 - REVIEW-20260712-001 (High): grpc_protocol_submit_rst_stream_in_callback()を追加し、parser/callback内の全RST submit(14箇所)をfatal→mark_connection_dead+NGHTTP2_ERR_CALLBACK_FAILUREでmem_recv即時unwindする形に統一。unary/streamingのnghttp2_submit_request fatalもdead化。fault injection seam GRPC_LITE_TEST_FAULT (rst-submit-fatal / submit-request-fatal)を導入し、PHPT 038/039でfatal→dead→wire上にframeなし・fresh connectionを固定 - REVIEW-20260712-002 (Medium): grpc_call_note_connection_broken()を共通化し、streaming/unaryのsame-pull send失敗・non-timeout recv EOF/error経路すべてでUNAVAILABLEにsnapshot付きで写像 (mem_recvのnghttp2失敗は別taxonomyで据え置き) - REVIEW-20260712-003 (Low): preflight drainのread長を残余capでクリップし、PHPT 035にsum<=cap assertを追加 - REVIEW-20260712-004 (Low): fixture :50070 (INITIAL_WINDOW_SIZE=1024 + request未消費のstream A応答 + GOAWAY(Max) + 遅延WINDOW_UPDATE) + PHPT 037でUAF original shape (pending request DATA + draining destructor + 別owner drive)を固定。h2_send_data_callbackのlifetimeコメントからdraining誤条件を除去。GOAWAYはmessage前送出でdraining観測を決定的化 (fixture :50067も同様)。sanitizer (ASan/UBSan)スイート24/24 PASS・報告ゼロ Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第三パスの4件、すべて妥当と判断し d54a2ba で対応しました。レビュー記録は REVIEW-20260712-001〜004 として追記しています。 [High] fatal nghttp2 returnの全call site dead遷移 → 対応ご指摘のとおり「fatal経路はすべて
[Medium] same-pullのconnection break → UNAVAILABLE
[Low] drain capのread上限化read長を [Low] UAF original shapeのsanitizer固定fixture sanitizer検証: 検証
🤖 Generated with Claude Code |
|
再レビューしました(HEAD ただし、以下 High 1 / Medium 2 が残るためREQUEST_CHANGES相当です。 [High] test fault seamをproduction buildから分離してください
さらに、最初のRPCで取得した fault seamはdefault-offのtest build defineでcompile outし、test buildでもMINIT-owned copyとexact token matchを使ってください。request境界を跨ぐASan/ZTS regressionも追加してください。 [Medium] partial message中のconnection breakをserver streamingでもUNAVAILABLEにしてくださいsame-pullのconnection break marker自体は有効ですが、server streamingはterminal pathでparser途中stateがあると無条件に response HEADERS + 3-byte partial gRPC header後にTCPをcloseする既存fixtureでは、unaryは TCP/TLS connection breakは両call kindとも [Medium] unary submit fatal時にdead connectionをcacheから即時detachしてくださいunaryのsubmit fatal branchはconnectionをdeadにして終了しますが、 同じkeyなら次回取得時にlazy evictionされますが、異なるauthority 129件でfatalを注入すると、128件のdead entryがcacheを占有し、129件目が fatal cleanup内でdead entryを即時detachし、最後のowner解放後に破棄してください。 |
…on break=UNAVAILABLE / fatal時のcache即時evict - REVIEW-20260712-005 (High): fault injection seamを--enable-grpc-test-fault (default off)でcompile outし、production buildから排除。test buildではGRPC_LITE_TEST_FAULTをMINITで固定バッファへcopy (getenv pointer非保持=putenv後のUAF解消、MINITはthread起動前でZTS安全)し、カンマ区切りexact token matchへ変更。test系スクリプト4本にflag追加。PHPT 038にputenv snapshot regressionとsuperstring decoy tokenによるexact match regressionを追加、038/039はseam未buildでSKIP - REVIEW-20260712-006 (Medium): streamingのtruncated判定にconnection_broken除外を追加し、TCP/TLS connection break mid-messageを両call kindでUNAVAILABLEに統一 (clean END_STREAM途中のみINTERNAL)。PHPT 024の:50057をexact UNAVAILABLEに強化しstreamingケースを追加 - REVIEW-20260712-007 (Medium): unary/streamingのsubmit fatal branchでdetach_persistent_connection_by_ptrによる即時evictを追加し、distinct keyのdead entry累積によるcache limit枯渇を解消。PHPT 039に130 distinct key sweepを追加 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第四パスの3件、すべて妥当と判断し 3e128d4 で対応しました。レビュー記録は REVIEW-20260712-005〜007 に追記しています。 [High] fault seamのtest build分離 → 対応3点とも実在の問題でした(build guardなし / getenv raw pointerのstatic保持によるputenv後UAF / ZTS static race)。対応:
[Medium] partial message中のconnection break → 両call kindでUNAVAILABLEご実測どおり、streamingのtruncated判定が [Medium] submit fatal時のcache即時detach → 対応ご指摘どおりlazy per-key evictionではdistinct keyのdead entryが累積します。unary / streaming両方のsubmit fatal branchで 検証
🤖 Generated with Claude Code |
|
再レビューしました(HEAD ただし、今回の修正に起因する High 1 / Medium 1 が残るためREQUEST_CHANGES相当です。 [High] unary coreとdiagnostic callerのconnection lifetime契約を揃えてくださいsubmit fatal時、unary coreはconnectionをdead化・cacheからdetachし、owner clear後に最終destroyしてFAILUREを返します。一方、
calleeがconnectionを消費して返る契約なら、diagnostic failure branchから [Medium] RST submit fatalでもdeadlineのstatus detailsを維持してくださいserver streamingで1 messageを受信後、次のpull前にdeadlineが切れると code resolverは deadlineはprimary call outcome、RST送出失敗はsecondary connection-cleanup failureとして扱い、PHP-visible code/detailsをともにdeadlineへ揃えてください。PHPT 038へbetween-pull server-streaming deadlineを追加し、exact code/detailsとfresh connectionを固定してください。 |
… details維持 - [High] unary coreのFAILURE契約を「connectionを消費して返る」に統一: submit fatalに加えregister失敗・mem_recv fatalでもdetach+destroyし、 bench diagnostic callerはFAILURE後にconnection pointerへ触れない (旧コードはfreed pointerへのconnection_usable()でASan UAF)。 PHPT 040で固定(旧コードではASan buildで実際にFAILすることを確認済み) - [Medium] timed_outのcallはstatus codeだけでなくdetailsも "HTTP/2 transport deadline exceeded" を維持(fatal RST submit等の teardown失敗はsecondaryでありdetailsを上書きしない)。 PHPT 038にbetween-pull streaming deadline + exact details assertを追加 - check-phpt / check-c-sanitizer に --enable-grpc-bench を追加し、 001はbench surfaceの露出をビルド構成と両方向で照合するassertへ変更 (MINFO行 "grpc_lite bench diagnostics" で判定) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第五パスの2件、すべて妥当と判断し e424689 で対応しました。レビュー記録は REVIEW-20260712-008〜009 に追記しています。 [High] unary coreとdiagnostic callerのconnection lifetime契約 → 統一ご指摘のとおり、第四パスで私が入れた「callee側でdetach+destroy」がdiagnostic caller(
[Medium] RST submit fatal時のdeadline details → deadlineへ整合ご実測どおり、code resolverは 検証
🤖 Generated with Claude Code |
|
再レビューしました(HEAD ただし、今回の対応で検証境界に Medium 1 / Low 2 が残るため、REQUEST_CHANGES相当です。 [Medium] production sanitizer laneをbench laneで置き換えないでください
今回のUAF regressionをbench sanitizerで固定するのは妥当ですが、既存のproduction相当ASan/UBSan laneを置換せず、production full sanitizer と bench+fault sanitizer の2 laneを実行してください。現状ではproduction-onlyのlayout/分岐に入るmemory bugがsanitizer gateから外れます。 [Low] PHPT 001のbench期待値を同じmoduleのMINFOから導かないでくださいPHPT 001はMINFOの runnerから [Low] unary mem-recv fatalのownership修正もsanitizer regressionへ固定してください
既存の |
…sion - [Medium] check-c-sanitizer.sh を production lane(--enable-grpc のみ、 純production binaryで全PHPT、fault/bench系はSKIP)と bench+fault lane の 2 laneに分離。bench buildによるlayout/分岐差でproduction-onlyの memory bugがsanitizer gateから外れないようにする - [Low] PHPT 001 のbench surface期待値を同一moduleのMINFOから導出せず、 runnerが宣言する GRPC_LITE_EXPECT_BENCH=0|1 を外部入力として使用 (未設定=production期待)。MINFO行も同じ外部期待と照合 - [Low] PHPT 041 を追加: rst-submit-fatal × 小receive limitで diagnostic unaryの mem_recv fatal FAILURE branch を通し、 2 attemptのlifetime + 130 distinct-key sweepでcache非残留を固定 (detachを一時除去すると実際にFAILすることを確認済み) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第六パスの3件、すべて妥当と判断し 24abba3 で対応しました。レビュー記録は REVIEW-20260713-001〜003 に追記しています。 [Medium] production sanitizer laneのbench置換 → 2 lane化ご指摘のとおり、第五パスの変更でsanitizer gateの検証対象がbench binary(
実測: production lane 22 PASS / 4 SKIP、bench-fault lane 26/26 PASS、ASan/UBSan報告ゼロ(halt_on_error下でexit 0)。 [Low] PHPT 001の期待値のMINFO由来 → runner宣言の外部入力へご指摘のとおり、同一moduleのMINFOから期待値を導く形は整合性検査にしかならず、build flag誤りで両方が有効になるとPASSする循環がありました。期待値を [Low] mem-recv fatal ownershipのregression → PHPT 041で固定ご指摘のとおり040はsubmit-request-fatalのみで、e424689で変更したmem_recv fatal branchが未固定でした。PHPT 041 を追加: 検証
🤖 Generated with Claude Code |
|
第七パスの再レビューを完了しました(HEAD 前回のMedium(production sanitizer laneのbench置換)は2 lane化で修正済みです。bench surfaceの期待値外部化もadequateで、PHPT 041はmem-recv fatalへの到達、diagnostic callerのpost-failure UAF、cache detach / non-reuseを固定できています。現HEADのproduction codeに新たなlifetime defectは確認していません。 ただしrequired gateとしては Low 3件 が残るため、REQUEST_CHANGES相当です。 [Low] production laneでtest-fault seam非露出も外部期待へ照合してください
そのためproduction laneへ誤って
[Low] PHPT 041でdetached connectionのdestroyまで観測してくださいPHPT 041はcontractを 現実装は正しくdestroyしていますが、この1行の退行は現在のgateを通ります。test-only destroy counter / trace eventで全132 connectionのdestroyをassertするか、PHPT内でboundedな [Low] open issueを現在のdeadline/RST lifecycleへ揃えてください元issueはdeadline時にconnectionを破棄しRSTを送らない状態を「現状」と記載し、RST後に短時間drainする案をactive Planとして残しています。一方、同文書のProgressでは実装済み、Decision Logではdrain不採用です。またVerificationは第六パスが第五パスより先になっています。 Backgroundを「変更前」と明示し、Planを現行方針へ更新するかsupersededと表示し、第五→第六の順へ直してください。元issueの中心概念であるstream-local deadline cancellationを入口文書が逆に説明しない状態にする必要があります。 検証
|
- [Low] GRPC_LITE_EXPECT_TEST_FAULT=0|1 をrunnerが宣言し、PHPT 001が MINFOの "grpc_lite test fault seam" 行を外部期待と照合(未設定=非露出)。 production laneへのseam漏出はSKIP解除でなく001のFAILとして検出される - [Low] destroy_h2_connection に wire.connection_close traceイベントを追加し、 PHPT 041で全132 connectionのdestroyをassert。detach-only退行 (leak検出無効下では不可視)でもFAILすることをdestroy一時除去で実証済み - [Low] issue文書のBackgroundを変更前/現在で書き分け、Planのdrain項を superseded化(Decision Log参照)、Verificationを時系列順(第五→第六)へ修正 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第七パスの3件、すべて妥当と判断し 3ed170f で対応しました。レビュー記録は REVIEW-20260713-004〜006 に追記しています。 [Low] test-fault seam非露出の外部期待照合 → 対応ご指摘のとおり、外部期待化したのはbenchだけで、seamのavailabilityはSKIPIF経由で同一moduleのMINFO由来のままでした(production laneへの漏出は038/039のSKIP解除で静かに通る)。PHPT 001に [Low] PHPT 041のdestroy観測 → wire.connection_close traceイベントで固定ご指摘のとおり、 [Low] open issueの入口文書整合 → 対応Backgroundを「変更前」(過去形)と「現在の実装」(stream-scoped RST + 接続温存)で書き分け、Planのdrain項をsuperseded化(不採用理由と50ms grace deadlineへの置換をDecision Log参照付きで注記、該当文は取り消し線)、Verificationを第五→第六の時系列順へ修正しました。 検証
🤖 Generated with Claude Code |
|
第八パスの再レビューを完了しました(HEAD 前回のLow 3件について、test-fault seamの外部期待は全runnerでbuild flagと一致しており、PHPT 041も132 connectionのdestroy invocationまで固定できています。ASan/UBSanを含む再検証でも、新たなC lifetime / runtime defectは確認していません。 ただしrequired gateとしては Low 2件 が残るため、REQUEST_CHANGES相当です。 [Low]
|
- [Low] wire.connection_close を transport.connection_destroy へrename。 発火点はlocal destructorの入口(TLS/fd/session解放前)で、preface前の setup failureでも発火するためwire semanticsではない。コメントと code-reading guideに発火phaseと非1対1対応を明記、PHPT 041を追従 - [Low] issue文書の「streamingのdeadline経路だけが接続破棄」を変更前として 過去形へ直し、現在のbest-effort reuse(SPEC §4.2)へ揃えた Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第八パスの2件、すべて妥当と判断し 1c55f56 で対応しました。レビュー記録は REVIEW-20260713-007〜008 に追記しています。 [Low] connection destroy eventのlocal lifecycle命名 →
|
|
第九パスの再レビューを完了しました(HEAD 前回のLow 2件のうち、 ただしrequired gateとしては Low 1件 が残るため、REQUEST_CHANGES相当です。 [Low] best-effort reuseのfallback説明にRSTの即時失敗も含めてください元issueのcurrent-state文は、fresh connectionへのfallbackを「RST flushがgrace deadlineを超過した場合」と説明しています。しかし実装はtimeoutだけではなく、 例えば「reuseはSPEC §4.2どおりbest-effort(RST submit / flush失敗〔grace deadline超過を含む〕またはpreflight drain cap超過時はfresh connectionへフォールバック)」へ揃えてください。即時失敗後にconnectionを捨てるのは、fatal nghttp2 sessionやpartial wire stateを再駆動しない本issueの安全側lifecycle contractです。 検証
|
…IEW-20260714-001) 「RST flushのgrace deadline超過」だけでなく、submitの即時失敗と nghttp2_session_send / socket / TLS / coalesced-buffer flushの任意の失敗 でもfresh connectionへフォールバックすることを明記(SPEC §4.2と整合)。 Planの同型の狭い記述2箇所も揃えた。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第九パスの1件、妥当と判断し f94d3ba で対応しました。レビュー記録は REVIEW-20260714-001 に追記しています。 [Low] best-effort reuseのfallback説明の拡張 → 対応ご指摘のとおり、第八パスで私が書いたcurrent-state文はfallbackを「RST flushがgrace deadlineを超過した場合」に限定しており、実装のfallback集合(RST submitの即時失敗によるdead化、 あわせて、Planのsuperseded注記と取り消し線行にも同型の狭い記述(grace deadline超過のみ)が残っていたため、「失敗〔grace deadline超過を含む〕」へ揃えています。 検証文書のみの変更(コード変更なし)のため、 🤖 Generated with Claude Code |
dkkoma
left a comment
There was a problem hiding this comment.
第十パスの再レビューを完了しました(HEAD f94d3ba)。第九パスの REVIEW-20260714-001 は適切に修正されています。HTTP/2 / gRPC domain gate は Blocker / High / Medium が none、今回新たに Low 1件です。runtime assertionは有効で、指摘はPHPT 035のtest contractコメント1か所に限定します。
検証: ASan/UBSan production 22 PASS / 4 SKIP、bench+fault 26/26 PASS、NTS PHPT 26/26、ZTS PHPT 24 PASS / 2 SKIP、C unit / C static analysis PASS、PHPUnit 31 tests / 116 assertions PASS。
|
|
||
| $call->cancel(); | ||
|
|
||
| // Connection reuse is best-effort: with more backlog than the 64KiB drain |
There was a problem hiding this comment.
[Low] testで設定した16KiB capとして説明してください
このPHPTはgrpc_lite.preflight_drain_max_bytes=16384を指定し、48KiB backlogを設定済み16KiB capに当てています。production defaultの64KiB超過は検証しておらず、上のfixture説明と下の16384-byte assertionにも反します。configured 16KiB drain capへ直し、production 64KiB境界はkernel window制約のため直接跨いでいないことと区別してください。
ini導入前の固定64KiB cap時代のコメント残骸を修正。テストが固定するのは --INI-- で下げた16KiB capの機構であり、production 64KiB境界は kernel window制約のため直接跨いでいないことを明記。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
第十パスの1件、妥当と判断し b7b9fd1 で対応しました。レビュー記録は REVIEW-20260714-002 に追記しています。 [Low] PHPT 035のcapコメント → 設定済み16KiBとして記述ご指摘のとおり、後続コール直前のコメントの「64KiB drain cap」はini導入前(固定64KiB cap時代)の設計のコメント残骸で、テストが実際に固定しているのは 検証コメントのみの変更のため、PHPT 035単体のPASSを確認しました。その他のコード検証は第八パスの状態から不変です。 🤖 Generated with Claude Code |
|
第十一パスの再レビューを完了しました(HEAD / 対応commit 前回のLowはadequateです。PHPT 035のコメントは、48KiB backlogが 新規指摘はありません。HTTP/2 / gRPC required domain gateは次のとおりall clearです。
検証も再実行しました。
このHEADはAPPROVE相当です。 |
- PR #26/#27/#28/#29 でマージ済みの issue(goaway transparent retry / bin metadata unpadded base64 / status taxonomy / encoding flag=0 / deadline RST_STREAM)を Status: Closed にして docs/issues/closed/ へ移動 - PR #29 レビューサイクル(pass 4〜11)の記録 30 ファイルを docs/reviews/issues/ に追加 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
概要
deadline超過(read poll timeout)を接続レベル障害ではなくstream-scopedな失敗として扱い、
RST_STREAM(CANCEL)を当該streamへ送出してpersistent connectionを温存する。C-core / grpc-go と同挙動。Issue:
docs/issues/open/2026-07-08-deadline-rst-stream-keep-connection.md従来はunaryのsocket timeoutで
mark_connection_deadにより接続ごと破棄しており、FrankenPHP worker等のpersistent connection前提の用途では1回のDEADLINE_EXCEEDEDごとにTCP+TLSハンドシェイクをやり直していた。またRST_STREAMを送らないためサーバー側はクライアント消失まで処理を継続し得た。変更内容
cancel_grpc_call_stream()を追加 (src/transport.c): stream単位の RST_STREAM(CANCEL) submit + flush を共通化。unaryのsocket timeout分岐 (src/unary_call.c) を接続破棄から本helperへ置き換えcancel_active_server_streaming_call_state/server_streaming_call_terminate_with_cancelは期限切れのcall deadlineをRST書き込みのwrite deadlineに使っており、deadline経路ではRSTが書けず即接続破棄になっていた。RST flushは専用の50ms grace deadline(pending frame一式のflush上限、超過時は従来どおり接続破棄)で行うsetup_deadline_abs_usのscope整理: connection setup完了時に0へクリア。従来は接続作成時のcall deadlineがconnection-scopedなwrite fallbackに残留し、温存した接続上のdeadlineなし後続コールが即ETIMEDOUTになった(timeout時に接続を破棄していた従来挙動では露見しなかった)connection->last_error_detail/last_io_errno/last_ssl_errorをクリアし、後続コールのstatus detailsへの漏れを防止locally_cancelledflag追加: 自送出RSTでmid-messageに閉じたstreamがtruncated-body判定でmalformed_response_frame偽陽性になるのを除外(status taxonomyはtimed_out優先で従来どおりDEADLINE_EXCEEDED)wire.frame_outにRST_STREAMのerror_codeを追加(inbound側と対称)persistent_reused=true+ OK、(3) deadlineなしin-flight streamingが並行コールのdeadline超過を生き延びる、を固定Non-Goals (issue記載どおり)
レビュー
HTTP/2/gRPCドメインモデルレビュー実施:
docs/reviews/issues/2026-07-11-deadline-rst-keep-connection-domain-review.md検証
tools/test/check-phpt.sh: 18/18 PASS(スイート3回連続、新規033は単体3回もPASS)tools/test/check-c-unit.sh: protocol_core / status_core / transport_core PASStools/test/check-c-static-analysis.sh: passpersistent_reused=trueで成功🤖 Generated with Claude Code