Coding advice to prevent client interceptor memory leaks (MLKs reported by Purify)

From Support
Jump to: navigation, search

Question:

Purify reports memory leaks in VBC++ stub creation routines (VISTypeInfo::createStub , VISStubInfo::bind). These leaks are associated with calls to _bind(), string_to_object(), or triggers received for an application trigger handler.

MLK: 3328 bytes leaked in 16 blocks * This memory was allocated from: malloc [rtlib.o] __nW__fUl [libCsup.2] operator new(unsigned long) [rtlib.o] VISStubInfo::VISStubInfo(CORBA_Object *) [liborb_r.sl] CORBA_Object::CORBA_Object(const char *,unsigned char)%2

[liborb_r.sl] myAPI::myApp::myTYpe(const char *)%1 [my_c.o] static myAPI::myApp::_factory() [my_c.C:525] VISTypeInfo::createStub() [liborb_r.sl] static VISUtil::convert(const IOP::IOR &,const CORBA_TypeInfo static VISUtil::convert(const IOP::IOR &,const CORBA_TypeInfo VISORB::string_to_object(const char *) [liborb_r.sl] AgentImpl::_objectFromRegisteredName(const DSName &)

[liborb_r.sl] VISTriggerHandler::trigger(const DSProvider &) [liborb_r.sl] DSUser::triggerService(DSReply *) [liborb_r.sl] DSUser::receiveReply(DSReply *) [liborb_r.sl] DSUser::inputReady(int) [liborb_r.sl] dpDispatcher::notify(int,dpFdMask &,dpFdMask &,dpFdMask &) dpDispatcher::dispatch(timeval *) [liborb_r.sl] dpDispatcher::dispatch() [liborb_r.sl] DSUser::begin() [liborb_r.sl] static VISThread::_start(void *) [liborb_r.sl] __pthread_create_system [libpthread.1] * Block of 208 bytes (16 times); last block at 0x4044cae0

MLK: 2893 bytes leaked in 32 blocks * This memory was allocated from: malloc [rtlib.o] __nWa__FuL [libCsup.2] __nwa(unsigned long) [rtlib.o] CORBA_OctetSequence::operator =(const CORBA_OctetSequence &) IOP::TaggedProfileSequence::operator =(const

IOP::TaggedProfileSequence VISStubInfo::bind(const IOP::IOR &,unsigned char)

[liborb_r.sl] static VISUtil::convert(const IOP::IOR &,const CORBA_TypeInfo static VISUtil::convert(const IOP::IOR &,const CORBA_TypeInfo VISORB::string_to_object(const char *) [liborb_r.sl] AgentImpl::_objectFromRegisteredName(const DSName &)

[liborb_r.sl] VISTriggerHandler::trigger(const DSProvider &) [liborb_r.sl] DSUser::triggerService(DSReply *) [liborb_r.sl] DSUser::receiveReply(DSReply *) [liborb_r.sl] DSUser::inputReady(int) [liborb_r.sl] dpDispatcher::notify(int,dpFdMask &,dpFdMask &,dpFdMask &) dpDispatcher::dispatch(timeval *) [liborb_r.sl] dpDispatcher::dispatch() [liborb_r.sl] DSUser::begin() [liborb_r.sl] static VISThread::_start(void *) [liborb_r.sl] __pthread_create_system [libpthread.1]

Answer:

If the application uses interceptors, and the leak appear to related to calls to _bind(), string_to_object(), or triggers being fired to an application trigger handler, then the cause may be due to the installed interceptor code.

It is common for a client interceptor to access the target object associated with the interceptor. The preferred approach is to use the protected _target member variable already available to the interceptor.

An alternative that is sometimes used by applications is to pass the Object_ptr from the interceptor factory create() method into the constructor of the interceptor for later use by the interceptor. Special care must be taken if this is done. If the Object_ptr is to be passed to and held by the interceptor code then it is important to follow these rules:

1) Store the object into an Object_ptr

2) Do not _duplicate the reference

These rules are contrary to common practice but are correct in this situation.

The reason has to do with the fact that the stub for the object contains reference to the interceptor. The interceptor is released when the destructor for the stub is executed. If the interceptor holds the reference and increments the ref count then the circularity prevents the stub from ever being released. This is a special case that applies only when an interceptor holds a reference to the object stub.

For example this code will not introduce a memory leak:

class SampleClientInterceptor : public VISClientInterceptor { public: CORBA::Object_ptr _obj; SampleClientInterceptor(CORBA::Object_ptr obj) : VISClientInterceptor(obj) { _obj = obj; } ...

This code leads to a memory leak: class SampleClientInterceptor : public VISClientInterceptor { public: CORBA::Object_ptr _obj; SampleClientInterceptor(CORBA::Object_ptr obj) : VISClientInterceptor(obj) { _obj = CORBA::Object::_duplicate(obj); } ...

This code leads to a memory leak: class SampleClientInterceptor : public VISClientInterceptor { public: CORBA::Object_var _obj; SampleClientInterceptor(CORBA::Object_ptr obj) : VISClientInterceptor(obj) { _obj = CORBA::Object::_duplicate(obj); } ...

This code leads to many FMR/FMW/FUM errors, but no memory leaks: class SampleClientInterceptor : public VISClientInterceptor { public: CORBA::Object_var _obj; SampleClientInterceptor(CORBA::Object_ptr obj) : VISClientInterceptor(obj) { _obj = obj; } ...

Article originally contributed by Jimmy Maher