diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs
index bdef98c27..dca5a53b4 100644
--- a/src/runtime/importhook.cs
+++ b/src/runtime/importhook.cs
@@ -16,7 +16,13 @@ internal class ImportHook
 
 #if PYTHON3
         static IntPtr py_clr_module;
-        static IntPtr module_def;
+        static IntPtr module_def = IntPtr.Zero;
+
+        internal static void InitializeModuleDef()
+        {
+            if (module_def == IntPtr.Zero)
+                module_def = ModuleDefOffset.AllocModuleDef("clr");
+        }
 #endif
 
         //===================================================================
@@ -44,8 +50,8 @@ internal static void Initialize()
             root = new CLRModule();
 
 #if PYTHON3
-    // create a python module with the same methods as the clr module-like object
-            module_def = ModuleDefOffset.AllocModuleDef("clr");
+            // create a python module with the same methods as the clr module-like object
+            InitializeModuleDef();
             py_clr_module = Runtime.PyModule_Create2(module_def, 3);
 
             // both dicts are borrowed references
@@ -70,21 +76,13 @@ internal static void Initialize()
 
         internal static void Shutdown()
         {
-#if PYTHON3
             if (0 != Runtime.Py_IsInitialized()) {
+#if PYTHON3
                 Runtime.XDecref(py_clr_module);
-                Runtime.XDecref(root.pyHandle);
-            }
-            ModuleDefOffset.FreeModuleDef(module_def);
 #elif PYTHON2
-            if (0 != Runtime.Py_IsInitialized())
-            {
-                Runtime.XDecref(root.pyHandle);
                 Runtime.XDecref(root.pyHandle);
-            }
 #endif
-            if (0 != Runtime.Py_IsInitialized())
-            {
+                Runtime.XDecref(root.pyHandle);
                 Runtime.XDecref(py_import);
             }
         }
diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs
index 0657bc3e6..3dc5ad827 100644
--- a/src/runtime/interop.cs
+++ b/src/runtime/interop.cs
@@ -227,7 +227,7 @@ public static IntPtr AllocModuleDef(string modulename) {
             byte[] ascii = Encoding.ASCII.GetBytes(modulename);
             int size = name + ascii.Length + 1;
             IntPtr ptr = Marshal.AllocHGlobal(size);
-            for (int i = 0; i <= m_free; i += IntPtr.Size)
+            for (int i = 0; i < m_free; i += IntPtr.Size)
                 Marshal.WriteIntPtr(ptr, i, IntPtr.Zero);
             Marshal.Copy(ascii, 0, (IntPtr)(ptr + name), ascii.Length);
             Marshal.WriteIntPtr(ptr, m_name, (IntPtr)(ptr + name));
diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs
index 4c676d375..c296f1b87 100644
--- a/src/runtime/pythonengine.cs
+++ b/src/runtime/pythonengine.cs
@@ -411,33 +411,54 @@ public static PyObject ModuleFromString(string name, string code)
         /// executing the code string as a PyObject instance, or null if
         /// an exception was raised.
         /// </remarks>
-        public static PyObject RunString(string code)
+        public static PyObject RunString(
+            string code, IntPtr? globals = null, IntPtr? locals = null
+            )
         {
-            IntPtr globals = Runtime.PyEval_GetGlobals();
-            IntPtr locals = Runtime.PyDict_New();
-
-            IntPtr builtins = Runtime.PyEval_GetBuiltins();
-            Runtime.PyDict_SetItemString(locals, "__builtins__", builtins);
+            bool borrowedGlobals = true;
+            if (globals == null)
+            {
+                globals = Runtime.PyEval_GetGlobals();
+                if (globals == IntPtr.Zero)
+                {
+                    globals = Runtime.PyDict_New();
+                    Runtime.PyDict_SetItemString(
+                        globals.Value, "__builtins__",
+                        Runtime.PyEval_GetBuiltins()
+                        );
+                    borrowedGlobals = false;
+                }
+            }
 
-            IntPtr flag = (IntPtr)257; /* Py_file_input */
-            IntPtr result = Runtime.PyRun_String(code, flag, globals, locals);
-            Runtime.XDecref(locals);
-            if (result == IntPtr.Zero)
+            bool borrowedLocals = true;
+            if (locals == null)
             {
-                return null;
+                locals = Runtime.PyDict_New();
+                borrowedLocals = false;
             }
-            return new PyObject(result);
-        }
 
-        public static PyObject RunString(string code, IntPtr globals, IntPtr locals)
-        {
             IntPtr flag = (IntPtr)257; /* Py_file_input */
-            IntPtr result = Runtime.PyRun_String(code, flag, globals, locals);
-            if (result == IntPtr.Zero)
+
+            try
             {
-                return null;
+                IntPtr result = Runtime.PyRun_String(
+                    code, flag, globals.Value, locals.Value
+                    );
+
+                if (Runtime.PyErr_Occurred() != 0)
+                {
+                    throw new PythonException();
+                }
+
+                return new PyObject(result);
+            }
+            finally
+            {
+                if (!borrowedLocals)
+                    Runtime.XDecref(locals.Value);
+                if (!borrowedGlobals)
+                    Runtime.XDecref(globals.Value);
             }
-            return new PyObject(result);
         }
     }