Skip to content

feat(P-007): pin POOL005 full-length view stored into a field; defer object-level escape#206

Merged
PhysShell merged 2 commits into
mainfrom
claude/own-net-issue-198-pool45
Jul 10, 2026
Merged

feat(P-007): pin POOL005 full-length view stored into a field; defer object-level escape#206
PhysShell merged 2 commits into
mainfrom
claude/own-net-issue-198-pool45

Conversation

@PhysShell

Copy link
Copy Markdown
Owner

Что и зачем

Issue #198, оставшиеся Pool/Span-срезы P-007. Проверив поведение против реального Roslyn-экстрактора локально (поднял .NET SDK в песочнице — не только CI), обнаружил, что срез (a) уже срабатывает: POOL005 field-pass ловит полноразмерный вид по выражению, поэтому правая часть присваивания в поле _view = _buf.AsMemory() сама является таким выражением → OWN025 на месте сохранения (и для Memory<T>, и для ReadOnlyMemory<T>; Span<T> — ref struct и полем быть не может). Ограниченный фикс (AsMemory(0, _n)) молчит. Изменений в Program.cs не потребовалось — PR превращает это уже-корректное поведение в закреплённый контракт и закрывает пометку P-007 «left next». Precision-first: срез (b) — object-level cross-member escape — вынесен в отдельный issue (см. ниже), а не форсирован ложным срабатыванием.

Состав:

  • corpus/real-world/arraypool-view-into-field-overread/ — before.cs (OWN025 на обоих сохранениях вида в поле) / after.cs (ограниченный вид, молчит — specificity-половина zero-FP гейта) / case.own (редукция → OWN025) / expected-diagnostics.txt / notes.md. Проверено own-check.sh --format sarif: before → [OWN025], after → [].
  • tests/test_ownir.py — закрепляет форму OwnIR-фактов, которую экстрактор эмитит для сохранения (pool-тегированный acquire/overspan/release → OWN025) — замороженная цель, как советовал в брифе.
  • docs/proposals/P-007-arraypool-span.md + notes arraypool-field-fullspan-overread — обновлены.
  • tests/fixtures/cfg_parity.json — перегенерирован под новый case.own (ратчет CFG-паритета из P-022 step 3: port own-cfg (AST → CFG lowering) to Rust with exact differential parity #197; Rust own-cfg round-trip'ит его).

Срез (b), deeper POOL004 escape: единственная форма за этой границей — ограниченный вид, закэшированный в поле и прочитанный после Return в другом методе — это object-level cross-member escape, чья баговость зависит от порядка вызовов у вызывающего (Setup→Done→Late — баг; Setup→Late→Done — норма). Это требует межпроцедурного порядка, которого у per-method + field пассов нет, так что флаг был бы soft FP. Отложено с доказательством как #205 (по клаузе отсрочки в issue). Внутрипроцедурные escapes (return-after-return, using-owner-return) уже покрыты и остаются зелёными.

Про CI: PR не трогает .github/workflows/ci.yml — новый corpus-кейс подхватывается существующими corpus-benchmark и test_corpus авто-дискавери, так что с #204 (который правит ci.yml) конфликта по файлу нет.

Тип изменения

  • feat — новая возможность
  • fix — исправление бага
  • docs — документация
  • refactor / chore / test / ci — без изменения поведения

Как проверено

  • python tests/run_tests.py — зелено (corpus 32/32 вкл. новый кейс; CFG parity 67; ownir 249/249)
  • ruff check . и mypy — чисто
  • Реальный экстрактор локально: own-check.sh --format sarif before→[OWN025], after→[]; и OK-контрасты (bounded, non-pool, return-after-use) молчат / без ложного OWN002
  • cd rust && cargo testown-cfg round-trip'ит новый case.own

Связанные issue

Closes #198
Follow-up: #205 (POOL004 object-level cross-member escape — deferred)

Чеклист

  • изменение покрыто тестом/фикстурой (corpus bad/ok + фактовый пин в test_ownir + core .own)
  • README/docs обновлены (P-007 proposal + corpus notes)
  • коммиты в conventional-commit стиле (feat:)

🤖 Generated with Claude Code

https://claude.ai/code/session_01Cg6DVXahkyY68Ruu7f76rG


Generated by Claude Code

…ead)

Issue #198, slice (a): a full-length view of a pooled buffer cached into
another field (`_view = _buf.AsMemory()`, a Memory<T>/ReadOnlyMemory<T> field —
Span<T> is a ref struct and cannot be a field) and read in a later member reaches
past the logical rented length into the stale [n, Length) tail.

Verified end to end with the real Roslyn extractor (a local .NET SDK, not
CI-only): the POOL005 field pass fires on the full-length view *expression*, so
the RHS of the store is itself caught — OWN025 at the store, on both the Memory
and ReadOnlyMemory spellings; the bounded fix (`AsMemory(0, _n)`) is silent. No
extractor change was needed; this turns that already-correct behaviour into a
pinned contract and closes the P-007 "left next" note.

  * corpus/real-world/arraypool-view-into-field-overread/ — before.cs (OWN025 on
    both field stores) / after.cs (bounded, silent — the zero-FP specificity
    half), case.own (OWN025 reduction), expected-diagnostics.txt, notes.md.
    Confirmed via own-check.sh --format sarif (before -> [OWN025], after -> []).
  * tests/test_ownir.py — pins the OwnIR fact shape the extractor emits for the
    store (pool-tagged acquire/overspan/release -> OWN025), the frozen target.
  * docs/proposals/P-007-arraypool-span.md + the field-fullspan notes — updated.
  * tests/fixtures/cfg_parity.json — regenerated for the new case.own (the #197
    CFG-parity ratchet; Rust own-cfg round-trips it).

Slice (b), deeper POOL004 escape: the one shape past this — a *bounded* view
cached in a field, read after the owner is Return'ed in a *different* member — is
an object-level, cross-member escape whose bug-ness depends on the caller's
method-call order (Setup->Done->Late vs Setup->Late->Done). That needs
interprocedural ordering the per-method + field passes lack, so flagging it would
be a soft false positive. Deferred with evidence as a follow-up (#205), per the
issue's deferral clause; the intraprocedural escapes (return-after-return,
using-owner-return) are already covered and stay green.

Closes #198

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cg6DVXahkyY68Ruu7f76rG
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@PhysShell, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e3d375c9-b488-474a-9ca1-9d37b58451fb

📥 Commits

Reviewing files that changed from the base of the PR and between a4df528 and 9de7cbd.

📒 Files selected for processing (9)
  • corpus/real-world/arraypool-field-fullspan-overread/notes.md
  • corpus/real-world/arraypool-view-into-field-overread/after.cs
  • corpus/real-world/arraypool-view-into-field-overread/before.cs
  • corpus/real-world/arraypool-view-into-field-overread/case.own
  • corpus/real-world/arraypool-view-into-field-overread/expected-diagnostics.txt
  • corpus/real-world/arraypool-view-into-field-overread/notes.md
  • docs/proposals/P-007-arraypool-span.md
  • tests/fixtures/cfg_parity.json
  • tests/test_ownir.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/own-net-issue-198-pool45

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2193d77399

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Fill(_buf, n);
_view = _buf.AsMemory(0, _n); // FIX: bounded to the logical length
_metaLen = 8;
_metaView = _meta.AsMemory(0, _metaLen); // FIX: bounded

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Initialize pooled metadata before caching its view

In the fixed corpus case, Capture() bounds _metaView to 8 bytes but never writes _meta[0.._metaLen) after renting _meta from ArrayPool. For any Capture(); FlushMeta() call, FlushMeta() still copies stale bytes from a previous renter, so the after.cs file labeled as the clean specificity half is still an information disclosure; initialize the metadata slice before storing/exposing the view, as the _buf path does with Fill(_buf, n).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 9de7cbd. _meta is now written with Fill(_meta, _metaLen) before the bounded view is cached, in both before.cs and after.cs, so the "clean fix" half no longer exposes uninitialized pooled bytes and the "valid payload + stale tail" story holds. Checker behaviour is unchanged: before.cs still raises OWN025 on both full-length field stores, after.cs stays silent (verified via own-check.sh --format sarif).


Generated by Claude Code

…review)

The view-into-field fixture rented `_meta` but never wrote its valid bytes, so
after.cs (the "clean fix" specificity half) still exposed 8 uninitialized pooled
bytes via FlushMeta — a latent stale read in a file meant to be genuinely correct.
Write `_meta[0.._metaLen)` (Fill) before caching the bounded view, mirroring the
`_buf`/Fill path, in both before.cs and after.cs so the "valid payload + stale
tail" story holds. No checker-behaviour change: before still raises OWN025 on both
full-length field stores, after stays silent (verified via own-check.sh --format
sarif). case.own is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cg6DVXahkyY68Ruu7f76rG

Copy link
Copy Markdown
Owner Author

@coderabbitai review


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

@PhysShell: Sure, I'll review the changes.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@PhysShell
PhysShell merged commit 9fc8c27 into main Jul 10, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P-007: remaining POOL004/POOL005 slices — view stored into another field; deeper escape shapes

2 participants