tool for chasing elusive VclPtr<> crashers ...

classic Classic list List threaded Threaded
1 message Options
Michael Meeks-5 Michael Meeks-5
Reply | Threaded
Open this post in threaded view

tool for chasing elusive VclPtr<> crashers ...

Hi guys,

        I've been chasing this bug:

        on and off for around a week. And it's quite an amazing one =)

        Before I go further, I'd like to hope this is quite a rare specimen -
the vast majority of VclPtr<> bugs are really not this bug; so this is
really a thing of last-resort:

        The stack trace shows something like this:

 0x4C28FAC: operator delete(void*) (in /usr/lib64/valgrind/
 0x3134D719: ScPivotLayoutTreeListLabel::~ScPivotLayoutTreeListLabel() (PivotLayoutTreeListLabel.cxx:33)

        Here we delete this guy - which sounds sensible; except that ...

 0xB7F3FC4: OutputDevice::release() const (outdev.hxx:284)
 0xB7F71FB: rtl::Reference<vcl::Window>::set(vcl::Window*) (ref.hxx:95)
 0xB7F5249: rtl::Reference<vcl::Window>::operator=(rtl::Reference<vcl::Window> const&) (ref.hxx:106)
 0xB7F4214: VclPtr<vcl::Window>::operator=(VclPtr<vcl::Window> const&) (vclptr.hxx:83)
 0xB82AFF4: vcl::Window::ImplRemoveWindow(bool) (stacking.cxx:148)
 0xB9A8E20: vcl::Window::dispose() (window.cxx:511)
 0xBA12D1D: Control::dispose() (ctrl.cxx:76)
 0x9B434A5: SvTreeListBox::dispose() (treelistbox.cxx:1584)
 0x313499FD: ScPivotLayoutTreeListBase::dispose() (PivotLayoutTreeListBase.cxx:38)
 0xBAEF813: OutputDevice::disposeOnce() (outdev.cxx:203)
 0xB85E3BF: VclPtr<vcl::Window>::disposeAndClear() (vclptr.hxx:209)

        In this frame we are holding a reference (to ensure that the object
lives until the end of the disposeAndClear)

 0xB83F000: VclBuilder::disposeBuilder() (builder.cxx:536)

        So - despite all the smart-ref-counting logic - somehow we're getting
the reference counting wrong:

        So ... after about a week of chasing this on & off, I found the bug
which is here:

sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvTreeListBox* pSourceView )
    SvLBoxDDInfo aDDInfo;
    memset( &aDDInfo, 0, sizeof(SvLBoxDDInfo) );

    TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
    if( aData.HasFormat( SotClipboardFormatId::TREELISTBOX ))
        css::uno::Sequence<sal_Int8> aSeq = aData.GetSequence(SotClipboardFormatId::TREELISTBOX, OUString());
        if (sizeof(SvLBoxDDInfo) == aSeq.getLength())
            memcpy( &aDDInfo, aSeq.getConstArray(), sizeof(SvLBoxDDInfo) );

        This final memcpy writes over a VclPtr<> inside the aDDInfo struct:

struct SvLBoxDDInfo
    Application*    pApp;
    VclPtr<SvTreeListBox>         pSource;

        Lets hold our breath and gloss over the -horrible- details of passing
raw pointers through an UNO sequence as a byte array and then ... [ it
seems the D&D code - which is also threaded ] is some living nightmare
in this regard ;-)

        Anyhow - the question is: how to find this stuff ? the problem being
that when you track every one of the (2000+) acquire/releases on the
underlying ref-count they all appear to be correct: there are just more
releases than there should be. [ the ref-count is stored in the object
not the VclPtr which is clobbered ].

        Anyhow - here is how:

        a) run soffice.bin under gdb:

        gdb --args ./soffice.bin 2>&1 | tee /tmp/gdb-log.txt

        place a breakpoint in the 'makeFoo' function you're
        interested in - it is rather useful to get this function
        before the construction really gets going.

        (gdb) print &mnRefCnt
        $1 = (int *) 0x12345678
        (gdb) watch *$1

        This creates a hardware watch-point so whenever the ref-count
        changes you get a trace.

        (gdb) set pagination off
        (gdb) continue

        <it will break shortly afterwards>

        (gdb) commands
        backtrace 10
        (gdb) continue

        This will then produce a log of all stack frames that maniplate the
'mnRefCnt' - in my case this produced 2000+ of them or so ;-)

        It is probable that you want a dbgutil build - or at least one with
no-optimization too.

        When you hit your crash quit gdb.

        You should have a nice gdb-log.txt now.


        $ cat gdb-log.txt |
Problematic ref-count mis-matches on VclPtr instances with values:
this=0x7fffd7391148     -1
this=0x7fffffff6e70     -1
this=0x7fffffffc5b0     1
Search for the above pointer values in your log.

        Then look for the above ptr values in your log eg.

Old value = 22
New value = 21
0x00007ffff2af3647 in OutputDevice::release (this=0x2252e10) at /data/opt/libreoffice/master/include/vcl/outdev.hxx:284
284        if (!--mnRefCnt)
#0  0x00007ffff2af3647 in OutputDevice::release (this=0x2252e10) at /data/opt/libreoffice/master/include/vcl/outdev.hxx:284

#1  0x00007ffff2baa6bb in rtl::Reference<SvTreeListBox>::~Reference (this=0x7fffd7391148, __in_chrg=<optimized out>) at /data/opt/libreoffice/master/include/rtl/ref.hxx:81
#2  0x00007ffff2ba9eca in VclPtr<SvTreeListBox>::~VclPtr (this=0x7fffd7391148, __in_chrg=<optimized out>) at /data/opt/libreoffice/master/include/vcl/vclptr.hxx:83
*******                                                        ^^^^^^^^^^^^^^ matching mis-counted VclPtr 'this'
#3  0x00007ffff2bdf75e in SvLBoxDDInfo::~SvLBoxDDInfo (this=0x7fffd7391140, __in_chrg=<optimized out>) at /data/opt/libreoffice/master/include/svtools/treelistbox.hxx:820
#4  0x00007ffff2bd4fdd in SvTreeListBox::ExecuteDrop (this=0x222eda0, rEvt=..., pSourceView=0x2252e10) at /data/opt/libreoffice/master/svtools/source/contnr/treelistbox.cxx:1282

        And this of course took me straight to the SvLBoxDDInfo code.

        Phew ;-)

        I hope that's never useful for someone else =)



 [hidden email]  <><, Pseudo Engineer, itinerant idiot

LibreOffice mailing list
[hidden email] (1K) Download Attachment