[LLVMbugs] [Bug 8678] New: Destructors are not called for C++ temp objects that are created when C++ objects are copied via ObjC dot syntax

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Wed Nov 24 04:44:39 CST 2010


http://llvm.org/bugs/show_bug.cgi?id=8678

           Summary: Destructors are not called for C++ temp objects that
                    are created when C++ objects are copied via ObjC dot
                    syntax
           Product: clang
           Version: trunk
          Platform: Macintosh
        OS/Version: MacOS X
            Status: NEW
          Severity: normal
          Priority: P
         Component: -New Bugs
        AssignedTo: unassignedclangbugs at nondot.org
        ReportedBy: lgerbarg at gmail.com
                CC: llvmbugs at cs.uiuc.edu


While tracing down a a ref leak with C++ shared_ptrs I found a situation where
the shared_ptr's destructor was not being called, which was artificially
increasing the ref count of the object and preventing its deletion. Below is a
reduced case that demonstrates the problem and two workaround. The bug only
occurs using ObjC dot syntax, if you use the getter via bracket syntax
everything works as expected.

#include <Foundation/Foundation.h>

#include <tr1/memory>
#include <stdio.h>

class CXXClass {
private:
  unsigned long identity;
public:
  CXXClass(short I) : identity(I) {
    printf("Constructing: %lu\n", identity);
  }

  ~CXXClass(void) {
    printf("Destructing: %lu\n", identity);
  }

  unsigned long getIdentity(void) { return identity; }
};

@interface OBJCClass : NSObject {
  std::tr1::shared_ptr<CXXClass> cxxClass;
}

@property (nonatomic) std::tr1::shared_ptr<CXXClass> cxxClass;
@end

@implementation OBJCClass
@end

int main (void) {
  OBJCClass *test1 = [[OBJCClass alloc] init];
  OBJCClass *test2 = [[OBJCClass alloc] init];
  OBJCClass *test3 = [[OBJCClass alloc] init];
  OBJCClass *test4 = [[OBJCClass alloc] init];

  test1.cxxClass = std::tr1::shared_ptr<CXXClass>(new CXXClass(1));
  test2.cxxClass = std::tr1::shared_ptr<CXXClass>(new CXXClass(2));
  test3.cxxClass = std::tr1::shared_ptr<CXXClass>(new CXXClass(3));
  test4.cxxClass = std::tr1::shared_ptr<CXXClass>(new CXXClass(4));

  printf("Purposefully ignoring id 1 as a control group\n");

  //BUG
  //The property accessor copies cxxClass into a temp variable that is not
registered for cleanup
  //Therefore the shared_ptr destructor is never called, and we leak the
CXXClass pointed to by
  //test2.cxxClass
  printf("Reading id %lu\n", test2.cxxClass->getIdentity());

  //Workaround 1
  //If you use normal ObjC message syntax instead of dot accessors everything
works correctly
  printf("Reading id %lu\n", [test3 cxxClass]->getIdentity());

  //Workaround 2
  //If we explicitly assign the object to a name it will work fine
  std::tr1::shared_ptr<CXXClass> temp = test4.cxxClass;
  printf("Reading id %lu\n", temp->getIdentity());

  //Control group, destructor called
  [test1 release];

  //Bugged version, destructor not called
  [test2 release];

  //Workaround 1 (destructor called later, at scope collapse);
  [test3 release];

  //Workaround 2 (destructor called later, at scope collapse);
  [test4 release];

  return 0;
}

-- 
Configure bugmail: http://llvm.org/bugs/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


More information about the LLVMbugs mailing list