chore: code quality sweep 2026-05-04 / 2026-05-05

General code-quality and robustness pass across the plugin: thread-
safety on IPC state, resource-disposal cleanups, input validation,
defensive null-checks and a few small UX glitches. Compliance docs
(THIRD_PARTY_NOTICES, PRIVACY, COPYRIGHT) refreshed to v1.0.3.

Highlights
- ExtraChat IPC state synchronised across threads
- ChatLogWindow autocomplete no longer leaks the unmanaged
  ImGuiListClipper allocation
- ChatLogWindow + Popout style stack stays balanced when config
  toggles mid-frame
- Retention sweep and privacy cleanup wait for the actual filter
  pass instead of the fire-and-forget Task that started it
- Configuration.LatestVersion bumped to 13 to match the active
  migration path
- GameFunctions placeholder buffer guarded against oversized
  replacement names
- TellTarget.IsSet, ResolveTempInputChannel, InputPreview, IconUtil,
  Lender, Payloads, ExtraPayload all hardened against null / empty /
  EOF / cycle inputs
- FontManager Lodestone download stays in scope for a follow-up
  (timeout + lazy init pending)
- AutoTranslate replaced the msvcrt.dll memcmp P/Invoke with a
  managed Span comparison
- Privacy cleanup worker thread marked IsBackground = true
- Database cleanup now removes both legacy files in one click
- Tell-target name redacted in the verbose debug log

Compliance
- THIRD_PARTY_NOTICES: last-reviewed bumped to v1.0.3, Pidgin 3.5.1,
  SQLitePCLRaw.lib.e_sqlite3 3.50.3 listed as direct dependency with
  CVE-2025-6965 / CVE-2025-7709 rationale
- PRIVACY: last-reviewed bumped to v1.0.3, BetterTTV trigger wording
  clarified (list fetch at startup vs. on-demand image fetch)
- COPYRIGHT: upstream attribution range widened

Build: 0 warnings, 0 errors. No behavioural changes that would alter
existing user configuration or stored chat history.
This commit is contained in:
2026-05-05 07:25:47 +02:00
parent 698eb01bbe
commit 4d54eabdac
26 changed files with 251 additions and 98 deletions
+10 -3
View File
@@ -615,7 +615,7 @@ internal sealed class Privacy : ISettingsTab
CleanupRunning = true;
var allowed = Plugin.Config.PrivacyPersistChannels.Select(t => (int)(ushort)t).ToList();
new Thread(() =>
var thread = new Thread(() =>
{
try
{
@@ -625,10 +625,14 @@ internal sealed class Privacy : ISettingsTab
// Bound the wait so a hung framework tick can't deadlock
// the background cleanup worker. See the matching comment in
// the retention path above for rationale.
// Note: FilterAllTabs() is called synchronously instead of
// FilterAllTabsAsync() — the async variant fires-and-forgets
// a Task.Run, so the .Wait() would return before the filter
// pass actually finishes. See AUDIT-2026-05-05 [QUAL-02].
if (!Plugin.Framework.Run(() =>
{
Plugin.MessageManager.ClearAllTabs();
Plugin.MessageManager.FilterAllTabsAsync();
Plugin.MessageManager.FilterAllTabs();
}).Wait(TimeSpan.FromSeconds(5)))
{
Plugin.Log.Warning("Privacy cleanup: framework refresh timed out after 5s.");
@@ -646,6 +650,9 @@ internal sealed class Privacy : ISettingsTab
CleanupRunning = false;
CleanupCounts = null;
}
}).Start();
});
// Background thread so a still-running cleanup doesn't hold up FFXIV exit.
thread.IsBackground = true;
thread.Start();
}
}