crashtesting: use after free on export of tdf122510-1.xlsx to ods

and also tdf95549-3.xlsm

related to:

commit f8c1048eb437b1e685b76198165844e2ecc97a56
Date:   Wed May 19 19:04:02 2021 +0200

    fix leak in oox import

and:

commit 3cd6402c5443c8069c07d9e420d5ef5b43af6bef
Date:   Thu May 6 18:47:30 2021 +0200

    tdf#127301 XLSX import: hide hidden named range of autofilter

clearly this is fragile so just explicitly return who owns the
ScRangeData*

Change-Id: Ic3210bb8788bbbc85609bb384fa4a4625c15e487
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116432
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/sc/source/filter/inc/defnamesbuffer.hxx b/sc/source/filter/inc/defnamesbuffer.hxx
index 03eec97..3200bd5 100644
--- a/sc/source/filter/inc/defnamesbuffer.hxx
+++ b/sc/source/filter/inc/defnamesbuffer.hxx
@@ -122,7 +122,7 @@ public:
private:
    typedef ::std::unique_ptr< StreamDataSequence >   StreamDataSeqPtr;

    ScRangeData*        mpScRangeData;       /// ScRangeData of the defined name.
    RangeDataRet        maScRangeData;      /// ScRangeData of the defined name.
    sal_Int32           mnTokenIndex;       /// Name index used in API token array.
    sal_Int16           mnCalcSheet;        /// Calc sheet index for sheet-local names.
    sal_Unicode         mcBuiltinId;        /// Identifier for built-in defined names.
diff --git a/sc/source/filter/inc/workbookhelper.hxx b/sc/source/filter/inc/workbookhelper.hxx
index e6633d1..d6d0400 100644
--- a/sc/source/filter/inc/workbookhelper.hxx
+++ b/sc/source/filter/inc/workbookhelper.hxx
@@ -160,10 +160,13 @@ public:
    css::uno::Reference< css::style::XStyle >
                        getStyleObject( const OUString& rStyleName, bool bPageStyle ) const;

    // second is true if ownership belongs to the caller
    typedef std::pair<ScRangeData*, bool> RangeDataRet;

    /** Creates and returns a defined name on-the-fly in the Calc document.
        The name will not be buffered in the global defined names buffer.
        @param orName  (in/out-parameter) Returns the resulting used name. */
    ScRangeData* createNamedRangeObject(
    RangeDataRet createNamedRangeObject(
                            OUString& orName,
                            const css::uno::Sequence< css::sheet::FormulaToken>& rTokens,
                            sal_Int32 nIndex,
@@ -172,7 +175,7 @@ public:
    /** Creates and returns a defined name on-the-fly in the sheet.
        The name will not be buffered in the global defined names buffer.
        @param orName  (in/out-parameter) Returns the resulting used name. */
    ScRangeData* createLocalNamedRangeObject(
    RangeDataRet createLocalNamedRangeObject(
                            OUString& orName,
                            const css::uno::Sequence< css::sheet::FormulaToken>& rTokens,
                            sal_Int32 nIndex,
diff --git a/sc/source/filter/oox/defnamesbuffer.cxx b/sc/source/filter/oox/defnamesbuffer.cxx
index a554ab9..9eebaf1 100644
--- a/sc/source/filter/oox/defnamesbuffer.cxx
+++ b/sc/source/filter/oox/defnamesbuffer.cxx
@@ -146,7 +146,7 @@ const OUString& DefinedNameBase::getUpcaseModelName() const

DefinedName::DefinedName( const WorkbookHelper& rHelper ) :
    DefinedNameBase( rHelper ),
    mpScRangeData(nullptr),
    maScRangeData(nullptr, false),
    mnTokenIndex( -1 ),
    mnCalcSheet( 0 ),
    mcBuiltinId( BIFF_DEFNAME_UNKNOWN )
@@ -233,9 +233,9 @@ void DefinedName::createNameObject( sal_Int32 nIndex )

    // create the name and insert it into the document, maCalcName will be changed to the resulting name
    if (maModel.mnSheet >= 0)
        mpScRangeData = createLocalNamedRangeObject( maCalcName, ApiTokenSequence(), nIndex, nNameFlags, maModel.mnSheet, maModel.mbHidden );
        maScRangeData = createLocalNamedRangeObject( maCalcName, ApiTokenSequence(), nIndex, nNameFlags, maModel.mnSheet, maModel.mbHidden );
    else
        mpScRangeData = createNamedRangeObject( maCalcName, ApiTokenSequence(), nIndex, nNameFlags, maModel.mbHidden );
        maScRangeData = createNamedRangeObject( maCalcName, ApiTokenSequence(), nIndex, nNameFlags, maModel.mbHidden );
    mnTokenIndex = nIndex;
}

@@ -259,17 +259,18 @@ std::unique_ptr<ScTokenArray> DefinedName::getScTokens(

void DefinedName::convertFormula( const css::uno::Sequence<css::sheet::ExternalLinkInfo>& rExternalLinks )
{
    ScRangeData* pScRangeData = maScRangeData.first;
    // macro function or vba procedure
    if(!mpScRangeData)
    if (!pScRangeData)
        return;

    // convert and set formula of the defined name
    {
        std::unique_ptr<ScTokenArray> pTokenArray = getScTokens( rExternalLinks);
        mpScRangeData->SetCode( *pTokenArray );
        pScRangeData->SetCode( *pTokenArray );
    }

    ScTokenArray* pTokenArray = mpScRangeData->GetCode();
    ScTokenArray* pTokenArray = pScRangeData->GetCode();
    Sequence< FormulaToken > aFTokenSeq;
    ScTokenConversion::ConvertToTokenSequence( getScDocument(), aFTokenSeq, *pTokenArray );
    // set built-in names (print ranges, repeated titles, filter ranges)
@@ -327,7 +328,8 @@ void DefinedName::convertFormula( const css::uno::Sequence<css::sheet::ExternalL

bool DefinedName::getAbsoluteRange( ScRange& orRange ) const
{
    ScTokenArray* pTokenArray = mpScRangeData->GetCode();
    ScRangeData* pScRangeData = maScRangeData.first;
    ScTokenArray* pTokenArray = pScRangeData->GetCode();
    Sequence< FormulaToken > aFTokenSeq;
    ScTokenConversion::ConvertToTokenSequence(getScDocument(), aFTokenSeq, *pTokenArray);
    return getFormulaParser().extractCellRange( orRange, aFTokenSeq );
@@ -336,12 +338,11 @@ bool DefinedName::getAbsoluteRange( ScRange& orRange ) const
DefinedName::~DefinedName()
{
    // this kind of field is owned by us - see lcl_addNewByNameAndTokens
    if (mpScRangeData && maModel.mbHidden &&
        (mcBuiltinId == BIFF_DEFNAME_CRITERIA || mcBuiltinId == BIFF_DEFNAME_FILTERDATABASE))
        delete mpScRangeData;
    bool bOwned = maScRangeData.second;
    if (bOwned)
        delete maScRangeData.first;
}


DefinedNamesBuffer::DefinedNamesBuffer( const WorkbookHelper& rHelper ) :
    WorkbookHelper( rHelper )
{
diff --git a/sc/source/filter/oox/workbookhelper.cxx b/sc/source/filter/oox/workbookhelper.cxx
index 8c7ffb3..8a78041 100644
--- a/sc/source/filter/oox/workbookhelper.cxx
+++ b/sc/source/filter/oox/workbookhelper.cxx
@@ -149,9 +149,9 @@ public:
    /** Returns the specified cell or page style from the Calc document. */
    Reference< XStyle > getStyleObject( const OUString& rStyleName, bool bPageStyle ) const;
    /** Creates and returns a defined name on-the-fly in the Calc document. */
    ScRangeData* createNamedRangeObject( OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, bool bHidden );
    WorkbookHelper::RangeDataRet createNamedRangeObject( OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, bool bHidden );
    /** Creates and returns a defined name on the-fly in the correct Calc sheet. */
    ScRangeData* createLocalNamedRangeObject( OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden );
    WorkbookHelper::RangeDataRet createLocalNamedRangeObject( OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden );
    /** Creates and returns a database range on-the-fly in the Calc document. */
    Reference< XDatabaseRange > createDatabaseRangeObject( OUString& orName, const ScRange& rRangeAddr );
    /** Creates and returns an unnamed database range on-the-fly in the Calc document. */
@@ -350,7 +350,7 @@ Reference< XStyle > WorkbookGlobals::getStyleObject( const OUString& rStyleName,

namespace {

ScRangeData* lcl_addNewByNameAndTokens( ScDocument& rDoc, ScRangeName* pNames, const OUString& rName, const Sequence<FormulaToken>& rTokens, sal_Int16 nIndex, sal_Int32 nUnoType, bool bHidden )
WorkbookHelper::RangeDataRet lcl_addNewByNameAndTokens( ScDocument& rDoc, ScRangeName* pNames, const OUString& rName, const Sequence<FormulaToken>& rTokens, sal_Int16 nIndex, sal_Int32 nUnoType, bool bHidden )
{
    bool bDone = false;
    ScRangeData::Type nNewType = ScRangeData::Type::Name;
@@ -366,7 +366,9 @@ ScRangeData* lcl_addNewByNameAndTokens( ScDocument& rDoc, ScRangeName* pNames, c
        pNew->SetIndex( nIndex );
    // create but not insert hidden FILTER_CRITERIA named ranges to ScRangeName
    if ( bHidden && nNewType == ScRangeData::Type::Criteria )
        return pNew;
    {
        return WorkbookHelper::RangeDataRet(pNew, true);
    }
    if ( pNames->insert(pNew) )
        bDone = true;
    if (!bDone)
@@ -374,7 +376,7 @@ ScRangeData* lcl_addNewByNameAndTokens( ScDocument& rDoc, ScRangeName* pNames, c
        delete pNew;
        throw RuntimeException();
    }
    return pNew;
    return WorkbookHelper::RangeDataRet(pNew, false);
}

OUString findUnusedName( const ScRangeName* pRangeName, const OUString& rSuggestedName )
@@ -389,11 +391,11 @@ OUString findUnusedName( const ScRangeName* pRangeName, const OUString& rSuggest

}

ScRangeData* WorkbookGlobals::createNamedRangeObject(
WorkbookHelper::RangeDataRet WorkbookGlobals::createNamedRangeObject(
    OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, bool bHidden )
{
    // create the name and insert it into the Calc document
    ScRangeData* pScRangeData = nullptr;
    WorkbookHelper::RangeDataRet aScRangeData(nullptr, false);
    if( !orName.isEmpty() )
    {
        ScDocument& rDoc =  getScDocument();
@@ -401,16 +403,16 @@ ScRangeData* WorkbookGlobals::createNamedRangeObject(
        // find an unused name
        orName = findUnusedName( pNames, orName );
        // create the named range
        pScRangeData = lcl_addNewByNameAndTokens( rDoc, pNames, orName, rTokens, nIndex, nNameFlags, bHidden );
        aScRangeData = lcl_addNewByNameAndTokens( rDoc, pNames, orName, rTokens, nIndex, nNameFlags, bHidden );
    }
    return pScRangeData;
    return aScRangeData;
}

ScRangeData* WorkbookGlobals::createLocalNamedRangeObject(
WorkbookHelper::RangeDataRet WorkbookGlobals::createLocalNamedRangeObject(
    OUString& orName, const Sequence< FormulaToken >&  rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden )
{
    // create the name and insert it into the Calc document
    ScRangeData* pScRangeData = nullptr;
    WorkbookHelper::RangeDataRet aScRangeData(nullptr, false);
    if( !orName.isEmpty() )
    {
        ScDocument& rDoc =  getScDocument();
@@ -420,9 +422,9 @@ ScRangeData* WorkbookGlobals::createLocalNamedRangeObject(
        // find an unused name
        orName = findUnusedName( pNames, orName );
        // create the named range
        pScRangeData = lcl_addNewByNameAndTokens( rDoc, pNames, orName, rTokens, nIndex, nNameFlags, bHidden );
        aScRangeData = lcl_addNewByNameAndTokens( rDoc, pNames, orName, rTokens, nIndex, nNameFlags, bHidden );
    }
    return pScRangeData;
    return aScRangeData;
}

Reference< XDatabaseRange > WorkbookGlobals::createDatabaseRangeObject( OUString& orName, const ScRange& rRangeAddr )
@@ -865,12 +867,12 @@ Reference< XStyle > WorkbookHelper::getStyleObject( const OUString& rStyleName, 
    return mrBookGlob.getStyleObject( rStyleName, bPageStyle );
}

ScRangeData* WorkbookHelper::createNamedRangeObject( OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, bool bHidden ) const
WorkbookHelper::RangeDataRet WorkbookHelper::createNamedRangeObject( OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, bool bHidden ) const
{
    return mrBookGlob.createNamedRangeObject( orName, rTokens, nIndex, nNameFlags, bHidden );
}

ScRangeData* WorkbookHelper::createLocalNamedRangeObject( OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden ) const
WorkbookHelper::RangeDataRet WorkbookHelper::createLocalNamedRangeObject( OUString& orName, const Sequence< FormulaToken>& rTokens, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden ) const
{
    return mrBookGlob.createLocalNamedRangeObject( orName, rTokens, nIndex, nNameFlags, nTab, bHidden );
}