Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix marshalling of StringBuilder errors #533

Merged
merged 7 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 66 additions & 19 deletions SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,66 @@
return Encoding.GetEncoding(0);
}

/// <summary>
/// Helper class to marshall StringBuilder depending on encoding used by Libpcap
/// </summary>
private class PcapStringBuilderMarshaler : ICustomMarshaler
kayoub5 marked this conversation as resolved.
Show resolved Hide resolved
{

public static ICustomMarshaler GetInstance(string cookie)
{
return new PcapStringBuilderMarshaler();
}

public void CleanUpManagedData(object managedObj)
{

Check warning on line 63 in SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs

View check run for this annotation

Codecov / codecov/patch

SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs#L63

Added line #L63 was not covered by tests
// Nothing to clean
}

Check warning on line 65 in SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs

View check run for this annotation

Codecov / codecov/patch

SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs#L65

Added line #L65 was not covered by tests

public void CleanUpNativeData(IntPtr nativeData)
{
// Nothing to clean
}

public int GetNativeDataSize()
{
return -1;
}

Check warning on line 75 in SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs

View check run for this annotation

Codecov / codecov/patch

SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs#L73-L75

Added lines #L73 - L75 were not covered by tests

public IntPtr MarshalManagedToNative(object managedObj)
{
var builder = (StringBuilder)managedObj;
var byteCount = builder.Capacity + 1;
kayoub5 marked this conversation as resolved.
Show resolved Hide resolved
var gcHandle = GCHandle.ToIntPtr(GCHandle.Alloc(managedObj));

// The problem is that we need a reference to the StringBuilder in MarshalNativeToManaged
// So we get a pointer to it with GCHandle, and put it as prefix of the pointer we return
var ptr = Marshal.AllocHGlobal(byteCount + IntPtr.Size);
Marshal.WriteIntPtr(ptr, gcHandle);
ptr += IntPtr.Size;
return ptr;
}

public unsafe object MarshalNativeToManaged(IntPtr nativeData)
{
var gcHandlePtr = Marshal.ReadIntPtr(nativeData - IntPtr.Size);
var bytes = (byte*)nativeData;
var nbBytes = 0;
while (*(bytes + nbBytes) != 0)
{
nbBytes++;
}
var stringData = StringEncoding.GetString(bytes, nbBytes);

var gcHandle = GCHandle.FromIntPtr(gcHandlePtr);
var stringBuilder = (StringBuilder)gcHandle.Target;
gcHandle.Free();
stringBuilder.Append(stringData);

return null;
}
}

/// <summary>
/// Helper class to marshall string depending on encoding used by Libpcap
/// </summary>
Expand Down Expand Up @@ -90,25 +150,11 @@
{
return IntPtr.Zero;
}
byte[] bytes = null;
var byteCount = 0;
if (managedObj is string str)
{
bytes = StringEncoding.GetBytes(str);
byteCount = bytes.Length + 1;
}

if (managedObj is StringBuilder builder)
{
bytes = StringEncoding.GetBytes(builder.ToString());
byteCount = StringEncoding.GetMaxByteCount(builder.Capacity) + 1;
}

if (bytes is null)
{
throw new ArgumentException("The input argument is not a supported type.");
}
var ptr = Marshal.AllocHGlobal(byteCount);
var str = (string)managedObj;
var bytes = StringEncoding.GetBytes(str);
// The problem is that we need a reference to the StringBuilder in MarshalNativeToManaged
// So we get a pointer to it with GCHandle, and put it as prefix of the pointer we return
var ptr = Marshal.AllocHGlobal(bytes.Length + 1);
Marshal.Copy(bytes, 0, ptr, bytes.Length);
// Put zero string termination
Marshal.WriteByte(ptr + bytes.Length, 0);
Expand All @@ -121,6 +167,7 @@
{
return null;
}
var gcHandlePtr = Marshal.ReadIntPtr(nativeData);
var bytes = (byte*)nativeData;
var nbBytes = 0;
while (*(bytes + nbBytes) != 0)
Expand Down
22 changes: 11 additions & 11 deletions SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ internal static partial class LibPcapSafeNativeMethods
[DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)]
internal extern static int pcap_init(
uint opts,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf
);

[DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)]
internal extern static int pcap_findalldevs(
ref IntPtr /* pcap_if_t** */ alldevs,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf
);

[DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)]
internal extern static int pcap_findalldevs_ex(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string /*char **/source,
ref pcap_rmtauth /*pcap_rmtauth **/auth,
ref IntPtr /*pcap_if_t ** */alldevs,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /*char * */errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /*char * */errbuf
);

[DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)]
Expand All @@ -57,19 +57,19 @@ internal extern static int pcap_findalldevs_ex(
int flags,
int read_timeout,
ref pcap_rmtauth rmtauth,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder errbuf
);

[DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)]
internal extern static PcapHandle /* pcap_t* */ pcap_create(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string dev,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder errbuf
);

[DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)]
internal extern static PcapHandle /* pcap_t* */ pcap_open_offline(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string/*const char* */ fname,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder/* char* */ errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder/* char* */ errbuf
);

[DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)]
Expand Down Expand Up @@ -187,7 +187,7 @@ internal extern static int pcap_compile(
internal extern static int pcap_setnonblock(
PcapHandle /* pcap_if_t** */ adaptHandle,
int nonblock,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf
);

/// <summary>
Expand All @@ -196,7 +196,7 @@ internal extern static int pcap_setnonblock(
[DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)]
internal extern static int pcap_getnonblock(
PcapHandle /* pcap_if_t** */ adaptHandle,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf
);

/// <summary>
Expand Down Expand Up @@ -422,7 +422,7 @@ internal extern static int pcap_tstamp_type_name_to_val(
internal extern static PcapHandle /* pcap_t* */ pcap_open_offline_with_tstamp_precision(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string /* const char* */ fname,
uint precision,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf
);

/// <summary>
Expand Down Expand Up @@ -488,7 +488,7 @@ internal extern static int pcap_tstamp_type_name_to_val(
internal extern static IntPtr /* pcap_t* */ _pcap_hopen_offline_with_tstamp_precision(
SafeHandle handle,
uint precision,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf
);

/// <summary>
Expand All @@ -503,7 +503,7 @@ internal extern static int pcap_tstamp_type_name_to_val(
internal extern static IntPtr /* pcap_t* */ _pcap_fopen_offline_with_tstamp_precision(
SafeHandle fileObject,
uint precision,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf
);
}
}
Loading