|
1 | 1 | using System;
|
2 | 2 | using System.Diagnostics;
|
3 | 3 | using System.Reflection;
|
| 4 | +using System.Runtime.InteropServices; |
4 | 5 | using NUnit.Framework;
|
5 | 6 | using Python.Runtime;
|
6 | 7 |
|
@@ -115,6 +116,71 @@ public static void CrossDomainObject()
|
115 | 116 | }
|
116 | 117 | }
|
117 | 118 |
|
| 119 | + |
| 120 | + #region Tempary tests |
| 121 | + // https://github.com/pythonnet/pythonnet/pull/1074#issuecomment-596139665 |
| 122 | + [Test] |
| 123 | + public void CrossReleaseBuiltinType() |
| 124 | + { |
| 125 | + try |
| 126 | + { |
| 127 | + var numRef = CreateNumReference(); |
| 128 | + GC.Collect(); |
| 129 | + GC.WaitForPendingFinalizers(); // <- this will put former `num` into Finalizer queue |
| 130 | + Finalizer.Instance.Collect(forceDispose: true); |
| 131 | + // ^- this will call PyObject.Dispose, which will call XDecref on `num.Handle`, |
| 132 | + // but Python interpreter from "run" 1 is long gone, so it will corrupt memory instead. |
| 133 | + Assert.False(numRef.IsAlive); |
| 134 | + } |
| 135 | + finally |
| 136 | + { |
| 137 | + PythonEngine.Shutdown(); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + [Test] |
| 142 | + public void CrossReleaseCustomType() |
| 143 | + { |
| 144 | + try |
| 145 | + { |
| 146 | + var objRef = CreateConcreateObject(); |
| 147 | + GC.Collect(); |
| 148 | + GC.WaitForPendingFinalizers(); |
| 149 | + Finalizer.Instance.Collect(forceDispose: true); |
| 150 | + Assert.False(objRef.IsAlive); |
| 151 | + } |
| 152 | + finally |
| 153 | + { |
| 154 | + PythonEngine.Shutdown(); |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | + private static WeakReference CreateNumReference() |
| 159 | + { |
| 160 | + PythonEngine.Initialize(); |
| 161 | + var num = 3216757418.ToPython(); |
| 162 | + Assert.AreEqual(num.Refcount, 1); |
| 163 | + WeakReference numRef = new WeakReference(num, false); |
| 164 | + PythonEngine.Shutdown(); // <- "run" 1 ends |
| 165 | + PythonEngine.Initialize(); // <- "run" 2 starts |
| 166 | + num = null; |
| 167 | + return numRef; |
| 168 | + } |
| 169 | + |
| 170 | + private static WeakReference CreateConcreateObject() |
| 171 | + { |
| 172 | + PythonEngine.Initialize(); |
| 173 | + var obj = new Domain.MyClass().ToPython(); |
| 174 | + Assert.AreEqual(obj.Refcount, 1); |
| 175 | + WeakReference numRef = new WeakReference(obj, false); |
| 176 | + PythonEngine.Shutdown(); |
| 177 | + PythonEngine.Initialize(); |
| 178 | + obj = null; |
| 179 | + return numRef; |
| 180 | + } |
| 181 | + |
| 182 | + #endregion Tempary tests |
| 183 | + |
118 | 184 | /// <summary>
|
119 | 185 | /// This is a magic incantation required to run code in an application
|
120 | 186 | /// domain other than the current one.
|
@@ -305,6 +371,8 @@ from Python.EmbeddingTest.Domain import MyClass
|
305 | 371 | obj = MyClass()
|
306 | 372 | obj.Method()
|
307 | 373 | obj.StaticMethod()
|
| 374 | +obj.Property = 1 |
| 375 | +obj.Field = 10 |
308 | 376 | ", Assembly.GetExecutingAssembly().FullName);
|
309 | 377 |
|
310 | 378 | using (Py.GIL())
|
@@ -333,11 +401,27 @@ public static void RunTestObject(IntPtr handle)
|
333 | 401 | {
|
334 | 402 | using (Py.GIL())
|
335 | 403 | {
|
| 404 | + IntPtr tp = Runtime.Runtime.PyObject_TYPE(handle); |
| 405 | + IntPtr tp_clear = Marshal.ReadIntPtr(tp, TypeOffset.tp_clear); |
336 | 406 |
|
337 | 407 | using (PyObject obj = new PyObject(handle))
|
338 | 408 | {
|
339 | 409 | obj.InvokeMethod("Method");
|
340 | 410 | obj.InvokeMethod("StaticMethod");
|
| 411 | + |
| 412 | + using (var scope = Py.CreateScope()) |
| 413 | + { |
| 414 | + scope.Set("obj", obj); |
| 415 | + scope.Exec(@" |
| 416 | +obj.Method() |
| 417 | +obj.StaticMethod() |
| 418 | +obj.Property += 1 |
| 419 | +obj.Field += 10 |
| 420 | +"); |
| 421 | + } |
| 422 | + var clrObj = obj.As<Domain.MyClass>(); |
| 423 | + Assert.AreEqual(clrObj.Property, 2); |
| 424 | + Assert.AreEqual(clrObj.Field, 20); |
341 | 425 | }
|
342 | 426 | }
|
343 | 427 | }
|
@@ -370,6 +454,8 @@ namespace Python.EmbeddingTest.Domain
|
370 | 454 | [Serializable]
|
371 | 455 | public class MyClass
|
372 | 456 | {
|
| 457 | + public int Property { get; set; } |
| 458 | + public int Field; |
373 | 459 | public void Method() { }
|
374 | 460 | public static void StaticMethod() { }
|
375 | 461 | }
|
|
0 commit comments