Follow-up split out of #198 (P-007 Pool/Span). Deliberate deferral — recorded with evidence, per #198's "a deliberate deferral beats a soft false positive."
The uncovered shape
A pooled buffer's view is cached into a field, and that view field is read after the buffer is Returned in a different member:
sealed class ViewEscapeField : IDisposable
{
private byte[] _buf;
private Memory<byte> _view;
public void Setup(int n) { _buf = ArrayPool<byte>.Shared.Rent(n); _view = _buf.AsMemory(0, n); } // bounded view -> field
public void Done() => ArrayPool<byte>.Shared.Return(_buf); // release
public byte[] Late() => _view.ToArray(); // reads the field view AFTER the return
public void Dispose() { }
}
Verified against the current extractor + core (dotnet run … --flow-locals → python -m ownlang ownir): nothing fires. The view is bounded (so no POOL005/OWN025 over-read), and the use-after-return (POOL004/OWN002) is never surfaced because the Return and the field-view read live in different members.
Why it is deferred, not fixed
Whether this is a bug depends on the caller's method-call order, which a per-method + field pass cannot see:
Setup → Done → Late — use-after-return (the bug).
Setup → Late → Done — perfectly fine.
Flagging it unconditionally would be a soft false positive (P-007 §Non-goals: whole-program/interprocedural Span/Memory escape is out of v0 scope). It needs interprocedural / whole-program ordering (or a conservative "view field outlives a class-wide Return with no ordering proof" heuristic that would have to clear the corpus zero-FP gate).
What #198 did deliver
The materialization side is covered and now pinned: a full-length view stored into a field (_view = _buf.AsMemory()) is caught at the store as an OWN025 over-read (corpus arraypool-view-into-field-overread). This issue is only the bounded-view object-level escape left past that boundary.
Done when
The cross-member field-view-after-Return escape is caught (POOL004 → OWN002) with a corpus bad/ok pair, without any new false positive on the existing corpus (the Setup → Late → Done order and every current ok-fixture stay silent).
Refs: docs/proposals/P-007-arraypool-span.md; corpus/real-world/arraypool-view-into-field-overread/notes.md.
Follow-up split out of #198 (P-007 Pool/Span). Deliberate deferral — recorded with evidence, per #198's "a deliberate deferral beats a soft false positive."
The uncovered shape
A pooled buffer's view is cached into a field, and that view field is read after the buffer is
Returned in a different member:Verified against the current extractor + core (
dotnet run … --flow-locals→python -m ownlang ownir): nothing fires. The view is bounded (so no POOL005/OWN025 over-read), and the use-after-return (POOL004/OWN002) is never surfaced because theReturnand the field-view read live in different members.Why it is deferred, not fixed
Whether this is a bug depends on the caller's method-call order, which a per-method + field pass cannot see:
Setup → Done → Late— use-after-return (the bug).Setup → Late → Done— perfectly fine.Flagging it unconditionally would be a soft false positive (P-007 §Non-goals: whole-program/interprocedural
Span/Memoryescape is out of v0 scope). It needs interprocedural / whole-program ordering (or a conservative "view field outlives a class-wideReturnwith no ordering proof" heuristic that would have to clear the corpus zero-FP gate).What #198 did deliver
The materialization side is covered and now pinned: a full-length view stored into a field (
_view = _buf.AsMemory()) is caught at the store as an OWN025 over-read (corpusarraypool-view-into-field-overread). This issue is only the bounded-view object-level escape left past that boundary.Done when
The cross-member field-view-after-
Returnescape is caught (POOL004 → OWN002) with a corpus bad/ok pair, without any new false positive on the existing corpus (theSetup → Late → Doneorder and every current ok-fixture stay silent).Refs: docs/proposals/P-007-arraypool-span.md; corpus/real-world/arraypool-view-into-field-overread/notes.md.