fixed an annoying, but rare, bug where an |nsCOMPtr| in an ownership ring could |Release()| twice. See the comment in the code for details. r=waterson

This commit is contained in:
scc%netscape.com 1999-11-20 08:19:24 +00:00
Родитель 506d296672
Коммит 778573923a
4 изменённых файлов: 74 добавлений и 78 удалений

Просмотреть файл

@ -50,9 +50,7 @@ nsCOMPtr_base::assign_with_AddRef( nsISupports* rawPtr )
{ {
if ( rawPtr ) if ( rawPtr )
NSCAP_ADDREF(rawPtr); NSCAP_ADDREF(rawPtr);
if ( mRawPtr ) assign_assuming_AddRef(rawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = rawPtr;
} }
void void
@ -61,19 +59,12 @@ nsCOMPtr_base::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& i
nsISupports* newRawPtr; nsISupports* newRawPtr;
if ( !NS_SUCCEEDED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) if ( !NS_SUCCEEDED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) )
newRawPtr = 0; newRawPtr = 0;
if ( mRawPtr ) assign_assuming_AddRef(newRawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = newRawPtr;
} }
void** void**
nsCOMPtr_base::begin_assignment() nsCOMPtr_base::begin_assignment()
{ {
if ( mRawPtr ) assign_assuming_AddRef(0);
{
NSCAP_RELEASE(mRawPtr);
mRawPtr = 0;
}
return NS_REINTERPRET_CAST(void**, &mRawPtr); return NS_REINTERPRET_CAST(void**, &mRawPtr);
} }

Просмотреть файл

@ -261,7 +261,7 @@ class NS_EXPORT nsQueryInterface : public nsCOMPtr_helper
private: private:
nsISupports* mRawPtr; nsISupports* mRawPtr;
nsresult* mErrorPtr; nsresult* mErrorPtr;
}; };
inline inline
@ -373,6 +373,23 @@ class nsCOMPtr_base
protected: protected:
nsISupports* mRawPtr; nsISupports* mRawPtr;
void
assign_assuming_AddRef( nsISupports* newPtr )
{
/*
|AddRef()|ing the new value (before entering this function) before
|Release()|ing the old lets us safely ignore the self-assignment case.
We must, however, be careful only to |Release()| _after_ doing the
assignment, in case the |Release()| leads to our _own_ destruction,
which would, in turn, cause an incorrect second |Release()| of our old
pointer. Thank waterson@netscape.com for discovering this.
*/
nsISupports* oldPtr = mRawPtr;
mRawPtr = newPtr;
if ( oldPtr )
NSCAP_RELEASE(oldPtr);
}
}; };
// template <class T> class nsGetterAddRefs; // template <class T> class nsGetterAddRefs;
@ -389,6 +406,15 @@ class nsCOMPtr
void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); void assign_from_helper( const nsCOMPtr_helper&, const nsIID& );
void** begin_assignment(); void** begin_assignment();
void
assign_assuming_AddRef( T* newPtr )
{
T* oldPtr = mRawPtr;
mRawPtr = newPtr;
if ( oldPtr )
NSCAP_RELEASE(oldPtr);
}
private: private:
T* mRawPtr; T* mRawPtr;
@ -495,10 +521,7 @@ class nsCOMPtr
operator=( const nsDontAddRef<T>& rhs ) operator=( const nsDontAddRef<T>& rhs )
// assign from |dont_AddRef(expr)| // assign from |dont_AddRef(expr)|
{ {
if ( mRawPtr ) assign_assuming_AddRef(rhs.mRawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = rhs.mRawPtr;
NSCAP_ASSERT_NO_QUERY_NEEDED(); NSCAP_ASSERT_NO_QUERY_NEEDED();
return *this; return *this;
} }
@ -565,9 +588,7 @@ class nsCOMPtr
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
return NS_REINTERPRET_CAST(T**, begin_assignment()); return NS_REINTERPRET_CAST(T**, begin_assignment());
#else #else
if ( mRawPtr ) assign_assuming_AddRef(0);
NSCAP_RELEASE(mRawPtr);
mRawPtr = 0;
return NS_REINTERPRET_CAST(T**, &mRawPtr); return NS_REINTERPRET_CAST(T**, &mRawPtr);
#endif #endif
} }
@ -658,10 +679,7 @@ class nsCOMPtr<nsISupports>
operator=( const nsDontAddRef<nsISupports>& rhs ) operator=( const nsDontAddRef<nsISupports>& rhs )
// assign from |dont_AddRef(expr)| // assign from |dont_AddRef(expr)|
{ {
if ( mRawPtr ) assign_assuming_AddRef(rhs.mRawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = rhs.mRawPtr;
return *this; return *this;
} }
@ -726,9 +744,7 @@ class nsCOMPtr<nsISupports>
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
return NS_REINTERPRET_CAST(nsISupports**, begin_assignment()); return NS_REINTERPRET_CAST(nsISupports**, begin_assignment());
#else #else
if ( mRawPtr ) assign_assuming_AddRef(0);
NSCAP_RELEASE(mRawPtr);
mRawPtr = 0;
return NS_REINTERPRET_CAST(nsISupports**, &mRawPtr); return NS_REINTERPRET_CAST(nsISupports**, &mRawPtr);
#endif #endif
} }
@ -741,9 +757,7 @@ nsCOMPtr<T>::assign_with_AddRef( nsISupports* rawPtr )
{ {
if ( rawPtr ) if ( rawPtr )
NSCAP_ADDREF(rawPtr); NSCAP_ADDREF(rawPtr);
if ( mRawPtr ) assign_assuming_AddRef(NS_REINTERPRET_CAST(T*, rawPtr));
NSCAP_RELEASE(mRawPtr);
mRawPtr = NS_REINTERPRET_CAST(T*, rawPtr);
} }
template <class T> template <class T>
@ -753,21 +767,14 @@ nsCOMPtr<T>::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& aII
T* newRawPtr; T* newRawPtr;
if ( !NS_SUCCEEDED( helper(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) if ( !NS_SUCCEEDED( helper(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) )
newRawPtr = 0; newRawPtr = 0;
if ( mRawPtr ) assign_assuming_AddRef(newRawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = newRawPtr;
} }
template <class T> template <class T>
void** void**
nsCOMPtr<T>::begin_assignment() nsCOMPtr<T>::begin_assignment()
{ {
if ( mRawPtr ) assign_assuming_AddRef(0);
{
NSCAP_RELEASE(mRawPtr);
mRawPtr = 0;
}
return NS_REINTERPRET_CAST(void**, &mRawPtr); return NS_REINTERPRET_CAST(void**, &mRawPtr);
} }
#endif #endif

Просмотреть файл

@ -50,9 +50,7 @@ nsCOMPtr_base::assign_with_AddRef( nsISupports* rawPtr )
{ {
if ( rawPtr ) if ( rawPtr )
NSCAP_ADDREF(rawPtr); NSCAP_ADDREF(rawPtr);
if ( mRawPtr ) assign_assuming_AddRef(rawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = rawPtr;
} }
void void
@ -61,19 +59,12 @@ nsCOMPtr_base::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& i
nsISupports* newRawPtr; nsISupports* newRawPtr;
if ( !NS_SUCCEEDED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) if ( !NS_SUCCEEDED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) )
newRawPtr = 0; newRawPtr = 0;
if ( mRawPtr ) assign_assuming_AddRef(newRawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = newRawPtr;
} }
void** void**
nsCOMPtr_base::begin_assignment() nsCOMPtr_base::begin_assignment()
{ {
if ( mRawPtr ) assign_assuming_AddRef(0);
{
NSCAP_RELEASE(mRawPtr);
mRawPtr = 0;
}
return NS_REINTERPRET_CAST(void**, &mRawPtr); return NS_REINTERPRET_CAST(void**, &mRawPtr);
} }

Просмотреть файл

@ -261,7 +261,7 @@ class NS_EXPORT nsQueryInterface : public nsCOMPtr_helper
private: private:
nsISupports* mRawPtr; nsISupports* mRawPtr;
nsresult* mErrorPtr; nsresult* mErrorPtr;
}; };
inline inline
@ -373,6 +373,23 @@ class nsCOMPtr_base
protected: protected:
nsISupports* mRawPtr; nsISupports* mRawPtr;
void
assign_assuming_AddRef( nsISupports* newPtr )
{
/*
|AddRef()|ing the new value (before entering this function) before
|Release()|ing the old lets us safely ignore the self-assignment case.
We must, however, be careful only to |Release()| _after_ doing the
assignment, in case the |Release()| leads to our _own_ destruction,
which would, in turn, cause an incorrect second |Release()| of our old
pointer. Thank waterson@netscape.com for discovering this.
*/
nsISupports* oldPtr = mRawPtr;
mRawPtr = newPtr;
if ( oldPtr )
NSCAP_RELEASE(oldPtr);
}
}; };
// template <class T> class nsGetterAddRefs; // template <class T> class nsGetterAddRefs;
@ -389,6 +406,15 @@ class nsCOMPtr
void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); void assign_from_helper( const nsCOMPtr_helper&, const nsIID& );
void** begin_assignment(); void** begin_assignment();
void
assign_assuming_AddRef( T* newPtr )
{
T* oldPtr = mRawPtr;
mRawPtr = newPtr;
if ( oldPtr )
NSCAP_RELEASE(oldPtr);
}
private: private:
T* mRawPtr; T* mRawPtr;
@ -495,10 +521,7 @@ class nsCOMPtr
operator=( const nsDontAddRef<T>& rhs ) operator=( const nsDontAddRef<T>& rhs )
// assign from |dont_AddRef(expr)| // assign from |dont_AddRef(expr)|
{ {
if ( mRawPtr ) assign_assuming_AddRef(rhs.mRawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = rhs.mRawPtr;
NSCAP_ASSERT_NO_QUERY_NEEDED(); NSCAP_ASSERT_NO_QUERY_NEEDED();
return *this; return *this;
} }
@ -565,9 +588,7 @@ class nsCOMPtr
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
return NS_REINTERPRET_CAST(T**, begin_assignment()); return NS_REINTERPRET_CAST(T**, begin_assignment());
#else #else
if ( mRawPtr ) assign_assuming_AddRef(0);
NSCAP_RELEASE(mRawPtr);
mRawPtr = 0;
return NS_REINTERPRET_CAST(T**, &mRawPtr); return NS_REINTERPRET_CAST(T**, &mRawPtr);
#endif #endif
} }
@ -658,10 +679,7 @@ class nsCOMPtr<nsISupports>
operator=( const nsDontAddRef<nsISupports>& rhs ) operator=( const nsDontAddRef<nsISupports>& rhs )
// assign from |dont_AddRef(expr)| // assign from |dont_AddRef(expr)|
{ {
if ( mRawPtr ) assign_assuming_AddRef(rhs.mRawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = rhs.mRawPtr;
return *this; return *this;
} }
@ -726,9 +744,7 @@ class nsCOMPtr<nsISupports>
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
return NS_REINTERPRET_CAST(nsISupports**, begin_assignment()); return NS_REINTERPRET_CAST(nsISupports**, begin_assignment());
#else #else
if ( mRawPtr ) assign_assuming_AddRef(0);
NSCAP_RELEASE(mRawPtr);
mRawPtr = 0;
return NS_REINTERPRET_CAST(nsISupports**, &mRawPtr); return NS_REINTERPRET_CAST(nsISupports**, &mRawPtr);
#endif #endif
} }
@ -741,9 +757,7 @@ nsCOMPtr<T>::assign_with_AddRef( nsISupports* rawPtr )
{ {
if ( rawPtr ) if ( rawPtr )
NSCAP_ADDREF(rawPtr); NSCAP_ADDREF(rawPtr);
if ( mRawPtr ) assign_assuming_AddRef(NS_REINTERPRET_CAST(T*, rawPtr));
NSCAP_RELEASE(mRawPtr);
mRawPtr = NS_REINTERPRET_CAST(T*, rawPtr);
} }
template <class T> template <class T>
@ -753,21 +767,14 @@ nsCOMPtr<T>::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& aII
T* newRawPtr; T* newRawPtr;
if ( !NS_SUCCEEDED( helper(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) if ( !NS_SUCCEEDED( helper(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) )
newRawPtr = 0; newRawPtr = 0;
if ( mRawPtr ) assign_assuming_AddRef(newRawPtr);
NSCAP_RELEASE(mRawPtr);
mRawPtr = newRawPtr;
} }
template <class T> template <class T>
void** void**
nsCOMPtr<T>::begin_assignment() nsCOMPtr<T>::begin_assignment()
{ {
if ( mRawPtr ) assign_assuming_AddRef(0);
{
NSCAP_RELEASE(mRawPtr);
mRawPtr = 0;
}
return NS_REINTERPRET_CAST(void**, &mRawPtr); return NS_REINTERPRET_CAST(void**, &mRawPtr);
} }
#endif #endif