-
Notifications
You must be signed in to change notification settings - Fork 0
fix(extractor): curated app-scoped source exemption for the Application subscriber (Closes #228) #232
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
fix(extractor): curated app-scoped source exemption for the Application subscriber (Closes #228) #232
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| // issue #228 — an Application-derived subscriber whose event source is an APP-SCOPED | ||
| // RESOLVER RESULT (curated: PaletteHelper.GetThemeManager), not a literal static member. | ||
| // The source is process-lived (bound to the app's own state), so the subscription | ||
| // promotes nothing — but SubscriptionSourceKind honestly tiers a call-result receiver | ||
| // "injected", which used to warn. Real-world shape: MaterialDesignInXamlToolkit | ||
| // MahMaterialDragablzMashUp App.xaml.cs:10,22 (found by the issue #201 oracle sweep). | ||
| // | ||
| // The exemption is deliberately NARROW (see the rejected `clsIsStatic` broadening in | ||
| // docs/notes/oracle-known-fps.md): subscriber must be the Application class itself, | ||
| // the resolver must be on the curated list, and the handler must be a METHOD GROUP of | ||
| // that class — three negative controls below pin each edge. | ||
| using System; | ||
|
|
||
| namespace OwnSamples.AppScoped | ||
| { | ||
| // Stand-in for System.Windows.Application: IsProcessLivedApplication matches the | ||
| // base NAME syntactically (WPF assemblies do not resolve on the Linux runner). | ||
| public class Application { } | ||
|
|
||
| public class ThemeManagerLike | ||
| { | ||
| public event EventHandler? ThemeChanged; | ||
| public void Raise() => ThemeChanged?.Invoke(this, EventArgs.Empty); | ||
| } | ||
|
|
||
| // Stand-in for MaterialDesignThemes.Wpf.PaletteHelper — the curated resolver, | ||
| // matched by (containing-type, method) = (PaletteHelper, GetThemeManager). | ||
| public class PaletteHelper | ||
| { | ||
| static readonly ThemeManagerLike Manager = new(); | ||
| public ThemeManagerLike? GetThemeManager() => Manager; | ||
| } | ||
|
|
||
| // Same shape, NON-curated name -> never exempted. | ||
| public class OtherHelper | ||
| { | ||
| static readonly ThemeManagerLike Manager = new(); | ||
| public ThemeManagerLike? GetOtherService() => Manager; | ||
| } | ||
|
|
||
| // POSITIVE (silent): App + curated resolver via `is`-pattern local + method-group | ||
| // handler of the App class — the exact MaterialDesign shape. | ||
| public class App : Application | ||
| { | ||
| public void OnStartup() | ||
| { | ||
| var helper = new PaletteHelper(); | ||
| if (helper.GetThemeManager() is { } themeManager) | ||
| themeManager.ThemeChanged += ThemeManager_ThemeChanged; // silent (#228) | ||
| } | ||
|
|
||
| void ThemeManager_ThemeChanged(object? sender, EventArgs e) { } | ||
| } | ||
|
|
||
| // POSITIVE (silent): the direct-invocation receiver form, no intermediate local. | ||
| public class DirectApp : Application | ||
| { | ||
| public void OnStartup() | ||
| { | ||
| new PaletteHelper().GetThemeManager()!.ThemeChanged += OnTheme; // silent (#228) | ||
| } | ||
|
|
||
| void OnTheme(object? sender, EventArgs e) { } | ||
| } | ||
|
|
||
| // CONTROL 1 (flagged): the SAME curated shape from a class that is NOT the | ||
| // Application — the subscriber gate must stay `clsIsApp`, byte-for-byte. | ||
| public class NotAnApp | ||
| { | ||
| public void Wire() | ||
| { | ||
| var helper = new PaletteHelper(); | ||
| if (helper.GetThemeManager() is { } themeManager) | ||
| themeManager.ThemeChanged += OnTheme; // OWN001 warning | ||
Check warningCode scanning / Own.NET owned resource not released on all paths (possible leak) Warning
event 'themeManager.ThemeChanged' is subscribed (handler 'OnTheme') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'NotAnApp' alive (possible leak) [resource: subscription token]
Check warning on line 74 in frontend/roslyn/samples/AppScopedSourceSample.cs
|
||
|
|
||
| } | ||
|
|
||
| void OnTheme(object? sender, EventArgs e) { } | ||
| } | ||
|
|
||
| // CONTROL 2 (flagged): App + curated source, but the handler is a LAMBDA capturing | ||
| // an enclosing local — pinning that local to app lifetime is the exact hole that | ||
| // sank the `clsIsStatic` broadening; a lambda must never pass the handler gate. | ||
| public class LambdaApp : Application | ||
| { | ||
| public void OnStartup() | ||
| { | ||
| var counter = new int[1]; | ||
| if (new PaletteHelper().GetThemeManager() is { } themeManager) | ||
| themeManager.ThemeChanged += (s, e) => counter[0]++; // OWN001 warning | ||
Check warningCode scanning / Own.NET owned resource not released on all paths (possible leak) Warning
event 'themeManager.ThemeChanged' is subscribed (handler '(s, e) => counter[0]++') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'LambdaApp' alive (possible leak — and being an inline lambda it has no '-=' handle, so it could never be detached) [resource: subscription token]
Check warning on line 89 in frontend/roslyn/samples/AppScopedSourceSample.cs
|
||
|
|
||
| } | ||
| } | ||
|
|
||
| // CONTROL 3 (flagged): App + method-group handler, but a NON-curated resolver — | ||
| // membership is a curated allowlist, not "any call result inside App". | ||
| public class CuratedOnlyApp : Application | ||
| { | ||
| public void OnStartup() | ||
| { | ||
| if (new OtherHelper().GetOtherService() is { } service) | ||
| service.ThemeChanged += OnTheme; // OWN001 warning | ||
Check warningCode scanning / Own.NET owned resource not released on all paths (possible leak) Warning
event 'service.ThemeChanged' is subscribed (handler 'OnTheme') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'CuratedOnlyApp' alive (possible leak) [resource: subscription token]
Check warning on line 100 in frontend/roslyn/samples/AppScopedSourceSample.cs
|
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| } | ||
|
|
||
| void OnTheme(object? sender, EventArgs e) { } | ||
| } | ||
|
|
||
| // CONTROL 4 (flagged, Codex P2): the method group is qualified with ANOTHER | ||
| // instance of the same App-derived type — right ContainingType, wrong delegate | ||
| // TARGET: the process-lived source pins `_twin`, not `this`. | ||
| public class TwinApp : Application | ||
| { | ||
| readonly TwinApp? _twin; | ||
|
|
||
| public TwinApp(TwinApp? twin) => _twin = twin; | ||
|
|
||
| public void OnStartup() | ||
| { | ||
| if (new PaletteHelper().GetThemeManager() is { } themeManager) | ||
| themeManager.ThemeChanged += _twin!.OnTheme; // OWN001 warning | ||
Check warningCode scanning / Own.NET owned resource not released on all paths (possible leak) Warning
event 'themeManager.ThemeChanged' is subscribed (handler '_twin!.OnTheme') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'TwinApp' alive (possible leak) [resource: subscription token]
Check warning on line 118 in frontend/roslyn/samples/AppScopedSourceSample.cs
|
||
|
|
||
| } | ||
|
|
||
| public void OnTheme(object? sender, EventArgs e) { } | ||
| } | ||
|
|
||
| // CONTROL 5 (flagged, Codex P2): the local STARTS as the curated resolver result | ||
| // but is REASSIGNED to an injected publisher before the `+=` — the declaration-site | ||
| // binding is stale, so the exemption must not trust it. | ||
| public class ReassignApp : Application | ||
| { | ||
| readonly ThemeManagerLike _injectedBus; | ||
|
|
||
| public ReassignApp(ThemeManagerLike bus) => _injectedBus = bus; | ||
|
|
||
| public void OnStartup() | ||
| { | ||
| var tm = new PaletteHelper().GetThemeManager()!; | ||
| tm = _injectedBus; | ||
| tm.ThemeChanged += OnTheme; // OWN001 warning | ||
Check warningCode scanning / Own.NET owned resource not released on all paths (possible leak) Warning
event 'tm.ThemeChanged' is subscribed (handler 'OnTheme') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'ReassignApp' alive (possible leak) [resource: subscription token]
Check warning on line 137 in frontend/roslyn/samples/AppScopedSourceSample.cs
|
||
|
|
||
| } | ||
|
|
||
| void OnTheme(object? sender, EventArgs e) { } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.