Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
23 changes: 23 additions & 0 deletions LibGit2Sharp/Core/GitBuf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@

namespace LibGit2Sharp.Core.Handles
{
/// <summary>
/// Managed mirror of libgit2's <c>git_buf</c> for APIs that still pass a
/// sequential-layout class through the runtime marshaller.
/// </summary>
/// <remarks>
/// Prefer <see cref="GitBufNative"/> for new or Native AOT-sensitive call
/// sites. Under Native AOT, class-based sequential marshalling is effectively
/// [In]-only, so native writes to <c>ptr</c>/<c>size</c> never appear in
/// managed code.
/// </remarks>
[StructLayout(LayoutKind.Sequential)]
internal class GitBuf : IDisposable
{
Expand All @@ -15,4 +25,17 @@ public void Dispose()
Proxy.git_buf_dispose(this);
}
}

/// <summary>
/// Blittable <c>git_buf</c> for P/Invoke via <c>ref</c>. Required for Native AOT
/// so that libgit2 can write <c>ptr</c>/<c>asize</c>/<c>size</c> back to managed
/// memory (class marshalling does not).
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct GitBufNative
{
public IntPtr ptr;
public UIntPtr asize;
public UIntPtr size;
}
}
15 changes: 10 additions & 5 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
20 changes: 16 additions & 4 deletions LibGit2Sharp/Core/Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -3830,11 +3830,19 @@ private static unsafe bool RepositoryStateChecker(RepositoryHandle repo, Func<In
return (res == 1);
}

private static FilePath ConvertPath(Func<GitBuf, int> pathRetriever)
private delegate int PathRetriever(ref GitBufNative buf);

/// <summary>
/// Invokes a native path-returning API using a blittable <see cref="GitBufNative"/>.
/// Must not use class <see cref="GitBuf"/>: Native AOT marshalling does not
/// copy native fills of ptr/size back onto sequential-layout classes.
/// </summary>
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)
{
Expand All @@ -3844,6 +3852,10 @@ private static FilePath ConvertPath(Func<GitBuf, int> pathRetriever)
Ensure.ZeroResult(result);
return LaxFilePathMarshaler.FromNative(buf.ptr);
}
finally
{
NativeMethods.git_buf_dispose(ref buf);
}
}

private static readonly IDictionary<Type, Func<string, object>> configurationParser = new Dictionary<Type, Func<string, object>>
Expand Down
Loading