libgit2sharp icon indicating copy to clipboard operation
libgit2sharp copied to clipboard

Intermittent access violation when calling Repository.RetreiveStatus

Open davecader opened this issue 5 years ago • 8 comments

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

davecader avatar Aug 28 '19 09:08 davecader

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)

davecader avatar Sep 04 '19 15:09 davecader

To look at the important background information first: are you re-using a Repository object across threads or doing anything interesting with async here?

ethomson avatar Sep 05 '19 09:09 ethomson

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.

davecader avatar Sep 05 '19 11:09 davecader

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.

davecader avatar Sep 11 '19 16:09 davecader

This is still on ongoing problem that occurs at least a couple times every day.

davecader avatar Feb 26 '20 11:02 davecader

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 avatar Jun 23 '21 08:06 Xcone

@Xcone See #1884, this is likely fixed in 0.27.0-preview-0100.

bording avatar Jun 23 '21 18:06 bording

Yup; updating to that preview fixed it, indeed. Thanks!

Xcone avatar Jun 25 '21 07:06 Xcone