Menu

#101 Loki::COMRefCounted doesn't call AddRef() on assignment

closed-rejected
None
5
2006-05-17
2006-03-28
No

Version: loki-0.1.4

If you try to assign a COM object to a Loki smart
pointer it is wrapped into a smart pointer before it is
assigned. This wrapping smart pointer doesn't call
AddRef() but Release() when it goes out of scope and
deletes the object.

typedef ::Loki::SmartPtr<CMyObject,
::Loki::COMRefCounted, ::Loki::AllowConversion>
MyObjectPtr;

...
{
MyObjectPtr ptr;
ptr = obj; // obj is raw COM object
}
// CRASH!

Internally it's calling looks like:
...
{
MyObjectPtr ptr;
ptr = MyObjectPtr(obj); // obj is raw COM object
}

Unfortunately SmartPtr(ImplicitArg p) uses default
constructor of ownership policy which doesn't call
AddRef().

I added an additional constructor to each ownership
policy which allows special treatment of that case.

Best regards,
Thomas Albrecht

Discussion

  • Thomas Albrecht

    Thomas Albrecht - 2006-03-28

    Diff with changes to fix Loki::COMRefCounted.

     
  • Peter Kuemmel

    Peter Kuemmel - 2006-03-29

    Logged In: YES
    user_id=1159765

    Thanks Thomas,
    when I've more time I'll have a more closer look at it.
    Peter

     
  • Richard Sposato

    Richard Sposato - 2006-03-31

    Logged In: YES
    user_id=749922

    I tested the behavior of SmartPtr with the COMRefCounted
    Ownership policy. I did verify that it does not call the
    shared object's AddRef function when constructor is passed a
    pointer to shared object.

    I reviewed the diff file, and tried the fix suggested by
    Thomas Albrecht. His changes do fix the bug as intended.

    I added more tests to the SmartPtr test suite to check for
    this specific bug. I can add the new tests and the fix to
    CVS later. (Can't connect to CVS right now.)

    And many thanks to Thomas!

    Cheers,

    Rich

     
  • Richard Sposato

    Richard Sposato - 2006-03-31
    • assigned_to: nobody --> rich_sposato
     
  • Richard Sposato

    Richard Sposato - 2006-04-05

    Logged In: YES
    user_id=749922

    Fixed in Rev 1.29.

     
  • Richard Sposato

    Richard Sposato - 2006-04-05
    • status: open --> closed-fixed
     
  • Jon Colverson

    Jon Colverson - 2006-05-02

    Logged In: YES
    user_id=479642

    This looks very wrong to me. I believe the original behavior
    was by design. It's conventional that when a function gives
    out a (raw) COM interface pointer it is the responsibility
    of the giving function to do the AddRef(). From the
    "Managing a COM Object's Lifetime" section in the
    crash-course guide to COM that's included in the Microsoft
    DirectX SDK:

    "Whenever you obtain a new interface pointer, the reference
    count must be incremented by a call to AddRef. However, your
    application does not usually need to call this method. If
    you obtain an interface pointer by calling an object
    creation method or by calling QueryInterface, the object
    will automatically increment the reference count. However,
    if you create an interface pointer in some other way, such
    as copying an existing pointer, you must explicitly call
    AddRef. Otherwise, when you release the original interface
    pointer, the object may be destroyed even though you may
    still need to use the copy of the pointer."

    As such, it makes sense to me that constructing a COM
    SmartPtr with a raw pointer will take ownership of the raw
    pointer without doing an AddRef(). However, I will grant
    that many of the other COM smart pointer classes out there
    do as the patch does and AddRef() when assigned a raw COM
    pointer value. If, for some reason, you did want this
    behavior with SmartPtr then it could be achieved by
    implementing your own StoragePolicy.

    So, as I said, I'm pretty sure the original SmartPtr
    behavior was a design decision and not a bug. It could be
    argued that since it is different to many other COM smart
    pointer classes it should be changed but:
    a) I think it makes more sense not to AddRef() for the
    reasons mentioned above (I can go into more detail on this
    if needed),
    b) it changes the established behavior for all existing
    users of COMRefCounted, who will be used to the
    non-AddRef()ing behavior,
    c) this proposed "fix" makes a change to the OwnershipPolicy
    interface, affecting every user that has written a custom
    OwnershipPolicy (whether they care about COM or not).

    Since it breaks backwards compatibility, surely this patch
    should have been discussed before being committed?

     
  • Richard Sposato

    Richard Sposato - 2006-05-02

    Logged In: YES
    user_id=749922

    I did a Google search on QueryInterface, COM, and AddRef.
    I checked several links in the search result about whether
    QueryInterface does (or should) automatically call AddRef.
    All the ones I checked said that QueryInterface is supposed
    to call AddRef, and that AddRef is explicitly called only
    when one pointer is assigned from another. I found no
    websites in the search results which suggested otherwise -
    which confirms what jjc1138 wrote.

    Thomas, please check if the QueryInterface functions your
    code calls already call AddRef. I suspect the problem you
    found might be in the QueryInterface functions your code
    calls, rather than in the SmartPtr policy.

    jjc1138, since the change to SmartPtr.h was after the last
    release of Loki, it would only affect those who download
    directly from CVS. Because no changes were made to
    SmartPtr.h after that, we should be able to correct this
    with minimal fuss.

    Thanks!

    Rich

     
  • Peter Kuemmel

    Peter Kuemmel - 2006-05-17

    Logged In: YES
    user_id=1159765

    +
    + COMRefCounted(const P& val)
    + {
    + if(val!=0)
    + val->AddRef();
    + }
    +

    causes a regression in RegressionTest/SmartPtrTest.h

     
  • Peter Kuemmel

    Peter Kuemmel - 2006-05-17
    • status: closed-fixed --> open-accepted
     
  • Peter Kuemmel

    Peter Kuemmel - 2006-05-17

    Logged In: YES
    user_id=1159765

    Hi Rich,
    this sounds like you don't wanna apply Thomas patch:

    > which confirms what jjc1138 wrote.
    >
    > Thomas, please check if the QueryInterface functions your
    > code calls already call AddRef. I suspect the problem you
    > found might be in the QueryInterface functions your code
    > calls, rather than in the SmartPtr policy.

    Because of this, your last message, jjc1138 arguments and
    the regression bug we maybe should undo the 1.29 patch
    before the next release (at least the AddRef in the
    COMRefCounted constructor).

     
  • Richard Sposato

    Richard Sposato - 2006-05-17

    Logged In: YES
    user_id=749922

    Hi Peter,

    > this sounds like you don't wanna apply Thomas patch:

    Yes, that is correct. I now think the change was made when
    I had inaccurate knowledge of the problem. Let's undo the
    whole change, rather than just removing the COMRefCounted
    constructor. (Without that constructor, the other changes
    are entirely superfluous.)

    Rich

     
  • Peter Kuemmel

    Peter Kuemmel - 2006-05-17
    • status: open-accepted --> closed-rejected
     
  • Peter Kuemmel

    Peter Kuemmel - 2006-05-17

    Logged In: YES
    user_id=1159765

    I've reverted to version 1.28:

    Modified Files:
    SmartPtr.h
    Log Message:
    undo commit 1.29, reject bug: [ 1459838 ]
    Loki::COMRefCounted doesn't call AddRef() on assignment

    Index: SmartPtr.h

    RCS file: /cvsroot/loki-lib/loki/include/loki/SmartPtr.h,v
    retrieving revision 1.29
    retrieving revision 1.30
    diff -u -d -r1.29 -r1.30
    --- SmartPtr.h 5 Apr 2006 22:41:43 -0000 1.29
    +++ SmartPtr.h 17 May 2006 16:04:32 -0000 1.30
    @@ -260,15 +260,7 @@
    assert(pCount_!=0);
    *pCount_ = 1;
    }
    -
    - RefCounted( const P & )
    - : pCount_(static_cast<uintptr_t*>(
    - SmallObject<>::operator
    new(sizeof(uintptr_t))))
    - {
    - assert(pCount_!=0);
    - *pCount_ = 1;
    - }
    -
    +
    RefCounted(const RefCounted& rhs)
    pCount_(rhs.pCount_)
    {}
    @@ -337,16 +329,6 @@
    ThreadingModel<RefCountedMT,
    MX>::AtomicAssign(*pCount_, 1);
    }
    - RefCountedMT( const P & )
    - {
    - pCount_ = static_cast<CountPtrType>(
    -
    SmallObject<LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL>::operator new(
    - sizeof(*pCount_)));
    - assert(pCount_);
    - //*pCount_ = 1;
    - ThreadingModel<RefCountedMT,
    MX>::AtomicAssign(*pCount_, 1);
    - }
    -
    RefCountedMT(const RefCountedMT& rhs)
    pCount_(rhs.pCount_)
    {}
    @@ -400,13 +382,7 @@
    public:
    COMRefCounted()
    {}
    -
    - COMRefCounted(const P& val)
    - {
    - if(val!=0)
    - val->AddRef();
    - }
    -
    +
    template <class U>
    COMRefCounted(const COMRefCounted<U>&)
    {}
    @@ -445,10 +421,7 @@
    {
    DeepCopy()
    {}
    -
    - DeepCopy( const P & )
    - {}
    -
    +
    template <class P1>
    DeepCopy(const DeepCopy<P1>&)
    {}
    @@ -508,10 +481,7 @@
    public:
    RefLinked()
    {}
    -
    - RefLinked( const P & )
    - {}
    -
    +
    template <class P1>
    RefLinked(const RefLinked<P1>& rhs)
    Private::RefLinkedBase(rhs)
    @@ -544,10 +514,7 @@
    public:
    DestructiveCopy()
    {}
    -
    - DestructiveCopy( const P & )
    - {}
    -
    +
    template <class P1>
    DestructiveCopy(const DestructiveCopy<P1>&)
    {}
    @@ -583,10 +550,7 @@
    public:
    NoCopy()
    {}
    -
    - NoCopy( const P & )
    - {}
    -
    +
    template <class P1>
    NoCopy(const NoCopy<P1>&)
    {}
    @@ -655,8 +619,6 @@
    /// Well, it's clear what it does :o)
    ////////////////////////////////////////////////////////////////////////////////

    - template < class P > struct AssertCheck;
    -
    template <class P>
    struct NoCheck
    {
    @@ -667,10 +629,6 @@
    NoCheck(const NoCheck<P1>&)
    {}

    - template <class P1>
    - NoCheck(const AssertCheck<P1>&)
    - {}
    -
    static void OnDefault(const P&)
    {}

    @@ -1005,10 +963,10 @@
    { KP::OnDefault(GetImpl(*this)); }

    explicit
    - SmartPtr(ExplicitArg p) : SP(p), OP(p)
    + SmartPtr(ExplicitArg p) : SP(p)
    { KP::OnInit(GetImpl(*this)); }

    - SmartPtr(ImplicitArg p) : SP(p), OP(p)
    + SmartPtr(ImplicitArg p) : SP(p)
    { KP::OnInit(GetImpl(*this)); }

    SmartPtr(CopyArg& rhs)
    @@ -1561,7 +1519,11 @@

    #endif // SMARTPTR_INC_

    +
    // $Log$
    +// Revision 1.30 2006/05/17 16:04:32 syntheticpp
    +// undo commit 1.29, reject bug: [ 1459838 ]
    Loki::COMRefCounted doesn't call AddRef() on assignment
    +//
    // Revision 1.29 2006/04/05 22:41:43 rich_sposato
    // Fixed bug 1459838 using fix made by Thomas Albrecht.
    (Thanks!)
    // Also added a constructor for NoCheck policy.

     

Log in to post a comment.

MongoDB Logo MongoDB