Index: lldb/trunk/source/Target/Target.cpp =================================================================== --- lldb/trunk/source/Target/Target.cpp +++ lldb/trunk/source/Target/Target.cpp @@ -1276,7 +1276,7 @@ void Target::ModuleRemoved (const ModuleList& module_list, const ModuleSP &module_sp) { - // A module is being added to this target for the first time + // A module is being removed from this target. if (m_valid) { ModuleList my_module_list; Index: lldb/trunk/test/lldbtest.py =================================================================== --- lldb/trunk/test/lldbtest.py +++ lldb/trunk/test/lldbtest.py @@ -32,6 +32,7 @@ """ import abc +import gc import glob import os, sys, traceback import os.path @@ -2544,6 +2545,11 @@ #import traceback #traceback.print_stack() + # Ensure all the references to SB objects have gone away so that we can + # be sure that all test-specific resources have been freed before we + # attempt to delete the targets. + gc.collect() + # Delete the target(s) from the debugger as a general cleanup step. # This includes terminating the process for each target, if any. # We'd like to reuse the debugger for our next test without incurring Index: lldb/trunk/test/unittest2/case.py =================================================================== --- lldb/trunk/test/unittest2/case.py +++ lldb/trunk/test/unittest2/case.py @@ -353,32 +353,7 @@ except Exception: result.addError(self, sys.exc_info()) else: - try: - testMethod() - except self.failureException: - result.addFailure(self, sys.exc_info()) - except _ExpectedFailure, e: - addExpectedFailure = getattr(result, 'addExpectedFailure', None) - if addExpectedFailure is not None: - addExpectedFailure(self, e.exc_info, e.bugnumber) - else: - warnings.warn("Use of a TestResult without an addExpectedFailure method is deprecated", - DeprecationWarning) - result.addSuccess(self) - except _UnexpectedSuccess, x: - addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None) - if addUnexpectedSuccess is not None: - addUnexpectedSuccess(self, x.bugnumber) - else: - warnings.warn("Use of a TestResult without an addUnexpectedSuccess method is deprecated", - DeprecationWarning) - result.addFailure(self, sys.exc_info()) - except SkipTest, e: - self._addSkip(result, str(e)) - except Exception: - result.addError(self, sys.exc_info()) - else: - success = True + success = self.runMethod(testMethod, result) try: self.tearDown() @@ -399,6 +374,42 @@ if stopTestRun is not None: stopTestRun() + def runMethod(self, testMethod, result): + """Runs the test method and catches any exception that might be thrown. + + This is factored out of TestCase.run() to ensure that any exception + thrown during the test goes out of scope before tearDown. Otherwise, an + exception could hold references to Python objects that are bound to + SB objects and prevent them from being deleted in time. + """ + try: + testMethod() + except self.failureException: + result.addFailure(self, sys.exc_info()) + except _ExpectedFailure, e: + addExpectedFailure = getattr(result, 'addExpectedFailure', None) + if addExpectedFailure is not None: + addExpectedFailure(self, e.exc_info, e.bugnumber) + else: + warnings.warn("Use of a TestResult without an addExpectedFailure method is deprecated", + DeprecationWarning) + result.addSuccess(self) + except _UnexpectedSuccess, x: + addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None) + if addUnexpectedSuccess is not None: + addUnexpectedSuccess(self, x.bugnumber) + else: + warnings.warn("Use of a TestResult without an addUnexpectedSuccess method is deprecated", + DeprecationWarning) + result.addFailure(self, sys.exc_info()) + except SkipTest, e: + self._addSkip(result, str(e)) + except Exception: + result.addError(self, sys.exc_info()) + else: + return True + return False + def doCleanups(self): """Execute all cleanup functions. Normally called for you after tearDown."""