CL/cl.hpp: Problems with reference counting

In CL/cl.hpp, line 1222, there is a constructor Wrapper::Wrapper(const cl_type &obj) that is used to wrap a C-style object into a C++ style object. Unlike the copy constructor, it does not call retain(). However, the destructor always calls release() for non-null objects. This asymmetry leads to subtile bugs that causes random crashes for which the culprit is hard to find.

Consider for example, a function like:

void eventCompleteCallBack(cl_event ev, cl_int status, void *arg)
{
  cl::Event event(ev); // wrap C-style object into C++ style object

  ... // use event as C++-style object

  // destructor of cl::Event calls release() while retain() was never invoked
}

The fact that event callback functions return a cl_event instead of a cl::Event is already not really elegant, but the obvious solution to wrap the cl_event object into a cl::Event as done above silently corrupts memory, as the destructor of cl::Event implicitly calls release() while retain() was never invoked.

Likewise, Wrapper<cl_type>& operator = (const cl_type &rhs) does not call retain().

I realise that simply adding “if (object_ != NULL) { retain(); }” causes other problems, as some of the internal code within cl.hpp seems to rely on this behavior, but I would be happy if this unexpected behavior could be fixed in the next release of CL/cl.hpp.

Looking at the OpenCL 1.0 specs, I see that every function that returns a cl_event is also supposed to perform an implicit retain() on that event. If the wrapper’s constructor performed another retain then the reference count would go to 2 for that event. Upon deleting the cl::Event object, the release() would decrement the reference count, bringing it to 1. It would not reach 0 though, so the event would never be deleted by the OpenCL implementation. That seems to be the behaviour defined in the specs for all objects generated by OpenCL.