From 75e62cf2afab535260e89516fc15bc807d7bf20b Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 27 Apr 2026 17:50:53 -0700 Subject: [PATCH] Fix dangling pointer crash in PacketReader(byte[], bool) The byte[] constructor pinned the array only for the duration of the fixed block and stored the pointer past the unpin, leaving m_Data referring to a managed array the GC was free to relocate. Reads after a Gen0 compaction would dereference invalid memory and raise AccessViolationException. The most reliable trigger is GetCompressedReader -> CompressedGump, which allocates a string[] between constructing the inner reader and the first ReadInt16 -- opening a Gen0 collection window before any read. Pin the array for the lifetime of the reader via GCHandle and release it from the finalizer; suppress finalize on the byte* overload since the caller owns the pin there. --- Razor/Network/Packet.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Razor/Network/Packet.cs b/Razor/Network/Packet.cs index b0417d80..36ad5f2c 100644 --- a/Razor/Network/Packet.cs +++ b/Razor/Network/Packet.cs @@ -18,6 +18,7 @@ using System; using System.IO; +using System.Runtime.InteropServices; using System.Text; namespace Assistant @@ -789,6 +790,7 @@ public unsafe sealed class PacketReader private int m_Pos; private int m_Length; private bool m_Dyn; + private GCHandle m_Handle; public PacketReader(byte* buff, int len, bool dyn) { @@ -796,17 +798,24 @@ public PacketReader(byte* buff, int len, bool dyn) m_Length = len; m_Pos = 0; m_Dyn = dyn; + GC.SuppressFinalize(this); } public PacketReader(byte[] buff, bool dyn) { - fixed (byte* p = buff) - m_Data = p; + m_Handle = GCHandle.Alloc(buff, GCHandleType.Pinned); + m_Data = (byte*)m_Handle.AddrOfPinnedObject(); m_Length = buff.Length; m_Pos = 0; m_Dyn = dyn; } + ~PacketReader() + { + if (m_Handle.IsAllocated) + m_Handle.Free(); + } + public void MoveToData() { m_Pos = m_Dyn ? 3 : 1;