The gc.collect works only if I set the variables to None in the finally blocks, which is no better than just del'ing the objects in the finally blocks.
On Thu, Oct 15, 2015 at 9:47 AM, Adrian McCarthy <amcca...@google.com> wrote: > > On Thu, Oct 15, 2015 at 9:31 AM, Todd Fiala <todd.fi...@gmail.com> wrote: > >> >> >> On Thu, Oct 15, 2015 at 9:23 AM, Zachary Turner via lldb-dev < >> lldb-dev@lists.llvm.org> wrote: >> >>> That wouldn't work in this case because it causes a failure from one >>> test to the next. So a single test suite has 5 tests, and the second one >>> fails because the first one didn't clean up correctly. You couldn't call >>> ScriptInterpreterpython::Clear here, because then you'd have to initialize >>> it again, and while it might work, it seems scary and like something which >>> is untested and we recommend you don't do. >>> >>> What about calling `gc.collect()` in the tearDown() method? >>> >> >> If it's a laziness thing, that seems like it might do it. I would think >> we could stick that in the base test class and get it everywhere. Is that >> something you can try, Adrian? >> > > That seemed promising, but it doesn't seem to work, so maybe I don't > understand the problem as well as I thought I did. > > >> >> >>> >>> On Thu, Oct 15, 2015 at 9:10 AM Oleksiy Vyalov via lldb-dev < >>> lldb-dev@lists.llvm.org> wrote: >>> >>>> I stumbled upon similar problem when was looking into why SBDebugger >>>> wasn't unloaded upon app's exit. >>>> The problem was in Python global objects like lldb.debugger, >>>> lldb.target sitting around. >>>> So, my guess is to try to call ScriptInterpreterPython::Clear within >>>> test's tearDown call - e.g., expose Clear method as part of >>>> SBCommandInterpreter and call it via SBDebugger::GetCommandInterpreter >>>> >>>> On Thu, Oct 15, 2015 at 8:50 AM, Adrian McCarthy via lldb-dev < >>>> lldb-dev@lists.llvm.org> wrote: >>>> >>>>> I've tracked down a source of flakiness in tests on Windows to Python >>>>> object lifetimes and the SB interface, and I'm wondering how best to >>>>> handle >>>>> it. >>>>> >>>>> Consider this portion of a test from TestTargetAPI: >>>>> >>>>> def find_functions(self, exe_name): >>>>> """Exercise SBTaget.FindFunctions() API.""" >>>>> exe = os.path.join(os.getcwd(), exe_name) >>>>> >>>>> # Create a target by the debugger. >>>>> target = self.dbg.CreateTarget(exe) >>>>> self.assertTrue(target, VALID_TARGET) >>>>> list = target.FindFunctions('c', lldb.eFunctionNameTypeAuto) >>>>> self.assertTrue(list.GetSize() == 1) >>>>> >>>>> for sc in list: >>>>> self.assertTrue(sc.GetModule().GetFileSpec().GetFilename() >>>>> == exe_name) >>>>> self.assertTrue(sc.GetSymbol().GetName() == 'c') >>>>> >>>>> The local variables go out of scope when the function exits, but the >>>>> SB (C++) objects they represent aren't (always) immediately destroyed. At >>>>> least some of these objects keep references to the executable module in >>>>> the >>>>> shared module list, so when the test framework cleans up and calls >>>>> `SBDebugger::DeleteTarget`, the module isn't orphaned, so LLDB maintains >>>>> an >>>>> open handle to the executable. >>>>> >>>>> The result of the lingering handle is that, when the next test case in >>>>> the test suite tries to re-build the executable, it fails because the file >>>>> is not writable. (This is problematic on Windows because the file system >>>>> works differently in this regard than Unix derivatives.) Every subsequent >>>>> case in the test suite fails. >>>>> >>>>> I managed to make the test work reliably by rewriting it like this: >>>>> >>>>> def find_functions(self, exe_name): >>>>> """Exercise SBTaget.FindFunctions() API.""" >>>>> exe = os.path.join(os.getcwd(), exe_name) >>>>> >>>>> # Create a target by the debugger. >>>>> target = self.dbg.CreateTarget(exe) >>>>> self.assertTrue(target, VALID_TARGET) >>>>> >>>>> try: >>>>> list = target.FindFunctions('c', >>>>> lldb.eFunctionNameTypeAuto) >>>>> self.assertTrue(list.GetSize() == 1) >>>>> >>>>> for sc in list: >>>>> try: >>>>> >>>>> self.assertTrue(sc.GetModule().GetFileSpec().GetFilename() == exe_name) >>>>> self.assertTrue(sc.GetSymbol().GetName() == 'c') >>>>> finally: >>>>> del sc >>>>> >>>>> finally: >>>>> del list >>>>> >>>>> The finally blocks ensure that the corresponding C++ objects are >>>>> destroyed, even if the function exits as a result of a Python exception >>>>> (e.g., if one of the assertion expressions is false and the code throws an >>>>> exception). Since the objects are destroyed, the reference counts are >>>>> back >>>>> to where they should be, and the orphaned module is closed when the target >>>>> is deleted. >>>>> >>>>> But this is ugly and maintaining it would be error prone. Is there a >>>>> better way to address this? >>>>> >>>>> In general, it seems bad that our tests aren't well-isolated. I >>>>> sympathize with the concern that re-starting LLDB for each test case would >>>>> slow down testing, but I'm also concerned that the state of LLDB for any >>>>> given test case can depend on what happened in the earlier cases. >>>>> >>>>> Adrian. >>>>> >>>>> _______________________________________________ >>>>> lldb-dev mailing list >>>>> lldb-dev@lists.llvm.org >>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev >>>>> >>>>> >>>> >>>> >>>> -- >>>> Oleksiy Vyalov | Software Engineer | ovya...@google.com >>>> _______________________________________________ >>>> lldb-dev mailing list >>>> lldb-dev@lists.llvm.org >>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev >>>> >>> >>> _______________________________________________ >>> lldb-dev mailing list >>> lldb-dev@lists.llvm.org >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev >>> >>> >> >> >> -- >> -Todd >> > >
_______________________________________________ lldb-dev mailing list lldb-dev@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev