Skip to content

Commit 43d3bb8

Browse files
committed
Fixed crash in Finalize on Python2
1 parent 628320c commit 43d3bb8

5 files changed

Lines changed: 78 additions & 10 deletions

File tree

src/runtime/importhook.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,25 @@ internal static void Initialize()
3939
IntPtr mod = Runtime.IsPython3
4040
? Runtime.PyImport_ImportModule("builtins")
4141
: Runtime.PyDict_GetItemString(dict, "__builtin__");
42+
if (mod == IntPtr.Zero)
43+
{
44+
throw new PythonException();
45+
}
4246

4347
py_import = Runtime.PyObject_GetAttrString(mod, "__import__");
48+
if (py_import == IntPtr.Zero)
49+
{
50+
throw new PythonException();
51+
}
52+
4453
hook = new MethodWrapper(typeof(ImportHook), "__import__", "TernaryFunc");
4554
Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr);
46-
Runtime.XDecref(hook.ptr);
55+
56+
if (Runtime.IsPython3)
57+
{
58+
// On Python3, PyImport_ImportModule got a new reference, so we need to decrease it.
59+
Runtime.Py_DecRef(mod);
60+
}
4761

4862
root = new CLRModule();
4963

@@ -75,8 +89,18 @@ internal static void Shutdown()
7589
if (Runtime.Py_IsInitialized() != 0)
7690
{
7791
Runtime.XDecref(py_clr_module);
92+
py_clr_module = IntPtr.Zero;
93+
7894
Runtime.XDecref(root.pyHandle);
95+
root = null;
96+
97+
hook.Dispose();
98+
hook = null;
99+
79100
Runtime.XDecref(py_import);
101+
py_import = IntPtr.Zero;
102+
103+
CLRModule.ResetFlags();
80104
}
81105
}
82106

@@ -142,7 +166,7 @@ public static IntPtr GetCLRModule(IntPtr? fromList = null)
142166
}
143167
}
144168
}
145-
Runtime.XIncref(py_clr_module);
169+
Runtime.Py_IncRef(py_clr_module);
146170
return py_clr_module;
147171
}
148172

src/runtime/interop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ public static IntPtr AllocModuleDef(string modulename)
227227
byte[] ascii = Encoding.ASCII.GetBytes(modulename);
228228
int size = name + ascii.Length + 1;
229229
IntPtr ptr = Marshal.AllocHGlobal(size);
230-
for (int i = 0; i < m_free; i += IntPtr.Size)
230+
for (int i = 0; i <= m_free; i += IntPtr.Size)
231231
Marshal.WriteIntPtr(ptr, i, IntPtr.Zero);
232232
Marshal.Copy(ascii, 0, (IntPtr)(ptr + name), ascii.Length);
233233
Marshal.WriteIntPtr(ptr, m_name, (IntPtr)(ptr + name));

src/runtime/methodwrapper.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ namespace Python.Runtime
88
/// currently used mainly to implement special cases like the CLR
99
/// import hook.
1010
/// </summary>
11-
internal class MethodWrapper
11+
internal class MethodWrapper : IDisposable
1212
{
1313
public IntPtr mdef;
1414
public IntPtr ptr;
15+
private bool _disposed = false;
1516

1617
public MethodWrapper(Type type, string name, string funcType = null)
1718
{
@@ -27,9 +28,29 @@ public MethodWrapper(Type type, string name, string funcType = null)
2728
ptr = Runtime.PyCFunction_NewEx(mdef, IntPtr.Zero, IntPtr.Zero);
2829
}
2930

31+
~MethodWrapper()
32+
{
33+
Dispose();
34+
}
35+
3036
public IntPtr Call(IntPtr args, IntPtr kw)
3137
{
3238
return Runtime.PyCFunction_Call(ptr, args, kw);
3339
}
40+
41+
public void Dispose()
42+
{
43+
if (_disposed)
44+
{
45+
return;
46+
}
47+
_disposed = true;
48+
Runtime.XDecref(ptr);
49+
if (mdef != IntPtr.Zero)
50+
{
51+
Runtime.PyMem_Free(mdef);
52+
mdef = IntPtr.Zero;
53+
}
54+
}
3455
}
3556
}

src/runtime/moduleobject.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,15 @@ public CLRModule() : base("clr")
335335
}
336336
}
337337

338+
internal static void ResetFlags()
339+
{
340+
hacked = false;
341+
interactive_preload = true;
342+
preload = false;
343+
_SuppressDocs = false;
344+
_SuppressOverloads = false;
345+
}
346+
338347
/// <summary>
339348
/// The initializing of the preload hook has to happen as late as
340349
/// possible since sys.ps1 is created after the CLR module is
@@ -423,7 +432,7 @@ public static Assembly AddReference(string name)
423432
/// clr.GetClrType(IComparable) gives you the Type for IComparable,
424433
/// that you can e.g. perform reflection on. Similar to typeof(IComparable) in C#
425434
/// or clr.GetClrType(IComparable) in IronPython.
426-
///
435+
///
427436
/// </summary>
428437
/// <param name="type"></param>
429438
/// <returns>The Type object</returns>

src/runtime/pythonengine.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,20 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true)
184184
// Load the clr.py resource into the clr module
185185
IntPtr clr = Python.Runtime.ImportHook.GetCLRModule();
186186
IntPtr clr_dict = Runtime.PyModule_GetDict(clr);
187+
if (clr_dict == IntPtr.Zero)
188+
{
189+
throw new PythonException();
190+
}
187191

188192
var locals = new PyDict();
193+
IntPtr module = IntPtr.Zero;
189194
try
190195
{
191-
IntPtr module = Runtime.PyImport_AddModule("clr._extras");
196+
module = Runtime.PyImport_AddModule("clr._extras");
197+
if (module == IntPtr.Zero)
198+
{
199+
throw new PythonException();
200+
}
192201
IntPtr module_globals = Runtime.PyModule_GetDict(module);
193202
IntPtr builtins = Runtime.PyEval_GetBuiltins();
194203
Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins);
@@ -205,7 +214,8 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true)
205214
// add the imported module to the clr module, and copy the API functions
206215
// and decorators into the main clr module.
207216
Runtime.PyDict_SetItemString(clr_dict, "_extras", module);
208-
foreach (PyObject key in locals.Keys())
217+
using (PyObject keys = locals.Keys())
218+
foreach (PyObject key in keys)
209219
{
210220
if (!key.ToString().StartsWith("_") || key.ToString().Equals("__version__"))
211221
{
@@ -219,6 +229,10 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true)
219229
finally
220230
{
221231
locals.Dispose();
232+
if (clr != IntPtr.Zero)
233+
{
234+
Runtime.Py_DecRef(clr);
235+
}
222236
}
223237
}
224238
}
@@ -496,7 +510,7 @@ internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals,
496510
borrowedGlobals = false;
497511
}
498512
}
499-
513+
500514
if (locals == null)
501515
{
502516
locals = globals;
@@ -552,7 +566,7 @@ public static PyScope CreateScope(string name)
552566
var scope = PyScopeManager.Global.Create(name);
553567
return scope;
554568
}
555-
569+
556570
public class GILState : IDisposable
557571
{
558572
private IntPtr state;
@@ -649,7 +663,7 @@ public static void SetArgv(IEnumerable<string> argv)
649663

650664
public static void With(PyObject obj, Action<dynamic> Body)
651665
{
652-
// Behavior described here:
666+
// Behavior described here:
653667
// https://docs.python.org/2/reference/datamodel.html#with-statement-context-managers
654668

655669
IntPtr type = Runtime.PyNone;

0 commit comments

Comments
 (0)