1- using System ;
1+ // This activates a lightweight mode which will help put under the light
2+ // incorrectly released handles by outputing a warning message in the console.
3+ //
4+ // This should be activated when tests are being run of the CI server.
5+ //
6+ // Uncomment the line below or add a conditional symbol to activate this mode
7+
8+ // #define LEAKS_IDENTIFYING
9+
10+ // This activates a more throrough mode which will show the stack trace of the
11+ // allocation code path for each handle that has been improperly released.
12+ //
13+ // This should be manually activated when some warnings have been raised as
14+ // a result of LEAKS_IDENTIFYING mode activation.
15+ //
16+ // Uncomment the line below or add a conditional symbol to activate this mode
17+
18+ // #define LEAKS_TRACKING
19+
20+ using System ;
21+ using System . Linq ;
22+ using System . Diagnostics ;
23+ using System . Globalization ;
24+ using System . Collections . Generic ;
25+
26+ #if LEAKS_IDENTIFYING
27+ namespace LibGit2Sharp . Core
28+ {
29+ /// <summary>
30+ /// Holds leaked handle type names reported by <see cref="Core.Handles.Libgit2Object"/>
31+ /// </summary>
32+ public static class LeaksContainer
33+ {
34+ private static readonly HashSet < string > _typeNames = new HashSet < string > ( ) ;
35+ private static readonly object _lockpad = new object ( ) ;
36+
37+ /// <summary>
38+ /// Report a new leaked handle type name
39+ /// </summary>
40+ /// <param name="typeName">Short name of the leaked handle type.</param>
41+ public static void Add ( string typeName )
42+ {
43+ lock ( _lockpad )
44+ {
45+ _typeNames . Add ( typeName ) ;
46+ }
47+ }
48+
49+ /// <summary>
50+ /// Removes all previously reported leaks.
51+ /// </summary>
52+ public static void Clear ( )
53+ {
54+ lock ( _lockpad )
55+ {
56+ _typeNames . Clear ( ) ;
57+ }
58+ }
59+
60+ /// <summary>
61+ /// Returns all reported leaked handle type names.
62+ /// </summary>
63+ public static IEnumerable < string > TypeNames
64+ {
65+ get
66+ {
67+ string [ ] result = null ;
68+ lock ( _lockpad )
69+ {
70+ result = _typeNames . ToArray ( ) ;
71+ }
72+ return result ;
73+ }
74+ }
75+ }
76+ }
77+ #endif
278
379namespace LibGit2Sharp . Core . Handles
480{
581 internal unsafe abstract class Libgit2Object : IDisposable
682 {
83+ #if LEAKS_TRACKING
84+ private readonly string trace ;
85+ private readonly Guid id ;
86+ #endif
87+
788 protected void * ptr ;
889
990 internal void * Handle
@@ -21,12 +102,17 @@ internal unsafe Libgit2Object(void* handle, bool owned)
21102 {
22103 this . ptr = handle ;
23104 this . owned = owned ;
105+
106+ #if LEAKS_TRACKING
107+ id = Guid . NewGuid ( ) ;
108+ Trace . WriteLine ( string . Format ( CultureInfo . InvariantCulture , "Allocating {0} handle ({1})" , GetType ( ) . Name , id ) ) ;
109+ trace = new StackTrace ( 2 , true ) . ToString ( ) ;
110+ #endif
24111 }
25112
26113 internal unsafe Libgit2Object ( IntPtr ptr , bool owned )
114+ : this ( ptr . ToPointer ( ) , owned )
27115 {
28- this . ptr = ptr . ToPointer ( ) ;
29- this . owned = owned ;
30116 }
31117
32118 ~ Libgit2Object ( )
@@ -51,6 +137,15 @@ internal IntPtr AsIntPtr()
51137
52138 void Dispose ( bool disposing )
53139 {
140+ #if LEAKS_IDENTIFYING
141+ bool leaked = ! disposing && ptr != null ;
142+
143+ if ( leaked )
144+ {
145+ LeaksContainer . Add ( GetType ( ) . Name ) ;
146+ }
147+ #endif
148+
54149 if ( ! disposed )
55150 {
56151 if ( owned )
@@ -62,6 +157,19 @@ void Dispose(bool disposing)
62157 }
63158
64159 disposed = true ;
160+
161+ #if LEAKS_TRACKING
162+ if ( ! leaked )
163+ {
164+ Trace . WriteLine ( string . Format ( CultureInfo . InvariantCulture , "Disposing {0} handle ({1})" , GetType ( ) . Name , id ) ) ;
165+ }
166+ else
167+ {
168+ Trace . WriteLine ( string . Format ( CultureInfo . InvariantCulture , "Unexpected finalization of {0} handle ({1})" , GetType ( ) . Name , id ) ) ;
169+ Trace . WriteLine ( trace ) ;
170+ Trace . WriteLine ( "" ) ;
171+ }
172+ #endif
65173 }
66174
67175 public void Dispose ( )
0 commit comments