fix(chat): release Utf8String when linkshell check rejects channel

Cherry-pick from ChatTwo upstream f35b7d3 (Infiziert90, 2026-05-12).

Chat.SetChannel allocates a native Utf8String for the target name and
then runs a validity check. The previous early return on an invalid
linkshell skipped Dtor and leaked the native allocation; every invalid
linkshell switch added one Utf8String to the unmanaged heap.

- Renamed ValidAnyLinkshell to IsChannelOrExistingLinkshell so the
  call-site reads naturally.
- Wrapped ChangeChatChannel in the validity check instead of
  early-returning. Dtor now runs on every path.
- ChatLogWindow follows the rename at its single call-site.
This commit is contained in:
2026-05-12 20:39:23 +02:00
parent f8b5c14509
commit db48f27842
2 changed files with 28 additions and 12 deletions
+22 -9
View File
@@ -423,16 +423,24 @@ internal sealed unsafe class Chat : IDisposable
); );
} }
// Check if channel is valid (non-linkshell or existing linkshell) // ---------------------------------------------------------------
internal static bool ValidAnyLinkshell(InputChannel channel) // Cherry-picked from ChatTwo upstream f35b7d3 (Infiziert90, 2026-05-12)
// - Renamed ValidAnyLinkshell -> IsChannelOrExistingLinkshell. The
// name now states intent: returns true for any non-linkshell
// channel, or a linkshell index that actually exists.
// ---------------------------------------------------------------
internal static bool IsChannelOrExistingLinkshell(InputChannel channel)
{ {
var idx = channel.LinkshellIndex(); var idx = channel.LinkshellIndex();
if (idx == uint.MaxValue || channel.IsExtraChatLinkshell()) if (idx == uint.MaxValue || channel.IsExtraChatLinkshell())
return true; return true;
if (channel.IsLinkshell() && ValidLinkshell(idx))
return true; if (channel.IsLinkshell())
if (channel.IsCrossLinkshell() && ValidCrossLinkshell(idx)) return ValidLinkshell(idx);
return true;
if (channel.IsCrossLinkshell())
return ValidCrossLinkshell(idx);
return false; return false;
} }
@@ -531,12 +539,17 @@ internal sealed unsafe class Chat : IDisposable
if (idx == uint.MaxValue) if (idx == uint.MaxValue)
idx = 0; idx = 0;
if (!ValidAnyLinkshell(channel)) // ---------------------------------------------------------------
return; // Cherry-picked from ChatTwo upstream f35b7d3 (Infiziert90, 2026-05-12)
// - Wrap ChangeChatChannel in the validity check instead of
// early-returning. The previous early return skipped Dtor and
// leaked the native Utf8String allocated a few lines above.
// ---------------------------------------------------------------
if (IsChannelOrExistingLinkshell(channel))
RaptureShellModule RaptureShellModule
.Instance() .Instance()
->ChangeChatChannel(tellTarget != null ? 17 : (int)channel, idx, target, true); ->ChangeChatChannel(tellTarget != null ? 17 : (int)channel, idx, target, true);
target->Dtor(true); target->Dtor(true);
} }
+4 -1
View File
@@ -272,7 +272,10 @@ public sealed class ChatLogWindow : Window
} }
} }
if (targetChannel == null || !GameFunctions.Chat.ValidAnyLinkshell(targetChannel.Value)) if (
targetChannel == null
|| !GameFunctions.Chat.IsChannelOrExistingLinkshell(targetChannel.Value)
)
{ {
Plugin.Log.Warning( Plugin.Log.Warning(
$"Channel was set to an invalid value '{targetChannel}', ignoring" $"Channel was set to an invalid value '{targetChannel}', ignoring"