fix(work): 修复指针 Double Free 问题

This commit is contained in:
Fu Diwei
2023-05-19 18:29:26 +08:00
parent 830d8bf9ec
commit 03b3a3166e
5 changed files with 51 additions and 94 deletions

View File

@@ -32,8 +32,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance.InteropServices
public static extern void FreeSlice([In] IntPtr slice);
[DllImport(DLL_NAME, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]
public static extern string GetContentFromSlice([In] IntPtr slice);
public static extern IntPtr GetContentFromSlice([In] IntPtr slice);
[DllImport(DLL_NAME, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSliceLen([In] IntPtr slice);
@@ -45,7 +44,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance.InteropServices
public static extern void FreeMediaData([In] IntPtr mediaData);
[DllImport(DLL_NAME, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern string GetOutIndexBuf([In] IntPtr mediaData);
public static extern IntPtr GetOutIndexBuf([In] IntPtr mediaData);
[DllImport(DLL_NAME, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetData([In] IntPtr mediaData);

View File

@@ -42,8 +42,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance.InteropServices
[DllImport(DLL_NAME, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]
public static extern string GetContentFromSlice([In] IntPtr slice);
public static extern IntPtr GetContentFromSlice([In] IntPtr slice);
[DllImport(DLL_NAME, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
[SuppressUnmanagedCodeSecurity]
@@ -59,7 +58,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance.InteropServices
[DllImport(DLL_NAME, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
[SuppressUnmanagedCodeSecurity]
public static extern string GetOutIndexBuf([In] IntPtr mediaData);
public static extern IntPtr GetOutIndexBuf([In] IntPtr mediaData);
[DllImport(DLL_NAME, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
[SuppressUnmanagedCodeSecurity]

View File

@@ -0,0 +1,41 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance.InteropServices
{
internal static class MarshalerHelper
{
public static string PtrToStringAnsi(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return default!;
return Marshal.PtrToStringAnsi(ptr)!;
}
public static string PtrToStringUTF8(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return default!;
#if NETCOREAPP || NET5_0_OR_GREATER
return Marshal.PtrToStringUTF8(ptr)!;
#else
byte b;
int offset = 0;
do
{
b = Marshal.ReadByte(ptr, offset);
offset++;
}
while (b != 0);
byte[] bytes = new byte[offset - 1];
Marshal.Copy(ptr, bytes, 0, bytes.Length);
return Encoding.UTF8.GetString(bytes);
#endif
}
}
}

View File

@@ -1,83 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance.InteropServices
{
internal sealed class UTF8Marshaler : ICustomMarshaler
{
private static readonly Lazy<UTF8Marshaler> _instance = new Lazy<UTF8Marshaler>(() => new UTF8Marshaler());
public static ICustomMarshaler GetInstance(string pstrCookie)
{
return _instance.Value;
}
public static string? PtrToStringUTF8(IntPtr pNativeData)
{
return _instance.Value.MarshalNativeToManaged(pNativeData) as string;
}
public IntPtr MarshalManagedToNative(object managedObj)
{
if (managedObj is null)
return IntPtr.Zero;
if (!(managedObj is string))
throw new InvalidOperationException();
byte[] bytes = Encoding.UTF8.GetBytes((string)managedObj);
IntPtr pNativeData = Marshal.AllocHGlobal(bytes.Length + 1);
Marshal.Copy(bytes, 0, pNativeData, bytes.Length);
Marshal.WriteByte(pNativeData, bytes.Length, 0);
return pNativeData;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
if (pNativeData == IntPtr.Zero)
return default!;
#if NETCOREAPP || NET5_0_OR_GREATER
return Marshal.PtrToStringUTF8(pNativeData)!;
#else
byte b;
int offset = 0;
do
{
b = Marshal.ReadByte(pNativeData, offset);
offset++;
}
while (b != 0);
byte[] bytes = new byte[offset - 1];
Marshal.Copy(pNativeData, bytes, 0, bytes.Length);
return Encoding.UTF8.GetString(bytes);
#endif
}
public void CleanUpManagedData(object managedObj)
{
}
public void CleanUpNativeData(IntPtr pNativeData)
{
if (pNativeData == IntPtr.Zero)
{
return;
}
/**
* NOTICE:
* 这里释放内存会导致外部 P/Invoke 调用 FreeSlice() 方法时抛出异常
* 因此请注释下面的代码
*/
// Marshal.FreeHGlobal(pNativeData);
}
public int GetNativeDataSize()
{
return -1;
}
}
}

View File

@@ -129,10 +129,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance
// IsRunOnWindows() ? FinanceDllWindowsPInvoker.GetSliceLen(dataPtr) :
// IsRunOnLinux() ? FinanceDllLinuxPInvoker.GetSliceLen(dataPtr) :
// throw new PlatformNotSupportedException();
string dataContent = /* 获取聊天记录数据内容 */
IntPtr dataContentPtr = /* 获取聊天记录数据内容 */
IsRunOnWindows() ? FinanceDllWindowsPInvoker.GetContentFromSlice(dataPtr) :
IsRunOnLinux() ? FinanceDllLinuxPInvoker.GetContentFromSlice(dataPtr) :
throw new PlatformNotSupportedException();
string dataContent = MarshalerHelper.PtrToStringUTF8(dataContentPtr);
response = JsonSerializer.Deserialize<Models.GetChatRecordsResponse>(dataContent);
response.RawBytes = Encoding.UTF8.GetBytes(dataContent);
@@ -220,10 +221,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance
// IsRunOnWindows() ? FinanceDllWindowsPInvoker.GetSliceLen(dataPtr) :
// IsRunOnLinux() ? FinanceDllLinuxPInvoker.GetSliceLen(dataPtr) :
// throw new PlatformNotSupportedException();
string dataContent = /* 获取聊天记录数据内容 */
IntPtr dataContentPtr = /* 获取聊天记录数据内容 */
IsRunOnWindows() ? FinanceDllWindowsPInvoker.GetContentFromSlice(dataPtr) :
IsRunOnLinux() ? FinanceDllLinuxPInvoker.GetContentFromSlice(dataPtr) :
throw new PlatformNotSupportedException();
string dataContent = MarshalerHelper.PtrToStringUTF8(dataContentPtr);
response = JsonSerializer.Deserialize<Models.DecryptChatRecordResponse>(dataContent);
response.RawBytes = Encoding.UTF8.GetBytes(dataContent);
@@ -293,7 +295,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance
IsRunOnWindows() ? FinanceDllWindowsPInvoker.GetData(dataPtr) :
IsRunOnLinux() ? FinanceDllLinuxPInvoker.GetData(dataPtr) :
throw new PlatformNotSupportedException();
string dataNextBufferIndex = /* 获取媒体文件数据内容缓冲标识 */
IntPtr dataNextBufferIndex = /* 获取媒体文件数据内容缓冲标识 */
IsRunOnWindows() ? FinanceDllWindowsPInvoker.GetOutIndexBuf(dataPtr) :
IsRunOnLinux() ? FinanceDllLinuxPInvoker.GetOutIndexBuf(dataPtr) :
throw new PlatformNotSupportedException();
@@ -304,10 +306,9 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance
byte[] bytes = new byte[dataSize];
Marshal.Copy(dataContentPtr, bytes, 0, bytes.Length);
Marshal.FreeHGlobal(dataContentPtr);
response.FileBufferBytes = bytes;
response.NextBufferIndex = dataNextBufferIndex;
response.NextBufferIndex = MarshalerHelper.PtrToStringAnsi(dataNextBufferIndex);
response.IsFinished = dataIsFinishFlag != 0;
}