[lldb-dev] Python object lifetimes affect the reliability of tests

Adrian McCarthy via lldb-dev lldb-dev at lists.llvm.org
Thu Oct 15 10:11:37 PDT 2015


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 <amccarth at google.com>
wrote:

>
> On Thu, Oct 15, 2015 at 9:31 AM, Todd Fiala <todd.fiala at gmail.com> wrote:
>
>>
>>
>> On Thu, Oct 15, 2015 at 9:23 AM, Zachary Turner via lldb-dev <
>> lldb-dev at 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 at 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 at 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 at lists.llvm.org
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Oleksiy Vyalov | Software Engineer | ovyalov at google.com
>>>> _______________________________________________
>>>> lldb-dev mailing list
>>>> lldb-dev at lists.llvm.org
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>>>>
>>>
>>> _______________________________________________
>>> lldb-dev mailing list
>>> lldb-dev at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>>>
>>>
>>
>>
>> --
>> -Todd
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20151015/72dec56e/attachment-0001.html>


More information about the lldb-dev mailing list