Hi guys, I've been chasing this bug: https://bugs.documentfoundation.org/show_bug.cgi?id=91125 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/vgpreload_memcheck-amd64-linux.so) 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 continue end (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. now $ cat gdb-log.txt | chase.pl 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 =) ATB, Michael. -- michael.meeks@collabora.com <><, Pseudo Engineer, itinerant idiot
Attachment:
chase.pl
Description: Perl program