Bug 158913 - Error: attempt to increment a singular iterator.
Summary: Error: attempt to increment a singular iterator.
Status: RESOLVED FIXED
Alias: None
Product: LibreOffice
Classification: Unclassified
Component: Draw (show other bugs)
Version:
(earliest affected)
24.8.0.0 alpha0+ Master
Hardware: All All
: medium normal
Assignee: Armin Le Grand
URL:
Whiteboard: target:24.8.0
Keywords: bisected, regression
Depends on:
Blocks: Crash
  Show dependency treegraph
 
Reported: 2023-12-28 20:49 UTC by Caolán McNamara
Modified: 2024-02-25 02:00 UTC (History)
5 users (show)

See Also:
Crash report or crash signature:


Attachments
reproducer (957.40 KB, application/vnd.oasis.opendocument.graphics)
2023-12-28 20:49 UTC, Caolán McNamara
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Caolán McNamara 2023-12-28 20:49:01 UTC
Description:
crash of "Error: attempt to increment a singular iterator."

Steps to Reproduce:
1. with a dbgutil linux build
2. ./instdir/program/soffice --headless --convert-to pdf ~/Downloads/moz766916-1.odg


Actual Results:
backtrace of:

#3  0x00007ffff74a7493 in std::__throw_bad_exception() () at /lib64/libstdc++.so.6
#4  0x00007fffe96eadbe in __gnu_debug::_Safe_iterator<std::__cxx1998::_Deque_iterator<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>, rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> const&, rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> const*>, std::__debug::deque<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>, std::allocator<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> > >, std::forward_iterator_tag>::operator++() (this=0x7ffffffef028) at /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/debug/safe_iterator.h:326
#5  0x00007fffe96eacf9 in __gnu_debug::_Safe_iterator<std::__cxx1998::_Deque_iterator<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>, rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> const&, rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> const*>, std::__debug::deque<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>, std::allocator<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> > >, std::bidirectional_iterator_tag>::operator++() (this=0x7ffffffef028) at /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/debug/safe_iterator.h:594
#6  0x00007fffe96ea479 in __gnu_debug::_Safe_iterator<std::__cxx1998::_Deque_iterator<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>, rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> const&, rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> const*>, std::__debug::deque<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>, std::allocator<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> > >, std::random_access_iterator_tag>::operator++() (this=0x7ffffffef028) at /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/debug/safe_iterator.h:748
#7  0x00007fffe9780eae in drawinglayer::processor2d::BaseProcessor2D::process(drawinglayer::primitive2d::Primitive2DContainer const&)
    (this=0x5f8e040, rSource=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:65
#8  0x00007fffe97ba3bc in drawinglayer::processor2d::VclProcessor2D::RenderTransformPrimitive2D(drawinglayer::primitive2d::TransformPrimitive2D const&)
    (this=0x5f8e040, rTransformCandidate=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/vclprocessor2d.cxx:1003
#9  0x00007fffe979abca in drawinglayer::processor2d::VclMetafileProcessor2D::processBasePrimitive2D(drawinglayer::primitive2d::BasePrimitive2D const&)
    (this=0x5f8e040, rCandidate=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx:862
#10 0x00007fffe9780e6a in drawinglayer::processor2d::BaseProcessor2D::process(drawinglayer::primitive2d::Primitive2DContainer const&)
    (this=0x5f8e040, rSource=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:68
#11 0x00007fffe9780d4d in drawinglayer::processor2d::BaseProcessor2D::visit(drawinglayer::primitive2d::Primitive2DContainer const&)
    (this=0x5f8e040, rContainer=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:56
#12 0x00007ffff466a4a6 in drawinglayer::primitive2d::BufferedDecompositionPrimitive2D::get2DDecomposition(drawinglayer::primitive2d::Primitive2DDecompositionVisitor&, drawinglayer::geometry::ViewInformation2D const&) const (this=0x5ee0660, rVisitor=..., rViewInformation=...)
    at /home/caolan/LibreOffice/core/drawinglayer/source/primitive2d/BufferedDecompositionPrimitive2D.cxx:124
#13 0x00007fffe9780ce6 in drawinglayer::processor2d::BaseProcessor2D::process(drawinglayer::primitive2d::BasePrimitive2D const&)
    (this=0x5f8e040, rCandidate=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:46
#14 0x00007fffe979adfb in drawinglayer::processor2d::VclMetafileProcessor2D::processGraphicPrimitive2D(drawinglayer::primitive2d::GraphicPrimitive2D const&)
    (this=0x5f8e040, rGraphicPrimitive=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx:1006
#15 0x00007fffe979aa3a in drawinglayer::processor2d::VclMetafileProcessor2D::processBasePrimitive2D(drawinglayer::primitive2d::BasePrimitive2D const&)
    (this=0x5f8e040, rCandidate=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx:727
#16 0x00007fffe9780e6a in drawinglayer::processor2d::BaseProcessor2D::process(drawinglayer::primitive2d::Primitive2DContainer const&)
    (this=0x5f8e040, rSource=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:68
#17 0x00007fffe9780d4d in drawinglayer::processor2d::BaseProcessor2D::visit(drawinglayer::primitive2d::Primitive2DContainer const&)
    (this=0x5f8e040, rContainer=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:56
#18 0x00007ffff466a4a6 in drawinglayer::primitive2d::BufferedDecompositionPrimitive2D::get2DDecomposition(drawinglayer::primitive2d::Primitive2DDecompositionVisitor&, drawinglayer::geometry::ViewInformation2D const&) const (this=0x5edd2b0, rVisitor=..., rViewInformation=...)
    at /home/caolan/LibreOffice/core/drawinglayer/source/primitive2d/BufferedDecompositionPrimitive2D.cxx:124
#19 0x00007fffe9780ce6 in drawinglayer::processor2d::BaseProcessor2D::process(drawinglayer::primitive2d::BasePrimitive2D const&)
    (this=0x5f8e040, rCandidate=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:46
#20 0x00007fffe979ac62 in drawinglayer::processor2d::VclMetafileProcessor2D::processBasePrimitive2D(drawinglayer::primitive2d::BasePrimitive2D const&)
    (this=0x5f8e040, rCandidate=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx:921
#21 0x00007fffe9780e6a in drawinglayer::processor2d::BaseProcessor2D::process(drawinglayer::primitive2d::Primitive2DContainer const&)
    (this=0x5f8e040, rSource=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:68
#22 0x00007fffe97a51d1 in drawinglayer::processor2d::VclMetafileProcessor2D::processStructureTagPrimitive2D(drawinglayer::primitive2d::StructureTagPrimitive2D const&) (this=0x5f8e040, rStructureTagCandidate=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx:2637
#23 0x00007fffe979ac12 in drawinglayer::processor2d::VclMetafileProcessor2D::processBasePrimitive2D(drawinglayer::primitive2d::BasePrimitive2D const&)
    (this=0x5f8e040, rCandidate=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx:889
#24 0x00007fffe9780e6a in drawinglayer::processor2d::BaseProcessor2D::process(drawinglayer::primitive2d::Primitive2DContainer const&)
    (this=0x5f8e040, rSource=...) at /home/caolan/LibreOffice/core/drawinglayer/source/processor2d/baseprocessor2d.cxx:68
#25 0x00007ffff12b13f6 in sdr::contact::ObjectContactOfPageView::DoProcessDisplay(sdr::contact::DisplayInfo&) (this=0x5f2ded0, rDisplayInfo=...)
    at /home/caolan/LibreOffice/core/svx/source/sdr/contact/objectcontactofpageview.cxx:278
#26 0x00007ffff12b0da2 in sdr::contact::ObjectContactOfPageView::ProcessDisplay(sdr::contact::DisplayInfo&) (this=0x5f2ded0, rDisplayInfo=...)
    at /home/caolan/LibreOffice/core/svx/source/sdr/contact/objectcontactofpageview.cxx:118
#27 0x00007ffff1348322 in SdrPageWindow::RedrawAll(sdr::contact::ViewObjectContactRedirector*) (this=0x5f87820, pRedirector=0x7fffffff0ab0)
    at /home/caolan/LibreOffice/core/svx/source/svdraw/sdrpagewindow.cxx:352
#28 0x00007ffff160cef8 in SdrPageView::CompleteRedraw(SdrPaintWindow&, vcl::Region const&, sdr::contact::ViewObjectContactRedirector*)
    (this=0x5f35ff0, rPaintWindow=..., rReg=..., pRedirector=0x7fffffff0ab0) at /home/caolan/LibreOffice/core/svx/source/svdraw/svdpagv.cxx:239
#29 0x00007ffff162677d in SdrPaintView::DoCompleteRedraw(SdrPaintWindow&, vcl::Region const&, sdr::contact::ViewObjectContactRedirector*)
    (this=0x7fffffff0b90, rPaintWindow=..., rReg=..., pRedirector=0x7fffffff0ab0) at /home/caolan/LibreOffice/core/svx/source/svdraw/svdpntv.cxx:612
#30 0x00007ffff162668f in SdrPaintView::CompleteRedraw(OutputDevice*, vcl::Region const&, sdr::contact::ViewObjectContactRedirector*)
    (this=0x7fffffff0b90, pOut=0x5f78260, rReg=..., pRedirector=0x7fffffff0ab0) at /home/caolan/LibreOffice/core/svx/source/svdraw/svdpntv.cxx:525
#31 0x00007fffd550af40 in SdXImpressDocument::render(int, com::sun::star::uno::Any const&, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) (this=0x1c45d10, nRenderer=0, rSelection=uno::Any("com.sun.star.lang.XComponent": ...), rxOptions=uno::Sequence of length 9 = {...})
    at /home/caolan/LibreOffice/core/sd/source/ui/unoidl/unomodel.cxx:2134


Expected Results:
no crash


Reproducible: Always


User Profile Reset: No

Additional Info:
bisected to:

commit 0d512011a695da8dafe9467ec0ff7f564dfe8c88
Date:   Mon Dec 18 18:23:37 2023 +0100

    Add flush mechanism to buffered Primitives


and still seen after:

commit 71c555c5ae31d84dff8d9448fd2be4dab23f20a8
Date:   Thu Dec 21 15:02:52 2023 +0100

    Add flush mechanism to buffered Primitives II

with build of 10e7d8d1dcf0e3a45044643ab7b572af997543e9
Comment 1 Caolán McNamara 2023-12-28 20:49:25 UTC
Created attachment 191618 [details]
reproducer
Comment 2 Stéphane Guillou (stragu) 2023-12-28 23:09:38 UTC
Struggles but manages to convert with debug build from before the bisected commit:

Version: 24.8.0.0.alpha0+ (X86_64) / LibreOffice Community
Build ID: fdc87dd56548622e13353b4cf9864232ee0110fb
CPU threads: 8; OS: Linux 5.15; UI render: default; VCL: gtk3
Locale: en-AU (en_AU.UTF-8); UI: en-US
Calc: threaded

Reproduced with recent debug build:

Version: 24.8.0.0.alpha0+ (X86_64) / LibreOffice Community
Build ID: 29097009b1f8c0dcb050367d3f2acfcaf2074a56
CPU threads: 8; OS: Linux 5.15; UI render: default; VCL: gtk3
Locale: en-AU (en_AU.UTF-8); UI: en-US
Calc: threaded

In console:

/opt/rh/gcc-toolset-12/root/usr/include/c++/12/debug/safe_iterator.h:332:
In function:
    gnu_debug::_Safe_iterator<_Iterator, _Sequence, _Category>& 
    gnu_debug::_Safe_iterator<_Iterator, _Sequence, _Category>::operator++() 
    [with _Iterator = std::
    _Deque_iterator<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>, 
    const rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>&, const 
    rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>*>; _Sequence 
    = std::
    debug::deque<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> 
    >; _Category = std::forward_iterator_tag]

Error: attempt to increment a singular iterator.

Objects involved in the operation:
    iterator "this" @ 0x7ffe594ee120 {
      type = std::_Deque_iterator<rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>, rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> const&, rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> const*> (constant iterator);
      state = singular;
    }
Unspecified Application Error

No repro in non-debug build:

Version: 24.8.0.0.alpha0+ (X86_64) / LibreOffice Community
Build ID: 40617d867346956588ac023511f31210107217f4
CPU threads: 8; OS: Linux 5.15; UI render: default; VCL: gtk3
Locale: en-AU (en_AU.UTF-8); UI: en-US
Calc: threaded
Comment 3 Armin Le Grand 2024-01-02 14:04:24 UTC
Happens as described. Also quickly found the problem - the Primitive is deleted while being in use.

The original concept designing the Primitives was to have read-only, small, unchangeable objects. This is undermined by the 'visitor' concept - the instance owning the Primitive decomposition/representation 'directly' uses that representation, while at the same time that instance is allowed to re-create (and thus also delete) that instance.
This can/could not happen without the visitor concept before: The instances were fetched and held safe ref-counted (that's why Primitives can be held by uno::Reference).

I see the (small) advantage here by using that visitor concept, but:
- less ref-counting (guessed initial reason for visitor concept?) is easily possible by packing decompositions in single references by themselves (Group/transformPrimitive with neutral transformation), so no need to achieve that advantage by 'visitor' concept and pay the security price for it
- potentially more usage of multi-threading with Primitives, esp. for expensive decomposition ceations combined with timing stuff

So - for the future - I would really prefer safety/ref-counting over small advantages (other achievable, see above) here.

For now I will probably just make that safe using a std::mutex to ensure that the local decomposition gets *not* changed while being 'visited' - with the known possible costs for multi-threading. Of course only when really needed, to minimize possible impact(s)...
Comment 4 Armin Le Grand 2024-01-02 15:06:12 UTC
Added https://gerrit.libreoffice.org/c/core/+/161543 to gerrit, works locally and should do it.
Comment 5 Commit Notification 2024-01-02 19:38:32 UTC
Armin Le Grand (allotropia) committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/e1402abc5c6d08ae541ca6ef31b017034232d4cf

tdf#158913 secure Primitive 'visit' using mutex

It will be available in 24.8.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.