8000 Prevent Repository objects from being prematurely GCed by jcansdale · Pull Request #1337 · github/VisualStudio · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Prevent Repository objects from being prematurely GCed #1337

Merged
merged 11 commits into from
Nov 28, 2017

Conversation

jcansdale
Copy link
Collaborator
@jcansdale jcansdale commented Nov 23, 2017

The Bug

The following code can fail on the repo.RetrieveStatus() line with an AccessViolationException:

var repo = new Repository(path);
var status = repo.RetrieveStatus();

This is because RetrieveStatus creates a native pointer to the Repository object and but doesn't hold on to a managed reference. This allows the Repository object to be GCed before RetrieveStatus has finished with the native pointer.

To vaoid random crashes, we need to be careful to keep a reference to Repository when calling its methods. The above code can be fixed like this:

var repo = new Repository(path);
var status = repo.RetrieveStatus();
GC.KeepAlive(repo);

Alternatively since the Repository object implements IDisposable, the following will keep a reference and dispose of it afterwards:

using (var repo = new Repository(path))
{
    var status = repo.RetrieveStatus();
}

This PR wraps all temporary references to a Repository object in a using statement.

Possible Gotchas

  • This bug only shows up when the extension is compiled in Release configuration (in Debug configuration, references are held on to for longer and this bug doesn't occur).
  • We need to make sure we don't return objects that keep references to disposed Repository objects. For example here, we need to make sure that CommitMessage doesn't cache a reference to the disposed Repository object:
    return gitClient.GetMessagesForUniqueCommits(repo, baseBranch, compareBranch, maxCommits).ToObservable();

Fixes #1315
See also: libgit2/libgit2sharp#1513

By wrapping the Repository object in a using statement we prevent it from being being GCed when there are only native pointers to it.
@jcansdale jcansdale changed the title Prevent Repository objects from being prematurely GCed [WIP] Prevent Repository objects from being prematurely GCed Nov 23, 2017
@jcansdale jcansdale changed the title [WIP] Prevent Repository objects from being prematurely GCed Prevent Repository objects from being prematurely GCed Nov 24, 2017
@jcansdale
Copy link
Collaborator Author

I got the following when trying to create a new PR:

image

 	LibGit2Sharp.dll!LibGit2Sharp.Core.Proxy.git_revparse_ext(LibGit2Sharp.Core.Handles.RepositoryHandle repo, string objectish)	Unknown
 	LibGit2Sharp.dll!LibGit2Sharp.Core.Proxy.git_revparse_single(LibGit2Sharp.Core.Handles.RepositoryHandle repo, string objectish)	Unknown
 	LibGit2Sharp.dll!LibGit2Sharp.Repository.Lookup(string objectish, LibGit2Sharp.Core.GitObjectType type, LibGit2Sharp.Core.LookUpOptions lookUpOptions)	Unknown
 	LibGit2Sharp.dll!LibGit2Sharp.Repository.Lookup(string objectish, LibGit2Sharp.ObjectType type)	Unknown
 	LibGit2Sharp.dll!LibGit2Sharp.RepositoryExtensions.Lookup<LibGit2Sharp.Commit>(LibGit2Sharp.IRepository repository, string objectish)	Unknown
>	GitHub.App.dll!GitHub.Services.GitClient.GetMessagesForUniqueCommits.AnonymousMethod__0() Line 486	C#

// CommitMessage doesn't keep a reference to Repository
using (var repo = gitService.GetRepository(repository.LocalPath))
{
return gitClient.GetMessagesForUniqueCommits(repo, baseBranch, compareBranch, maxCommits).ToObservable();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToObservable / threading issue.

< 8000 div class="AvatarStack flex-self-start " >
@jcansdale jcansdale force-pushed the fixes/1315-using-repository branch from 08afc5c to 4db51b2 Compare November 24, 2017 12:56
using (var repo = gitService.GetRepository(repository.LocalPath))
{
var result = GetLocalBranchesInternal(repository, repo, pullRequest).Select(x => new BranchModel(x, repository));
return result.ToObservable();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@grokys I have a bad feeling about this one. What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, as expected!
image

Copy link
Contributor
@grokys grokys Nov 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yeah, should probably call ToList() on result here.

For reference, the other option is to destroy the repo with a Using operator, I don't think that'd be necessary here however.

We don't want to dispose of Repository while still enumerating its branches.
@jcansdale
Copy link
Collaborator Author

Hmmm.

image

@jcansdale
Copy link
Collaborator Author

I'm seeing an issue where after clicking the checkout link, the checkout appears to succeed but the UI doesn't update. Any idea what might be causing that?

@grokys
Copy link
Contributor
grokys commented Nov 24, 2017

I'm seeing an issue where after clicking the checkout link, the checkout appears to succeed but the UI doesn't update. Any idea what might be causing that?

Not seen that before. Does it happen on master?

@jcansdale
Copy link
Collaborator Author
jcansdale commented Nov 24, 2017

@grokys I thought this was likely an issue introduced with this PR. Haven't seen it on master before.

Update, this is also happening on master. 😕

grokys
grokys previously approved these changes Nov 27, 2017
Copy link
Contributor
@grokys grokys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 LGTM! Just a small nit about a commented-out line.

repository.Dispose();

// NOTE: IDiffService doesn't own the Repository object
//repository.Dispose();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather remove this commented-out line.

@jcansdale jcansdale merged commit 9002364 into master Nov 28, 2017
@jcansdale jcansdale deleted the fixes/1315-using-repository branch November 28, 2017 10:25
9153
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Find out why / when LibGit2Sharp is crashing
2 participants
0