diff --git a/LibGit2Sharp/Core/GitBuf.cs b/LibGit2Sharp/Core/GitBuf.cs
index 19b1328b9..c19fd8487 100644
--- a/LibGit2Sharp/Core/GitBuf.cs
+++ b/LibGit2Sharp/Core/GitBuf.cs
@@ -3,6 +3,16 @@
namespace LibGit2Sharp.Core.Handles
{
+ ///
+ /// Managed mirror of libgit2's git_buf for APIs that still pass a
+ /// sequential-layout class through the runtime marshaller.
+ ///
+ ///
+ /// Prefer for new or Native AOT-sensitive call
+ /// sites. Under Native AOT, class-based sequential marshalling is effectively
+ /// [In]-only, so native writes to ptr/size never appear in
+ /// managed code.
+ ///
[StructLayout(LayoutKind.Sequential)]
internal class GitBuf : IDisposable
{
@@ -15,4 +25,17 @@ public void Dispose()
Proxy.git_buf_dispose(this);
}
}
+
+ ///
+ /// Blittable git_buf for P/Invoke via ref. Required for Native AOT
+ /// so that libgit2 can write ptr/asize/size back to managed
+ /// memory (class marshalling does not).
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct GitBufNative
+ {
+ public IntPtr ptr;
+ public UIntPtr asize;
+ public UIntPtr size;
+ }
}
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index cbb850b16..be3f62540 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -360,6 +360,9 @@ internal static extern unsafe int git_branch_upstream_name(
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
internal static extern void git_buf_dispose(GitBuf buf);
+ [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern void git_buf_dispose(ref GitBufNative buf);
+
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
internal static extern unsafe int git_checkout_tree(
git_repository* repo,
@@ -468,17 +471,19 @@ internal static extern unsafe int git_config_set_multivar(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string regexp,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string value);
+ // Use ref GitBufNative (not class GitBuf): under Native AOT, sequential
+ // class marshalling does not write ptr/size back to the managed object.
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
- internal static extern int git_config_find_global(GitBuf global_config_path);
+ internal static extern int git_config_find_global(ref GitBufNative global_config_path);
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
- internal static extern int git_config_find_system(GitBuf system_config_path);
+ internal static extern int git_config_find_system(ref GitBufNative system_config_path);
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
- internal static extern int git_config_find_xdg(GitBuf xdg_config_path);
+ internal static extern int git_config_find_xdg(ref GitBufNative xdg_config_path);
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
- internal static extern int git_config_find_programdata(GitBuf programdata_config_path);
+ internal static extern int git_config_find_programdata(ref GitBufNative programdata_config_path);
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
internal static extern unsafe void git_config_free(git_config* cfg);
@@ -1522,7 +1527,7 @@ IntPtr data
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
internal static extern int git_repository_discover(
- GitBuf buf,
+ ref GitBufNative buf,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictFilePathMarshaler))] FilePath start_path,
[MarshalAs(UnmanagedType.Bool)] bool across_fs,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictFilePathMarshaler))] FilePath ceiling_dirs);
diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs
index 83d35e22c..95c7b3325 100644
--- a/LibGit2Sharp/Core/Proxy.cs
+++ b/LibGit2Sharp/Core/Proxy.cs
@@ -2447,7 +2447,7 @@ public static unsafe string git_remote_pushurl(RemoteHandle remote)
public static FilePath git_repository_discover(FilePath start_path)
{
- return ConvertPath(buf => NativeMethods.git_repository_discover(buf, start_path, false, null));
+ return ConvertPath((ref GitBufNative buf) => NativeMethods.git_repository_discover(ref buf, start_path, false, null));
}
public static unsafe bool git_repository_head_detached(RepositoryHandle repo)
@@ -3830,11 +3830,19 @@ private static unsafe bool RepositoryStateChecker(RepositoryHandle repo, Func pathRetriever)
+ private delegate int PathRetriever(ref GitBufNative buf);
+
+ ///
+ /// Invokes a native path-returning API using a blittable .
+ /// Must not use class : Native AOT marshalling does not
+ /// copy native fills of ptr/size back onto sequential-layout classes.
+ ///
+ private static FilePath ConvertPath(PathRetriever pathRetriever)
{
- using (var buf = new GitBuf())
+ var buf = new GitBufNative();
+ try
{
- int result = pathRetriever(buf);
+ int result = pathRetriever(ref buf);
if (result == (int)GitErrorCode.NotFound)
{
@@ -3844,6 +3852,10 @@ private static FilePath ConvertPath(Func pathRetriever)
Ensure.ZeroResult(result);
return LaxFilePathMarshaler.FromNative(buf.ptr);
}
+ finally
+ {
+ NativeMethods.git_buf_dispose(ref buf);
+ }
}
private static readonly IDictionary> configurationParser = new Dictionary>