10000 Big improvement to unit testing. · openssl-net/openssl-net@d187fcd · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.

Commit d187fcd

Browse files
author
Frank Laub
committed
Big improvement to unit testing.
* Add Trace build configuration so that MemoryTracker can be enabled. * Replace MemoryTracker with interceptions of malloc/realloc/free. * Get SSL tests to work again.
1 parent acfcedd commit d187fcd

33 files changed

+669
-471
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ dist
1212
.DS_Store
1313
test-results
1414
TestResult.xml
15+
test/openssl.net.VisualState.xml

ManagedOpenSsl/Core/Asn1String.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace OpenSSL.Core
3131
/// <summary>
3232
/// Wraps ASN1_STRING_*
3333
/// </summary>
34-
public class Asn1String : BaseValue<Asn1String>, IComparable<Asn1String>
34+
public class Asn1String : BaseValue, IComparable<Asn1String>
3535
{
3636
#region Initialization
3737
/// <summary>

ManagedOpenSsl/Core/Base.cs

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -168,40 +168,20 @@ private void DoAfterDispose()
168168
/// <summary>
169169
/// Helper type that handles the AddRef() method.
170170
/// </summary>
171-
public abstract class BaseReference<T> : Base
172-
where T : BaseReference<T>
171+
public abstract class BaseReference : Base
173172
{
174173
internal BaseReference(IntPtr ptr, bool takeOwnership)
175174
: base(ptr, takeOwnership)
176175
{
177176
}
178177

179178
internal abstract void AddRef();
180-
181-
internal T CopyRef()
182-
{
183-
object[] args = {
184-
ptr,
185-
true
186-
};
187-
188-
var flags =
189-
BindingFlags.NonPublic |
190-
BindingFlags.Public |
191-
BindingFlags.Instance;
192-
193-
var ret = (T)Activator.CreateInstance(typeof(T), flags, null, args, null);
194-
ret.AddRef();
195-
196-
return ret;
197-
}
198179
}
199180

200181
/// <summary>
201182
/// Derived classes must implement the <code>LockType</code> and <code>RawReferenceType</code> properties
202183
/// </summary>
203-
public abstract class BaseReferenceImpl<T> : BaseReference<T>
204-
where T : BaseReference<T>
184+
public abstract class BaseReferenceImpl : BaseReference
205185
{
206186
internal BaseReferenceImpl(IntPtr ptr, bool takeOwnership)
207187
: base(ptr, takeOwnership)
@@ -245,8 +225,7 @@ internal override void AddRef()
245225
/// <summary>
246226
/// Helper base class that handles the AddRef() method by using a _dup() method.
247227
/// </summary>
248-
public abstract class BaseValue<T> : BaseReference<T>
249-
where T : BaseReference<T>
228+
public abstract class BaseValue : BaseReference
250229
{
251230
internal BaseValue(IntPtr ptr, bool takeOwnership)
252231
: base(ptr, takeOwnership)

ManagedOpenSsl/Core/Crypto.cs

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -127,24 +127,6 @@ public static string Blowfish_Options
127127
get { return Native.StaticString(Native.BF_options()); }
128128
}
129129

130-
/// <summary>
131-
/// Calls CRYPTO_dbg_set_options()
132-
/// </summary>
133-
/// <param name="options"></param>
134-
public static void SetDebugOptions(DebugOptions options)
135-
{
136-
Native.CRYPTO_dbg_set_options((int)options);
137-
}
138-
139-
/// <summary>
140-
/// Calls CRYPTO_mem_ctrl()
141-
/// </summary>
142-
/// <param name="options"></param>
143-
public static void SetMemoryCheck(MemoryCheck options)
144-
{
145-
Native.CRYPTO_mem_ctrl((int)options);
146-
}
147-
148130
/// <summary>
149131
/// Calls CRYPTO_cleanup_all_ex_data()
150132
/// </summary>
@@ -161,26 +143,6 @@ public static void ClearErrors()
161143
Native.ERR_clear_error();
162144
}
163145

164-
/// <summary>
165-
/// CRYPTO_MEM_LEAK_CB
166-
/// </summary>
167-
/// <param name="order"></param>
168-
/// <param name="file"></param>
169-
/// <param name="line"></param>
170-
/// <param name="num_bytes"></param>
171-
/// <param name="addr"></param>
172-
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
173-
public delegate void MemoryLeakHandler(uint order, IntPtr file, int line, int num_bytes, IntPtr addr);
174-
175-
/// <summary>
176-
/// Calls CRYPTO_mem_leaks_cb()
177-
/// </summary>
178-
/// <param name="callback"></param>
179-
public static void CheckMemoryLeaks(MemoryLeakHandler callback)
180-
{
181-
Native.CRYPTO_mem_leaks_cb(callback);
182-
}
183-
184146
/// <summary>
185147
/// Calls ERR_print_errors_cb()
186148
/// </summary>

ManagedOpenSsl/Core/MemoryTracker.cs

Lines changed: 208 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,248 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Runtime.InteropServices;
25

36
namespace OpenSSL.Core
47
{
8+
/// <summary>
9+
///
10+
/// </summary>
11+
public enum MemoryProblemType
12+
{
13+
/// <summary>
14+
///
15+
/// </summary>
16+
Leaked,
17+
/// <summary>
18+
///
19+
/// </summary>
20+
MultipleFree,
21+
}
22+
23+
/// <summary>
24+
///
25+
/// </summary>
26+
public class MemoryProblem
27+
{
28+
/// <summary>
29+
///
30+
/// </summary>
31+
public MemoryProblemType Type { get; set; }
32+
/// <summary>
33+
///
34+
/// </summary>
35+
public uint Size { get; set; }
36+
/// <summary>
37+
///
38+
/// </summary>
39+
public int FreeCount { get; set; }
40+
/// <summary>
41+
///
42+
/// </summary>
43+
public StackTrace StackTrace { get; set; }
44+
/// <summary>
45+
///
46+
/// </summary>
47+
public string File { get; set; }
48+
/// <summary>
49+
///
50+
/// </summary>
51+
public int Line { get; set; }
52+
53+
/// <summary>
54+
///
55+
/// </summary>
56+
/// <returns></returns>
57+
public override string ToString()
58+
{
59+
return string.Format("{0}: {1} bytes, {2} count, {3}, {4}:{5}",
60+
Type,
61+
Size,
62+
FreeCount,
63+
StackTrace.GetFrame(0).GetMethod().Name,
64+
File,
65+
Line
66+
);
67+
}
68+
}
69+
570
/// <summary>
671
/// Useful for tracking down memory leaks
772
/// </summary>
873
public class MemoryTracker
974
{
10-
private static int leaked = 0;
75+
class Block
76+
{
77+
public string file;
78+
public int line;
79+
public StackTrace stack;
80+
public uint bytes;
81+
public IntPtr ptr;
82+
public bool skip;
83+
public int count;
84+
85+
public override string ToString()
86+
{
87+
return string.Format("{0}{1}: {2} bytes at {3}:{4}", skip ? "*" : " ", count, bytes, file, line);
88+
}
89+
}
90+
91+
// These are used to pin the functions down so they don't get yanked while in use
92+
static Native.MallocFunctionPtr _ptrMalloc = malloc;
93+
static Native.ReallocFunctionPtr _ptrRealloc = realloc;
94+
static Native.FreeFunctionPtr _ptrFree = free;
95+
96+
static bool _tracking = false;
97+
static Dictionary<IntPtr, Block> _memory = new Dictionary<IntPtr, Block>();
1198

1299
/// <summary>
13-
/// Returns the number of bytes leaked between Start() and Finish()
100+
/// Initialize memory routines
14101
/// </summary>
15-
public static int Leaked { get { return leaked; } }
102+
public static void Init()
103+
{
104+
Native.CRYPTO_set_mem_ex_functions(_ptrMalloc, _ptrRealloc, _ptrFree);
105+
}
16106

17107
/// <summary>
18108
/// Begins memory tracking
19109
/// </summary>
20110
public static void Start()
21111
{
22-
leaked = 0;
23-
Native.CRYPTO_malloc_debug_init();
24-
CryptoUtil.SetDebugOptions(DebugOptions.All);
25-
CryptoUtil.SetMemoryCheck(MemoryCheck.On);
112+
lock (_memory)
113+
{
114+
_tracking = true;
115+
foreach (var item in _memory)
116+
{
117+
item.Value.skip = true;
118+
}
119+
}
26120
}
27121

28122
/// <summary>
29123
/// Stops memory tracking and reports any leaks found since Start() was called.
30124
/// </summary>
31-
public static void Finish()
125+
public static List<MemoryProblem> Finish()
32126
{
33127
GC.Collect();
34128
GC.WaitForPendingFinalizers();
35129
GC.Collect();
36130

37131
CryptoUtil.Cleanup();
38132
CryptoUtil.ClearErrors();
39-
Threading.RemoveState();
133+
Native.ERR_remove_state();
134+
135+
GC.Collect();
136+
GC.WaitForPendingFinalizers();
137+
GC.Collect();
138+
139+
_tracking = false;
140+
141+
return Flush();
142+
}
40143

41-
CryptoUtil.CheckMemoryLeaks(OnMemoryLeak);
42-
if (leaked > 0)
43-
Console.WriteLine("Leaked total bytes: {0}", leaked);
144+
static List<MemoryProblem> Flush()
145+
{
146+
var problems = new List<MemoryProblem>();
147+
148+
lock (_memory)
149+
{
150+
var frees = new List<Block>();
151+
152+
foreach (var item in _memory)
153+
{
154+
var block = item.Value;
155+
if (block.skip)
156+
continue;
157+
158+
if (block.count == 0)
159+
block.skip = true;
160+
161+
if (block.count > 0)
162+
frees.Add(block);
163+
164+
if (block.count == 0 || block.count > 1)
165+
{
166+
var problem = new MemoryProblem
167+
{
168+
Type = block.count == 0 ? MemoryProblemType.Leaked : MemoryProblemType.MultipleFree,
169+
Size = block.bytes,
170+
FreeCount = block.count,
171+
StackTrace = block.stack,
172+
File = block.file,
173+
Line = block.line,
174+
};
175+
Console.WriteLine(problem);
176+
problems.Add(problem);
177+
}
178+
}
179+
180+
foreach (var block in frees)
181+
{
182+
Marshal.FreeHGlobal(block.ptr);
183+
_memory.Remove(block.ptr);
184+
}
185+
}
186+
187+
return problems;
188+
}
189+
190+
static IntPtr malloc(uint num, IntPtr file, int line)
191+
{
192+
lock (_memory)
193+
{
194+
var block = new Block
195+
{
196+
file = Native.StaticString(file),
197+
line = line,
198+
stack = new StackTrace(1, true),
199+
bytes = num,
200+
ptr = Marshal.AllocHGlobal((int)num),
201+
};
202+
_memory.Add(block.ptr, block);
203+
return block.ptr;
204+
}
205+
}
206+
207+
static void free(IntPtr addr)
208+
{
209+
lock (_memory)
210+
{
211+
Block block;
212+
if (!_memory.TryGetValue(addr, out block))
213+
return;
44214

45-
CryptoUtil.SetMemoryCheck(MemoryCheck.Off);
215+
if (_tracking)
216+
{
217+
block.count++;
218+
}
219+
else
220+
{
221+
Marshal.FreeHGlobal(addr);
222+
_memory.Remove(addr);
223+
}
224+
}
46225
}
47226

48-
private static void OnMemoryLeak(uint order, IntPtr file, int line, int num_bytes, IntPtr addr)
227+
static IntPtr realloc(IntPtr addr, uint num, IntPtr file, int line)
49228
{
50-
string filename = (file != IntPtr.Zero) ? Native.StaticString(file) : "<null>";
229+
lock (_memory)
230+
{
231+
if (!_memory.Remove(addr))
232+
return malloc(num, file, line);
51233

52-
Console.WriteLine("[{0}] file: {1} line: {2} bytes: {3}", order, filename, line, num_bytes);
53-
leaked += num_bytes;
234+
var block = new Block
235+
{
236+
stack = new StackTrace(1, true),
237+
file = Native.StaticString(file),
238+
line = line,
239+
bytes = num,
240+
ptr = Marshal.ReAllocHGlobal(addr, (IntPtr)num),
241+
};
54242

55-
Native.CRYPTO_dbg_free(addr, 0);
243+
_memory.Add(block.ptr, block);
244+
return block.ptr;
245+
}
56246
}
57247
}
58248
}

0 commit comments

Comments
 (0)
0