libgit2sharp
libgit2sharp copied to clipboard
Intermittent access violation when calling Repository.RetreiveStatus
We are receiving an intermittent Access Violation exception when invoking Repository.RetrieveStatus. It does not happen often, but it is a fatal error when it does occur. The code looks something like this:
var options = new StatusOptions { IncludeUntracked = true };
var statusResult = repository.RetrieveStatus(options).ToList();
Version of LibGit2Sharp is 0.26.0
Operating system(s) tested is Windows 10 Pro (10.0.17763) .NET runtime tested is 4.7.1
Stack Trace for exception, when it occurs. Hope this helps.
at LibGit2Sharp.Core.NativeMethods.git_status_list_new(git_status_list*& git_status_list, git_repository* repo, GitStatusOptions options) at LibGit2Sharp.Core.Proxy.git_status_list_new(RepositoryHandle repo, GitStatusOptions options) at LibGit2Sharp.RepositoryStatus..ctor(Repository repo, StatusOptions options) at LibGit2Sharp.Repository.RetrieveStatus(StatusOptions options)
To look at the important background information first: are you re-using a Repository
object across threads or doing anything interesting with async
here?
The method that encapsulates this code is not itself asynchronous, but it is being executed within a background thread. This particular Repository instance is instantiated and disposed within the body of the method and is not being shared. With that being said, there are other background threads interacting with the targetted Git repository (one for branches, one for status, etc.) but each one would create and dispose of its own instance of the Repository class as required. In other words, no instances of the Repository class are shared, but it is possible that multiple instances of the Repository class could be active and interacting with the targeted Git repo at any given time.
As earlier posts in this thread implied this might be a threading issue, I encapsulated all of my calls to LibGit2Sharp in a single client class and used a lock to ensure that only only one call to the repository could occur at an given time.
Unfortunately, this did not work and the intermittent access violation that I was having when calling the RetrieveStatus method is still occurring.
This is still on ongoing problem that occurs at least a couple times every day.
I have an access violation consistantly since earlier this week when calling RetrieveStatus()
on a repository. I have some bare minimum code that is already being problematic.
public bool HasUncommittedChanges()
{
using (var git = new Repository(Directory.FullName))
{
return git.RetrieveStatus().IsDirty;
}
}
This method is being called from another thread then the main thread in a UI, but as it has its own instance of repository this has never been an issue; until it spontaniously occurred earlier this week.
I also have a CLI tool to perform a series of repo related tasks, in this instance a command to close a feature branch. It also throws:
[Verb("finish-branch", HelpText = "Fast-forwards or merges the checked out branch into develop, pushes it, and deletes the branch.")]
internal class FinishBranchCommand : IParsedCommand
{
public async Task RunAsync()
{
var directoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory());
using (var git = new Repository(directoryInfo.FullName))
{
await Cli.ExecuteAsync(directoryInfo, "git", "fetch");
if (!git.TryGetCheckedOutBranch(out var checkedOutBranch))
{
throw new PreconditionException("This commands needs a checked out branch. Are you in detached HEAD mode?");
}
if (BranchName.IsReserved(checkedOutBranch.FriendlyName))
{
throw new PreconditionException("Cannot finish a reserved branch. This command is intended for feature, fix, or chore branches.");
}
if (git.RetrieveStatus().IsDirty)
{
throw new PreconditionException("Uncommitted changes. Clean up before running command.");
}
// ..... and so on
Here I can see RetrieveStatus() being the problem as well, and the other interactions working just fine. Note that TryGetCheckedOutBranch
is an extention method
public static bool TryGetCheckedOutBranch(this Repository git, out Branch result)
{
result = git.Branches.FirstOrDefault(b => b.FriendlyName == git.Head.FriendlyName);
return result != null;
}
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Repeat 2 times:
--------------------------------
at LibGit2Sharp.Core.NativeMethods.git_status_list_new(LibGit2Sharp.Core.git_status_list* ByRef, LibGit2Sharp.Core.git_repository*, LibGit2Sharp.Core.GitStatusOptions)
--------------------------------
at LibGit2Sharp.Core.Proxy.git_status_list_new(LibGit2Sharp.Core.Handles.RepositoryHandle, LibGit2Sharp.Core.GitStatusOptions)
at LibGit2Sharp.RepositoryStatus..ctor(LibGit2Sharp.Repository, LibGit2Sharp.StatusOptions)
at LibGit2Sharp.RepositoryExtensions.RetrieveStatus(LibGit2Sharp.IRepository)
at TKH.Wow.DotNetTool.FinishBranchCommand+<RunAsync>d__0.MoveNext()
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[TKH.Wow.DotNetTool.FinishBranchCommand+<RunAsync>d__0, TKH.Wow.DotNetTool, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null]].ExecutionContextCallback(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[TKH.Wow.DotNetTool.FinishBranchCommand+<RunAsync>d__0, TKH.Wow.DotNetTool, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext(System.Threading.Thread)
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[TKH.Wow.DotNetTool.FinishBranchCommand+<RunAsync>d__0, TKH.Wow.DotNetTool, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Runtime.CompilerServices.IAsyncStateMachineBox, Boolean)
at System.Threading.Tasks.Task.RunContinuations(System.Object)
at System.Threading.Tasks.Task.FinishContinuations()
at System.Threading.Tasks.Task.FinishStageThree()
at System.Threading.Tasks.Task.FinishStageTwo()
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread)
at System.Threading.Tasks.Task.ExecuteEntryUnsafe(System.Threading.Thread)
at System.Threading.Tasks.Task.ExecuteFromThreadPool(System.Threading.Thread)
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Both examples have been without any issues for months now. And without change on my part they started failing this week.
@Xcone See #1884, this is likely fixed in 0.27.0-preview-0100.
Yup; updating to that preview fixed it, indeed. Thanks!