-
Notifications
You must be signed in to change notification settings - Fork 0
oracle: timer leak (а) + golden runtime-correlation fixture (б) #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2f388d2
oracle: golden arch-graph fixture + run arch/ on oracle-shaped data
claude 0955244
oracle fixtures: add System.String deps + reframe the contract (Codex…
claude 0bf5b44
Merge remote-tracking branch 'origin/main' into claude/sts-runtime-an…
claude 9a87eb6
oracle: add timer leak (а) + golden runtime correlation fixture (б)
claude 777f82b
oracle fixtures: add Ticker view-models to the arch graph + strengthe…
claude 155648d
oracle fixtures: correct finding lines + pin correlation config (Code…
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| using System; | ||
| using System.Threading; | ||
|
|
||
| namespace LeakyOracle.ViewModels; | ||
|
|
||
| /// <summary> | ||
| /// The corrected counterpart of <see cref="TickerViewModel"/>: it owns the <see cref="Timer"/> and | ||
| /// disposes it. Disposing unlinks the timer from the runtime's TimerQueue, so once disposed this | ||
| /// view-model is no longer rooted and collects normally — the control case that keeps the timer-leak | ||
| /// proof honest (same WeakReference harness; correct code collects, leaky code doesn't). | ||
| /// </summary> | ||
| public sealed class FixedTickerViewModel : IDisposable | ||
| { | ||
| private readonly Timer _timer; | ||
| private int _ticks; | ||
|
|
||
| public FixedTickerViewModel() | ||
| { | ||
| _timer = new Timer(OnTick, null, 300_000, 300_000); | ||
| } | ||
|
|
||
| private void OnTick(object? state) => _ticks++; | ||
|
|
||
| public void Dispose() => _timer.Dispose(); // the fix: unlink from the TimerQueue | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| using System.Threading; | ||
|
|
||
| namespace LeakyOracle.ViewModels; | ||
|
|
||
| /// <summary> | ||
| /// A per-screen view-model that drives a live "ticker" off a <see cref="Timer"/>. DELIBERATELY LEAKY: | ||
| /// it starts a recurring <see cref="System.Threading.Timer"/> in the constructor and never disposes it. | ||
| /// | ||
| /// An active timer is registered in the runtime's (static) TimerQueue, which holds the timer's callback | ||
| /// delegate — and the delegate's target is this view-model. So every TickerViewModel ever created stays | ||
| /// rooted by the timer queue until <see cref="Timer.Dispose()"/> is called: the timer-lifetime leak | ||
| /// (own-check small rule; docs/wpf-audit-coverage.md, "Timers": DispatcherTimer/Timers.Timer/ | ||
| /// Threading.Timer with no Stop/Dispose). The framework-agnostic core: identical on WPF and Avalonia. | ||
| /// | ||
| /// The `_timer` field is deliberate — without it the public Timer wrapper would be finalized and stop | ||
| /// the timer; holding it keeps the timer alive (and the leak real), exactly as leaky code does. | ||
| /// </summary> | ||
| public sealed class TickerViewModel | ||
| { | ||
| private readonly Timer _timer; | ||
| private int _ticks; | ||
|
|
||
| public TickerViewModel() | ||
| { | ||
| // recurring + far-future due time: registered (so it roots `this`) but won't actually fire | ||
| // during a sub-second scenario. Never disposed -> never unlinked from the TimerQueue. | ||
| _timer = new Timer(OnTick, null, 300_000, 300_000); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| private void OnTick(object? state) => _ticks++; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "_comment": "Static leak SUSPECTS for the LeakyOracle app — the findings.json a static pass (own-check) would emit for the oracle's two intentional lifetime leaks. Fed to runtime/correlate.py together with runtime.json to confirm them against heap evidence (test_oracle_runtime.py). `resource` is a DESCRIPTION (has spaces) not a type, so correlate keys on the source-file stem (the owning class) — WatchlistViewModel / TickerViewModel.", | ||
| "findings": [ | ||
| { | ||
| "tool": "own-check", | ||
| "rule": "OWN001", | ||
| "category_name": "subscription-leak", | ||
| "resource": "QuoteReceived subscription", | ||
| "path": "oracle/LeakyOracle/ViewModels/WatchlistViewModel.cs", | ||
| "line": 32, | ||
| "message": "subscribes to MarketDataService.QuoteReceived with no matching unsubscribe", | ||
| "suppressed": false | ||
| }, | ||
| { | ||
| "tool": "own-check", | ||
| "rule": "OWN-TIMER", | ||
| "category_name": "idisposable-leak", | ||
| "resource": "Timer never disposed", | ||
| "path": "oracle/LeakyOracle/ViewModels/TickerViewModel.cs", | ||
| "line": 27, | ||
| "message": "System.Threading.Timer created but never disposed (Stop/Dispose missing)", | ||
| "suppressed": false | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| { | ||
| "_comment": "Golden heap-retention artifact for the LeakyOracle app — what a stand-side ClrMD/gcdump collector would emit after running `LeakyOracle --leak-scenario` (open+close 50 screens). Faithful to the headless leak proof: 50 of each leaky view-model survive GC (expected 0), plus the 250k QuoteRow they transitively retain. Fed to runtime/correlate.py with findings.json to exercise all three buckets (test_oracle_runtime.py). The слой-2 ClrMD collector in Own.NET must emit this shape; here it's hand-authored from the proven leak.", | ||
| "schema": "ownAudit/runtime/v1", | ||
| "scenario": "open+close 50 watchlist/ticker screens (LeakyOracle --leak-scenario)", | ||
| "iterations": 50, | ||
| "retained": [ | ||
| { | ||
| "type": "LeakyOracle.ViewModels.WatchlistViewModel", | ||
| "count": 50, | ||
| "expected": 0, | ||
| "bytes": 11534336, | ||
| "roots": [ | ||
| { "kind": "static-field", "holder": "Avalonia.Application", "member": "Current", | ||
| "via": "App._service (MarketDataService).QuoteReceived delegate -> this" } | ||
| ] | ||
| }, | ||
| { | ||
| "type": "LeakyOracle.ViewModels.TickerViewModel", | ||
| "count": 50, | ||
| "expected": 0, | ||
| "roots": [ | ||
| { "kind": "timer", "holder": "System.Threading.TimerQueue", | ||
| "via": "undisposed Timer callback -> this" } | ||
| ] | ||
| }, | ||
| { | ||
| "type": "LeakyOracle.ViewModels.QuoteRow", | ||
| "count": 250000, | ||
| "expected": 0, | ||
| "bytes": 10485760, | ||
| "roots": [ | ||
| { "kind": "static-field", "holder": "Avalonia.Application", "member": "Current", | ||
| "via": "retained transitively through the 50 leaked WatchlistViewModel.Rows" } | ||
| ] | ||
| } | ||
| ] | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked
oracle/fixtures/graph.jsonandoracle/fixtures/test_oracle_arch.py: the golden architecture contract still describes 8 internal types and has noTickerViewModel/FixedTickerViewModelnodes orLeakScenarioedges to them. With this new view-model in the oracle, a real Roslyn extraction overoracle/LeakyOraclewould now emit those two types, so the pinned graph is no longer faithful and the drift guard keeps passing the stale fixture instead of catching the mismatch.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct on both counts — fixed in 777f82b. Adding the timer VMs in (а) left the arch golden at 8 internal types, and the old drift guard ("every node points at a real file") structurally couldn't catch a missing type. Fix: added
TickerViewModel/FixedTickerViewModelnodes + their edges (LeakScenario → Ticker VMs,Ticker → System.Threading.Timer,FixedTicker → IDisposable), and replaced the guard with a both-directions check — the graph's internal node set must equal the set of oracle source types (glob ofLeakyOracle/**/*.cs), so a new view-model with no node (or a node for a deleted type) now fails the test. Still 0 findings on the clean graph; 4/4 normal +-O.Generated by Claude Code