Skip to content

Wrap git_trace_set to hold a reference to trace method to prevent GC. #915

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Wrap git_trace_set to hold a reference to trace method to prevent GC. #915

wants to merge 1 commit into from

Conversation

jeffhostetler
Copy link
Contributor

Have NativeMethod layer hold a reference to the trace handler that we give to LibGit2 so that it won't be GC'd if the caller doesn't persist it properly.

I do question why this was necessary since GlobalSettings is holding a static LogConfiguration which contains a reference to the handler.

I don't have a test for the change since I couldn't figure out how to cause logging to happen from a test since everything is private and libgit2 doesn't have many calls to logging.

Please advise.
Thanks.

/// </summary>
public static int git_trace_set(LogLevel level, git_trace_cb trace_cb)
{
static_trace_cb = trace_cb;
Copy link
Member

Choose a reason for hiding this comment

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

Why not GC.KeepAlive in the caller?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I suppose, but that means all callers of git_trace_set() would need to do that to be completely safe. There's also the issue of when/if those callers could/should undo the KeepAlive on the method.

To me, it seemed that since this routine is stuffing a handle/object into LibGit2 for later use, it is responsible for holding the reference. And that reference should persist until we either clear or pass down a different object. (I guess technically, LibGit2 should call back into the CLR to declare that it is holding the reference, but this seemed more straight-forward.)

Copy link
Member

Choose a reason for hiding this comment

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

KeepAlive is just a an empty non-inlined method that will keep the object alive. What 'undo' are you talking about? :P

If this should persist for more time, I'd rather have this documented and tell the user. I don't want this to be kept alive for lifetime if the user doesn't want it to. /cc @nulltoken

Having it kept inside LibGit2Sharp would mean never having it freed. That can impact the user in case we're using delegates which keep other things in memory. Rather leave it in user control rather than a cache that might fail way harder than we think it should?

While it's true that the user can set the value to null and free it, I don't know how sure I am of this way of doing it.

Copy link
Member

Choose a reason for hiding this comment

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

For GC.KeepAlive check this and see how it works. It just makes an empty call that will trick the GC into thinking that the variable is used, so it can't reclaim it.

@jamill
Copy link
Member

jamill commented Jan 18, 2015

Thanks @jeffhostetler for this!

I am not sure if using GC.KeepAlive would help here - I think the problem is that there is no managed reference to the delegate past the scope of the Proxy.git_trace_set function, so calling GC.KeepAlive at the end of the function would not be sufficient.

I wonder if explicitly storing the delegate for GitTraceHandler in LogConfiguration, and passing that delegate instead of the GitTraceHandler to Proxy.git_trace_set would also prevent the garbage collection issue.

Assuming the above proposal even works, I think either the current solution proposed by @jeffhostetler (but I would move the static variable logic into the Proxy layer), or putting the onus on callers into Proxy.git_trace_set and documenting the method as @Therzok suggested would work. Keeping the logic closer to the native function call would make it harder for callers to misuse this function in a subtle way, which is nice. We control all the callers into Proxy.git_trace_set and how they set up the callback.

@jeffhostetler
Copy link
Contributor Author

Thanks to both @jamill and @Therzok for the suggestions and comments. I found a better solution and will close this PR and submit a new PR with that change.

@nulltoken nulltoken added this to the UnmergedOrDoNotRequireAFix milestone Jan 19, 2015
@jeffhostetler jeffhostetler deleted the jeffhostetler/hold_git_trace_reference branch September 22, 2015 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants