fdo#72695: avoid double-free race condition for SwXTextField

Change-Id: I6adfcb1bdd5e8e1525568a4bcd93a8e0e97359be
This commit is contained in:
Michael Stahl 2014-08-17 22:31:08 +02:00
parent 624198efe4
commit 8deeb0d538
5 changed files with 58 additions and 33 deletions

View file

@ -170,15 +170,16 @@ private:
SwXTextField(const SwFmtFld& rFmt, SwDoc & rDoc);
public:
/// descriptor
SwXTextField(sal_uInt16 nServiceId, SwDoc* pDoc=0);
public:
sal_uInt16 GetServiceId() const;
/// @return an SwXTextField, either an already existing one or a new one
static ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextField>
CreateXTextField(SwDoc & rDoc, SwFmtFld const& rFmt);
CreateXTextField(SwDoc * pDoc, SwFmtFld const* pFmt,
sal_uInt16 nServiceId = 0xFFFF);
static const ::com::sun::star::uno::Sequence< sal_Int8 > & getUnoTunnelId();

View file

@ -755,10 +755,11 @@ uno::Reference< uno::XInterface > SwXServiceProvider::MakeInstance(sal_uInt16
case SW_SERVICE_FIELDTYPE_COMBINED_CHARACTERS :
case SW_SERVICE_FIELDTYPE_DROPDOWN :
case SW_SERVICE_FIELDTYPE_TABLE_FORMULA:
xRet = (cppu::OWeakObject*)new SwXTextField(nObjectType);
// NOTE: the sw.SwXAutoTextEntry unoapi test depends on pDoc = 0
xRet = SwXTextField::CreateXTextField(0, 0, nObjectType);
break;
case SW_SERVICE_FIELDTYPE_ANNOTATION:
xRet = (cppu::OWeakObject*)new SwXTextField(nObjectType, pDoc);
xRet = SwXTextField::CreateXTextField(pDoc, 0, nObjectType);
break;
case SW_SERVICE_FIELDMASTER_USER:
case SW_SERVICE_FIELDMASTER_DDE:

View file

@ -522,8 +522,8 @@ bool getCrsrPropertyValue(const SfxItemPropertySimpleEntry& rEntry
if( pAny )
{
uno::Reference<text::XTextField> const xField(
SwXTextField::CreateXTextField(*rPam.GetDoc(),
pTxtAttr->GetFmtFld()));
SwXTextField::CreateXTextField(rPam.GetDoc(),
&pTxtAttr->GetFmtFld()));
*pAny <<= xField;
}
}

View file

@ -846,7 +846,7 @@ throw (beans::UnknownPropertyException, lang::WrappedTargetException,
{
pFld = aFldArr[i];
uno::Reference<text::XTextField> const xField =
SwXTextField::CreateXTextField(*m_pImpl->m_pDoc, *pFld);
SwXTextField::CreateXTextField(m_pImpl->m_pDoc, pFld);
pRetSeq[i] = uno::Reference<text::XDependentTextField>(xField,
uno::UNO_QUERY);
@ -1065,20 +1065,6 @@ OUString SwXFieldMaster::LocalizeFormula(
return rFormula;
}
uno::Reference<text::XTextField>
SwXTextField::CreateXTextField(SwDoc & rDoc, SwFmtFld const& rFmt)
{
// re-use existing SwXTextField
uno::Reference<text::XTextField> xField(rFmt.GetXTextField());
if (!xField.is())
{
SwXTextField *const pField(new SwXTextField(rFmt, rDoc));
xField.set(pField);
const_cast<SwFmtFld &>(rFmt).SetXTextField(xField);
}
return xField;
}
struct SwFieldProperties_Impl
{
OUString sPar1;
@ -1131,9 +1117,9 @@ class SwXTextField::Impl
{
private:
::osl::Mutex m_Mutex; // just for OInterfaceContainerHelper
SwXTextField & m_rThis;
public:
uno::WeakReference<uno::XInterface> m_wThis;
::cppu::OInterfaceContainerHelper m_EventListeners;
SwFmtFld const* m_pFmtFld;
@ -1148,10 +1134,9 @@ public:
OUString m_sTypeName;
boost::scoped_ptr<SwFieldProperties_Impl> m_pProps;
Impl(SwXTextField & rThis, SwDoc *const pDoc, SwFmtFld const*const pFmt,
Impl(SwDoc *const pDoc, SwFmtFld const*const pFmt,
sal_uInt16 const nServiceId)
: SwClient((pFmt) ? pDoc->GetUnoCallBack() : 0)
, m_rThis(rThis)
, m_EventListeners(m_Mutex)
, m_pFmtFld(pFmt)
, m_pDoc(pDoc)
@ -1202,7 +1187,7 @@ throw (uno::RuntimeException, std::exception)
SwXTextField::SwXTextField(
sal_uInt16 nServiceId,
SwDoc* pDoc)
: m_pImpl(new Impl(*this, pDoc, 0, nServiceId))
: m_pImpl(new Impl(pDoc, 0, nServiceId))
{
//Set visible as default!
if ( SW_SERVICE_FIELDTYPE_SET_EXP == nServiceId
@ -1225,7 +1210,7 @@ SwXTextField::SwXTextField(
SwXTextField::SwXTextField(
const SwFmtFld& rFmt,
SwDoc & rDoc)
: m_pImpl(new Impl(*this, &rDoc, &rFmt, USHRT_MAX))
: m_pImpl(new Impl(&rDoc, &rFmt, USHRT_MAX))
{
}
@ -1233,6 +1218,34 @@ SwXTextField::~SwXTextField()
{
}
uno::Reference<text::XTextField>
SwXTextField::CreateXTextField(SwDoc *const pDoc, SwFmtFld const* pFmt,
sal_uInt16 const nServiceId)
{
assert(!pFmt || pDoc);
assert(pFmt || nServiceId != 0xFFFF);
// re-use existing SwXTextField
uno::Reference<text::XTextField> xField;
if (pFmt)
{
xField = pFmt->GetXTextField();
}
if (!xField.is())
{
SwXTextField *const pField( (pFmt)
? new SwXTextField(*pFmt, *pDoc)
: new SwXTextField(nServiceId, pDoc));
xField.set(pField);
if (pFmt)
{
const_cast<SwFmtFld *>(pFmt)->SetXTextField(xField);
}
// need a permanent Reference to initialize m_wThis
pField->m_pImpl->m_wThis = xField;
}
return xField;
}
sal_uInt16 SwXTextField::GetServiceId() const
{
return m_pImpl->m_nServiceId;
@ -1317,6 +1330,7 @@ throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
SwDoc* pDoc = pRange ? (SwDoc*)pRange->GetDoc() : pCursor ? (SwDoc*)pCursor->GetDoc() : 0;
// if a FieldMaster was attached, then the document is already fixed!
// NOTE: sw.SwXAutoTextEntry unoapi test depends on m_pDoc = 0 being valid
if (!pDoc || (m_pImpl->m_pDoc && m_pImpl->m_pDoc != pDoc))
throw lang::IllegalArgumentException();
@ -2585,7 +2599,12 @@ void SwXTextField::Impl::Invalidate()
GetRegisteredInNonConst()->Remove(this);
m_pFmtFld = 0;
m_pDoc = 0;
lang::EventObject const ev(static_cast< ::cppu::OWeakObject&>(m_rThis));
uno::Reference<uno::XInterface> const xThis(m_wThis);
if (!xThis.is())
{ // fdo#72695: if UNO object is already dead, don't revive it with event
return;
}
lang::EventObject const ev(xThis);
m_EventListeners.disposeAndClear(ev);
}
}
@ -2990,7 +3009,7 @@ SwXFieldEnumeration::SwXFieldEnumeration(SwDoc & rDoc)
!pTxtFld->GetpTxtNode()->GetNodes().IsDocNodes();
if (!bSkip)
pItems[ nFillPos++ ] = SwXTextField::CreateXTextField(
*m_pImpl->m_pDoc, *pCurFldFmt);
m_pImpl->m_pDoc, pCurFldFmt);
pCurFldFmt = aIter.Next();
// enlarge sequence if necessary

View file

@ -273,8 +273,9 @@ namespace
rAnnotationStartArr.insert(
SwAnnotationStartPortion_ImplSharedPtr(
new SwAnnotationStartPortion_Impl(
SwXTextField::CreateXTextField( rDoc, *pAnnotationFmtFld ),
rStartPos ) ) );
SwXTextField::CreateXTextField(&rDoc,
pAnnotationFmtFld),
rStartPos)));
}
}
}
@ -810,7 +811,8 @@ lcl_ExportHints(
new SwXTextPortion(
pUnoCrsr, xParent, PORTION_FIELD);
Reference<XTextField> const xField =
SwXTextField::CreateXTextField(*pDoc, pAttr->GetFmtFld());
SwXTextField::CreateXTextField(pDoc,
&pAttr->GetFmtFld());
pPortion->SetTextField(xField);
}
break;
@ -835,7 +837,8 @@ lcl_ExportHints(
{
SwXTextPortion* pPortion = new SwXTextPortion( pUnoCrsr, xParent, PORTION_ANNOTATION );
Reference<XTextField> xField =
SwXTextField::CreateXTextField(*pDoc, pAttr->GetFmtFld());
SwXTextField::CreateXTextField(pDoc,
&pAttr->GetFmtFld());
pPortion->SetTextField(xField);
xRef = pPortion;
}
@ -857,7 +860,8 @@ lcl_ExportHints(
new SwXTextPortion( pUnoCrsr, xParent, PORTION_FIELD);
xRef = pPortion;
Reference<XTextField> xField =
SwXTextField::CreateXTextField(*pDoc, pAttr->GetFmtFld());
SwXTextField::CreateXTextField(pDoc,
&pAttr->GetFmtFld());
pPortion->SetTextField(xField);
}
break;