1- //#define LEAKS //Uncomment this or add a conditional symbol to activate this mode
1+
2+ // This activates a lightweight mode which will help put under the light
3+ // incorrectly released handles by outputing a warning message in the console.
4+ //
5+ // This should be activated when tests are being run of the CI server.
6+ //
7+ // Uncomment the line below or add a conditional symbol to activate this mode
8+
9+ //#define LEAKS_IDENTIFYING
10+
11+ // This activates a more throrough mode which will show the stack trace of the
12+ // allocation code path for each handle that has been improperly released.
13+ //
14+ // This should be manually activated when some warnings have been raised as
15+ // a result of LEAKS_IDENTIFYING mode activation.
16+ //
17+ // Uncomment the line below or add a conditional symbol to activate this mode
18+
19+ //#define LEAKS_TRACKING
220
321using System ;
22+ using System . Collections . Generic ;
423using System . Diagnostics ;
524using System . Globalization ;
25+ using System . Linq ;
626using System . Runtime . ConstrainedExecution ;
727using System . Runtime . InteropServices ;
828using System . Threading ;
929
30+ #if LEAKS_IDENTIFYING
31+ namespace LibGit2Sharp . Core
32+ {
33+ /// <summary>
34+ /// Holds leaked handle type names reported by <see cref="Core.Handles.SafeHandleBase"/>
35+ /// </summary>
36+ public static class LeaksContainer
37+ {
38+ private static readonly HashSet < string > _typeNames = new HashSet < string > ( ) ;
39+ private static readonly object _lockpad = new object ( ) ;
40+
41+ /// <summary>
42+ /// Report a new leaked handle type name
43+ /// </summary>
44+ /// <param name="typeName">Short name of the leaked handle type.</param>
45+ public static void Add ( string typeName )
46+ {
47+ lock ( _lockpad )
48+ {
49+ _typeNames . Add ( typeName ) ;
50+ }
51+ }
52+
53+ /// <summary>
54+ /// Removes all previously reported leaks.
55+ /// </summary>
56+ public static void Clear ( )
57+ {
58+ lock ( _lockpad )
59+ {
60+ _typeNames . Clear ( ) ;
61+ }
62+ }
63+
64+ /// <summary>
65+ /// Returns all reported leaked handle type names.
66+ /// </summary>
67+ public static IEnumerable < string > TypeNames
68+ {
69+ get { return _typeNames . ToArray ( ) ; }
70+ }
71+ }
72+ }
73+ #endif
74+
1075namespace LibGit2Sharp . Core . Handles
1176{
1277 internal abstract class SafeHandleBase : SafeHandle
1378 {
14- #if LEAKS
79+
80+ #if LEAKS_TRACKING
1581 private readonly string trace ;
82+ private readonly Guid id ;
1683#endif
1784
1885 /// <summary>
@@ -27,26 +94,40 @@ protected SafeHandleBase()
2794 {
2895 NativeMethods . AddHandle ( ) ;
2996 registered = 1 ;
30- #if LEAKS
97+
98+ #if LEAKS_TRACKING
99+ id = Guid . NewGuid ( ) ;
100+ Trace . WriteLine ( string . Format ( CultureInfo . InvariantCulture , "Allocating {0} handle ({1})" , GetType ( ) . Name , id ) ) ;
31101 trace = new StackTrace ( 2 , true ) . ToString ( ) ;
32102#endif
33103 }
34104
35- #if DEBUG
36105 protected override void Dispose ( bool disposing )
37106 {
38- if ( ! disposing && ! IsInvalid )
107+ bool leaked = ! disposing && ! IsInvalid ;
108+
109+ #if LEAKS_IDENTIFYING
110+ if ( leaked )
39111 {
40- Trace . WriteLine ( string . Format ( CultureInfo . InvariantCulture , "A {0} handle wrapper has not been properly disposed." , GetType ( ) . Name ) ) ;
41- #if LEAKS
42- Trace . WriteLine ( trace ) ;
43- #endif
44- Trace . WriteLine ( "" ) ;
112+ LeaksContainer . Add ( GetType ( ) . Name ) ;
45113 }
114+ #endif
46115
47116 base . Dispose ( disposing ) ;
48- }
117+
118+ #if LEAKS_TRACKING
119+ if ( ! leaked )
120+ {
121+ Trace . WriteLine ( string . Format ( CultureInfo . InvariantCulture , "Disposing {0} handle ({1})" , GetType ( ) . Name , id ) ) ;
122+ }
123+ else
124+ {
125+ Trace . WriteLine ( string . Format ( CultureInfo . InvariantCulture , "Unexpected finalization of {0} handle ({1})" , GetType ( ) . Name , id ) ) ;
126+ Trace . WriteLine ( trace ) ;
127+ Trace . WriteLine ( "" ) ;
128+ }
49129#endif
130+ }
50131
51132 // Prevent the debugger from evaluating this property because it has side effects
52133 [ DebuggerBrowsable ( DebuggerBrowsableState . Never ) ]
0 commit comments