tdf#149502 sc: crash fix: Change in Table destruction

Postpone ScTable destruction a bit, when ScTable::nTab is synchronized
with ScDocument::maTabs[] to avoid crashing.

Before the fix random crashing occurred if the ScTable::nTab was
already updated when ~ScTable() called, but the ScDocument::maTabs[]
was not reordered yet, so nTab could have pointed to the actually
deleted table in mTabs[].

Co-authored-by: Tibor Nagy (NISZ)

Change-Id: I2ac1450e3483ab334b4e20ac2598c2191e0135c9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136284
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
(cherry picked from commit c84c43320cc66152b00c0c0dad8b65de8a4b9015)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136320
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/sc/qa/unit/uicalc/data/tdf149502_HangOnDeletingSheet1.ods b/sc/qa/unit/uicalc/data/tdf149502_HangOnDeletingSheet1.ods
new file mode 100644
index 0000000..e34a75c
--- /dev/null
+++ b/sc/qa/unit/uicalc/data/tdf149502_HangOnDeletingSheet1.ods
Binary files differ
diff --git a/sc/qa/unit/uicalc/uicalc.cxx b/sc/qa/unit/uicalc/uicalc.cxx
index a6f648c..2e48f42 100644
--- a/sc/qa/unit/uicalc/uicalc.cxx
+++ b/sc/qa/unit/uicalc/uicalc.cxx
@@ -1512,6 +1512,23 @@ CPPUNIT_TEST_FIXTURE(ScUiCalcTest, testTdf86166)
    CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB>(1), pDoc->GetTableCount());
}

CPPUNIT_TEST_FIXTURE(ScUiCalcTest, testTdf149502_HangOnDeletingSheet1)
{
    ScModelObj* pModelObj = createDoc("tdf149502_HangOnDeletingSheet1.ods");
    ScDocument* pDoc = pModelObj->GetDocument();
    CPPUNIT_ASSERT(pDoc);

    CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB>(4), pDoc->GetTableCount());

    uno::Sequence<beans::PropertyValue> aArgs(
        comphelper::InitPropertySequence({ { "Index", uno::Any(sal_uInt16(0)) } }));

    // Before the fix in place, this test frozen here
    dispatchCommand(mxComponent, ".uno:Remove", aArgs);

    CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB>(3), pDoc->GetTableCount());
}

CPPUNIT_TEST_FIXTURE(ScUiCalcTest, testTdf149503)
{
    ScModelObj* pModelObj = createDoc("tdf149503.xls");
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index a458f4d..beb3e04 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -727,7 +727,14 @@ bool ScDocument::DeleteTab( SCTAB nTab )
                    if (pTab)
                        pTab->UpdateDeleteTab(aCxt);

                // tdf#149502 make sure ScTable destructor called after the erase is finished, when
                // maTabs[x].nTab==x is true again, as it should be always true.
                // In the end of maTabs.erase, maTabs indexes change, but nTab updated before erase.
                // ~ScTable expect that maTabs[x].nTab==x so it shouldn't be called during erase.
                ScTableUniquePtr pErasedTab = std::move(maTabs[nTab]);
                maTabs.erase(maTabs.begin() + nTab);
                delete pErasedTab.release();

                // UpdateBroadcastAreas must be called between UpdateDeleteTab,
                // which ends listening, and StartAllListeners, to not modify
                // areas that are to be inserted by starting listeners.