Summary
QfcCollectionController.RemoveSpecificControlGroupAsync (QuickFiler/Controllers/QfcCollectionController.cs:1142-1233) increments a static reentrancy counter at method entry but only decrements it at the normal exit path, with no try/finally. Any exception thrown mid-method leaves the counter permanently incremented, which then produces a false-positive "race condition" error log on every subsequent call for the remaining life of the process.
Environment
- OS/version: n/a (logic defect, reproducible on any platform running QuickFiler)
- Python version: n/a
- Command/flags used: n/a
- Data source or fixture:
QuickFiler/Controllers/QfcCollectionController.cs
Steps to Reproduce
- Inspect
QfcCollectionController.cs:1142: private static int removespecificcontrolgroupcounter = 0;
- Inspect
RemoveSpecificControlGroupAsync (line 1144): Interlocked.Increment(ref removespecificcontrolgroupcounter); at line 1146 (method entry), followed by ~80 lines of method body (navigation unregister/register, active-item handling), then Interlocked.Decrement(ref removespecificcontrolgroupcounter); at line 1232 (method's final statement).
- Note there is no
try/finally wrapping lines 1146-1232.
- Trigger any exception between the increment (line 1146) and the decrement (line 1232) - e.g. an unhandled exception from
UnregisterNavigation(), RegisterNavigation(), or any of the active-item/theme handling in between.
- The decrement at line 1232 never executes;
removespecificcontrolgroupcounter remains permanently incremented above its pre-call value.
- Every subsequent call to
RemoveSpecificControlGroupAsync now sees removespecificcontrolgroupcounter > 1 at line 1222 and logs logger.Error("RemoveSpecificControlGroupAsync: Counter is greater than 1. Race Condition Exists") - a false positive, since no concurrent reentrancy is actually occurring.
Expected Behavior
The counter should always return to its pre-call value once the method returns or throws, so the race-condition check at line 1222 only fires on genuine concurrent reentrancy, not on a leaked count from an earlier unrelated exception.
Actual Behavior
The decrement is skipped whenever the method body throws, permanently inflating the counter and causing the race-condition detector to report a false positive on every future call, masking the detector's ability to catch a real race condition later (since the counter is already above 1 regardless of actual concurrency).
Logs / Screenshots
Impact / Severity
The counter is diagnostic/observability-only (it drives a log statement, not control flow), so this does not directly corrupt user-facing behavior. However it permanently degrades the reliability of the race-condition detector after the first unrelated exception, producing misleading error-log noise that could mask or be confused with a genuine future race condition.
Source
From: docs/features/potential/2026-07-09-qfc-collectioncontroller-removespecificcontrolgroup-counter-leak.md
Summary
QfcCollectionController.RemoveSpecificControlGroupAsync(QuickFiler/Controllers/QfcCollectionController.cs:1142-1233) increments a static reentrancy counter at method entry but only decrements it at the normal exit path, with notry/finally. Any exception thrown mid-method leaves the counter permanently incremented, which then produces a false-positive "race condition" error log on every subsequent call for the remaining life of the process.Environment
QuickFiler/Controllers/QfcCollectionController.csSteps to Reproduce
QfcCollectionController.cs:1142:private static int removespecificcontrolgroupcounter = 0;RemoveSpecificControlGroupAsync(line 1144):Interlocked.Increment(ref removespecificcontrolgroupcounter);at line 1146 (method entry), followed by ~80 lines of method body (navigation unregister/register, active-item handling), thenInterlocked.Decrement(ref removespecificcontrolgroupcounter);at line 1232 (method's final statement).try/finallywrapping lines 1146-1232.UnregisterNavigation(),RegisterNavigation(), or any of the active-item/theme handling in between.removespecificcontrolgroupcounterremains permanently incremented above its pre-call value.RemoveSpecificControlGroupAsyncnow seesremovespecificcontrolgroupcounter > 1at line 1222 and logslogger.Error("RemoveSpecificControlGroupAsync: Counter is greater than 1. Race Condition Exists")- a false positive, since no concurrent reentrancy is actually occurring.Expected Behavior
The counter should always return to its pre-call value once the method returns or throws, so the race-condition check at line 1222 only fires on genuine concurrent reentrancy, not on a leaked count from an earlier unrelated exception.
Actual Behavior
The decrement is skipped whenever the method body throws, permanently inflating the counter and causing the race-condition detector to report a false positive on every future call, masking the detector's ability to catch a real race condition later (since the counter is already above 1 regardless of actual concurrency).
Logs / Screenshots
QuickFiler/Controllers/QfcCollectionController.cs:1142(counter field),:1146(increment),:1222-1227(race-condition check andlogger.Errorcall),:1232(decrement) - notry/finallypresent. Originally identified indocs/features/archive/2026-07-03-quickfiler-navigation-key-collision-232/evidence/other/follow-up-candidates.md(item 3, "removespecificcontrolgroupcounter reentrancy-counter hygiene"), explicitly deferred as out of scope for issue Bug: quickfiler-navigation-key-collision #232. No open GitHub issue currently references this (verified viagh issue list --search "RemoveSpecificControlGroup").Impact / Severity
The counter is diagnostic/observability-only (it drives a log statement, not control flow), so this does not directly corrupt user-facing behavior. However it permanently degrades the reliability of the race-condition detector after the first unrelated exception, producing misleading error-log noise that could mask or be confused with a genuine future race condition.
Source
From: docs/features/potential/2026-07-09-qfc-collectioncontroller-removespecificcontrolgroup-counter-leak.md