Index: include/lldb/Interpreter/PythonDataObjects.h =================================================================== --- include/lldb/Interpreter/PythonDataObjects.h +++ include/lldb/Interpreter/PythonDataObjects.h @@ -51,6 +51,14 @@ Reset (NULL); } + PyObject* + Release() + { + PyObject* obj = m_py_obj; + m_py_obj = nullptr; + return obj; + } + bool Reset (const PythonObject &object) { Index: source/Interpreter/ScriptInterpreterPython.cpp =================================================================== --- source/Interpreter/ScriptInterpreterPython.cpp +++ source/Interpreter/ScriptInterpreterPython.cpp @@ -209,6 +209,11 @@ ScriptInterpreterPython::~ScriptInterpreterPython () { + // Release the underlying PyObjects. Python will have already decref'ed these to 0 during + // Py_Finalize(), so allowing them to be destructed normally will cause Python to assert with a + // debug build. + m_session_dict.Release(); + m_sys_module_dict.Release(); } void @@ -1806,7 +1811,11 @@ Locker locker(this, ScriptInterpreterPython::Locker::AcquireLock, ScriptInterpreterPython::Locker::FreeAcquiredLock); - PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process = None; lldb.thread = None; lldb.frame = None"); + + // This may be called as part of Py_Finalize. In that case the modules are destroyed in random + // order and we can't guarantee that we can access these. + if (Py_IsInitialized()) + PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process = None; lldb.thread = None; lldb.frame = None"); } bool Index: test/dotest.py =================================================================== --- test/dotest.py +++ test/dotest.py @@ -20,7 +20,6 @@ for available options. """ -import atexit import commands import os import errno @@ -419,7 +418,6 @@ cmd = "xcrun clang %s -o %s -framework Python -Xlinker -dylib -iframework /System/Library/Frameworks/ -Xlinker -F /System/Library/Frameworks/" % (dylib_src,dylib_dst) if subprocess.call(cmd,shell=True) == 0 and os.path.exists(dylib_dst): setCrashInfoHook = setCrashInfoHook_Mac - atexit.register(deleteCrashInfoDylib,dylib_dst) else: pass @@ -1232,11 +1230,7 @@ # For the time being, let's bracket the test runner within the # lldb.SBDebugger.Initialize()/Terminate() pair. -import lldb, atexit -# Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(), -# there's no need to call it a second time. -#lldb.SBDebugger.Initialize() -atexit.register(lambda: lldb.SBDebugger.Terminate()) +import lldb # Create a singleton SBDebugger in the lldb namespace. lldb.DBG = lldb.SBDebugger.Create() @@ -1246,6 +1240,7 @@ lldb.remote_platform = lldb.SBPlatform(lldb_platform_name) if not lldb.remote_platform.IsValid(): print "error: unable to create the LLDB platform named '%s'." % (lldb_platform_name) + lldb.SBDebugger.Terminate() sys.exit(1) if lldb_platform_url: # We must connect to a remote platform if a LLDB platform URL was specified @@ -1256,6 +1251,7 @@ print "Connected." else: print "error: failed to connect to remote platform using URL '%s': %s" % (lldb_platform_url, err) + lldb.SBDebugger.Terminate() sys.exit(1) if lldb_platform_working_dir: @@ -1397,6 +1393,7 @@ if not compilers or len(compilers) == 0: print "No eligible compiler found, exiting." + lldb.SBDebugger.Terminate() sys.exit(1) if isinstance(compilers, list) and len(compilers) >= 1: @@ -1738,4 +1735,4 @@ subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())]) # Exiting. -sys.exit(failed) +lldb.SBDebugger.Terminate()