Discussion:
[omniORB] Memory Leak (CosNaming::NamingContextExt::_narrow)
Mifflin Mabalot
2013-12-10 10:38:58 UTC
Permalink
I think there is a bug on?CosNaming::NamingContextExt::_narrow. ?When an?omniORB::LOCATION_FORWARD happens, the initially allocated object gets orphaned when trying to do a "GIOP::LOCATION_FORWARD -- retry request.." ?I think cleanup of the initially allocated object should be done inside?omni::locationForward()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.omniorb-support.com/pipermail/omniorb-list/attachments/20131210/a10feccd/attachment.html>
Duncan Grisby
2013-12-10 22:48:23 UTC
Permalink
I think there is a bug on CosNaming::NamingContextExt::_narrow. When
an omniORB::LOCATION_FORWARD happens, the initially allocated object
gets orphaned when trying to do a "GIOP::LOCATION_FORWARD -- retry
request.." I think cleanup of the initially allocated object should
be done inside omni::locationForward()
What exactly are the circumstances, and what makes you think there is a
leak?

By design, when an invocation returns with a location forward, omniORB
remembers the original object reference. Then if invocations on the new
location fail, omniORB retries with the original object reference.
That's important for various implementation repository approaches and
for object migration support.

Duncan.
--
-- Duncan Grisby --
-- duncan at grisby.org --
-- http://www.grisby.org --
Mifflin Mabalot
2013-12-11 07:10:52 UTC
Permalink
Hi Duncan,

Then if invocations on the new
location fail, omniORB retries with the original object reference.
That's important for various implementation repository approaches and
for object migration support.
Post by Duncan Grisby
What happens if invocations on the new location succeed? Is the original object reference "deallocated", I think this is what's missing
I am using VC++ VS2010 (omniORB version is 4.1.7 compiled using cygwin using VS10 configurations)
It's probably better to provide code snippets and the trace log, so you can visualize easily:
Code Snippet:
DECLARATIONS:
helloInterface::HelloInt_varm_HelloObj;
CORBA::String_varm_ObjName;
CORBA::Object_varm_ObjContext;
CosNaming::NamingContextExt_varm_RootContext;
CORBA::Object_varm_NSObj;
CORBA::ORB_varm_ORB;

INITIALIZATION snippet:
//initialize ORB
CString lstr_Opt1 = "-ORBInitRef";
CString lstr_NS = "NameService=" + TaskWork.m_CORBAURL;
CString lstr_Opt2 = "-ORBDefaultInitRef";
CString lstr_NSDefault = TaskWork.m_CORBAURL + "#services" ;
//char *lc_argv[] = {lstr_Opt1.GetBuffer(), lstr_NS.GetBuffer(), lstr_Opt2.GetBuffer(), lstr_NSDefault.GetBuffer()} ;
char *lc_argv[] = {lstr_Opt1.GetBuffer(), lstr_NS.GetBuffer()} ;
int li_argc = (int)(sizeof(lc_argv)/sizeof(lc_argv[ 0 ]));

const char* options[][2] = {
{ "traceLevel", "11" },?
{ "traceExceptions", "1" },?
{ "traceInvocationReturns", "1" },?
{ "offerBiDirectionalGIOP", "1" },?
{ "nativeCharCodeSet", "UTF-8" },?
{ NULL, NULL }
? }; ? ?
TaskWork.m_ORB = CORBA::ORB_init(li_argc, lc_argv, "omniORB4", options);
omniORB::installSystemExceptionHandler(NULL,&CTask_CORBAClientDriver::ExceptionHandler);
omniORB::installTransientExceptionHandler(NULL,&CTask_CORBAClientDriver::TransientHandler);
omniORB::installCommFailureExceptionHandler(NULL,&CTask_CORBAClientDriver::CommExceptionHandler);
omniORB::setLogFunction(&CTask_CORBAClientDriver::omniOrbLog);

METHOD snippet:
TaskWork.m_NSObj = TaskWork.m_ORB->resolve_initial_references("NameService");
TaskWork.m_RootContext = CosNaming::NamingContextExt::_narrow(TaskWork.m_NSObj);
if(CORBA::is_nil(TaskWork.m_RootContext)){
CLogOut::OutputCORBALog("Naming Context ERROR");?
} else {
TaskWork.m_ObjContext = TaskWork.m_RootContext->resolve_str(TaskWork.m_ObjName);
//Get and store the remote obj
if (!CORBA::is_nil(TaskWork.m_ObjContext)) {
TaskWork.m_HelloObj = helloInterface::HelloInt::_narrow(TaskWork.m_ObjContext);
if (!CORBA::is_nil(TaskWork.m_HelloObj)) {
Log.Format( "Remote Object Found: %s [%s]", TaskWork.m_CORBAURL, TaskWork.m_CORBAObjName);
CLogOut::OutputCORBALog( Log );
}
}
}

omniORB Tracer log (custom logger set by using:?omniORB::setLogFunction)
[2013/12/10 17:48:47.069] [omniORB TRACE] : omniORB: Creating ref to remote: key<NameService>. target id ? ? ?: IDL:omg.org/CORBA/Object:1.0. most derived id: .
[2013/12/10 17:48:47.069] [omniORB TRACE] : omniORB: Initial reference `NameService' resolved from -ORBInitRef argument / ORB registration..
[2013/12/10 17:48:47.070] [omniORB TRACE] : omniORB: AsyncInvoker: thread id = 1 has started. Total threads = 1.
[2013/12/10 17:48:47.519] [omniORB TRACE] : omniORB: Creating ref to remote: key<???.......B.................RootPOA.....TNameService.................>. target id ? ? ?: IDL:omg.org/CORBA/Object:1.0. most derived id: IDL:omg.org/CosNaming/NamingContextExt:1.0.
[2013/12/10 17:48:47.519] [omniORB TRACE] : omniORB: Finish '_is_a' (location forward).
[2013/12/10 17:48:47.520] [omniORB TRACE] : omniORB: GIOP::LOCATION_FORWARD -- retry request..
[2013/12/10 17:48:47.523] [omniORB TRACE] : omniORB: Return '_is_a' on remote: key<???.......B.................RootPOA.....TNameService.................>.
[2013/12/10 17:48:47.523] [omniORB TRACE] : omniORB: Creating ref to remote: key<???.......B.................RootPOA.....TNameService.................>. target id ? ? ?: IDL:omg.org/CosNaming/NamingContextExt:1.0. most derived id: .
[2013/12/10 17:48:47.524] [omniORB TRACE] : omniORB: Creating ref to remote: key<???.....?.?..............>. target id ? ? ?: IDL:omg.org/CORBA/Object:1.0. most derived id: RMI:helloInterface.HelloInt:0000000000000000.
[2013/12/10 17:48:47.525] [omniORB TRACE] : omniORB: Return 'resolve_str' on remote: key<???.......B.................RootPOA.....TNameService.................>.
[2013/12/10 17:48:47.525] Remote Object Found: corbaname::localhost:1055 [HelloIIOP]
[2013/12/10 17:48:47.525] [omniORB TRACE] : omniORB: LocateRequest to remote: key<???.....?.?..............>.
[2013/12/10 17:48:47.528] [omniORB TRACE] : omniORB: Return 'sayHello' on remote: key<???.....?.?..............>.
[2013/12/10 17:48:47.529] ? ? ?Remote Object Return Value : Hello World
[2013/12/10 17:48:48.414] [omniORB TRACE] : omniORB: Return 'sayHello' on remote: key<???.....?.?..............>.
[2013/12/10 17:48:48.414] ? ? ?Remote Object Return Value : Hello World
[2013/12/10 17:48:49.398] [omniORB TRACE] : omniORB: Return 'sayHello' on remote: key<???.....?.?..............>.
[2013/12/10 17:48:49.398] ? ? ?Remote Object Return Value : Hello World
[2013/12/10 17:48:50.397] [omniORB TRACE] : omniORB: Return 'sayHello' on remote: key<???.....?.?..............>.
[2013/12/10 17:48:50.397] ? ? ?Remote Object Return Value : Hello World
[2013/12/10 17:48:50.668] [omniORB TRACE] : omniORB: Preparing to shutdown ORB..
[2013/12/10 17:48:50.669] [omniORB TRACE] : omniORB: Shutting-down all incoming endpoints..
[2013/12/10 17:48:50.669] [omniORB TRACE] : omniORB: ORB shutdown is complete..
[2013/12/10 17:48:50.669] [omniORB TRACE] : omniORB: Deinitialising omniDynamic library..
[2013/12/10 17:48:50.670] [omniORB TRACE] : omniORB: AsyncInvoker: thread id = 1 has exited. Total threads = 1.
[2013/12/10 17:48:50.670] [omniORB TRACE] : omniORB: AsyncInvoker: deleted..
[2013/12/10 17:48:50.670] CORBA Object Closed...
[2013/12/10 17:48:50.670] ORB Destroyed...

Visual Studio 2010 partial output log indicating the leak:
Detected memory leaks!
Dumping objects ->
{55607} normal block at 0x00B1E300, 100 bytes long.
?Data: <@?>[ Ww ? ? ? ? > 40 C6 3E 5B 20 57 77 00 FF FF FF FF 00 00 00 00?
Object dump complete.

Other notes:
Whenever a remote object is referenced, that too is causing leaks, but I found a way to cleanup the leaks by incorporating some extra code, see below (maybe the "allocation for every reference" is by design and is included in the CORBA specs, but I used a _var (smart pointer) which has been discussed as "self-cleaning / self-deallocating" during destruction, yet it is leaving behind leaks)
? CString* lClientRequest = (CString*)RecvParam.m_pPtr;?
if (!TaskWork.m_ORB->_NP_is_nil() && !TaskWork.m_ORB->_non_existent() && !TaskWork.m_HelloObj->_is_nil()) {
// Get the object's "storage location" so you can free it later (every time it is "referenced" a new allocation is made)
CORBA::WStringValue* l_sayHelloPtr = TaskWork.m_HelloObj->sayHello();
// Process all you want
*lClientRequest = l_sayHelloPtr->_boxed_out();
CString Log;
Log.Format( " ? ? Remote Object Return Value : %s", *lClientRequest);
CLogOut::OutputCORBALog( Log );
// Cleanup to avoid leaks (this simply releases a reference, so that the object can clean/deallocate itself)
CORBA::WStringValue_Helper::remove_ref(l_sayHelloPtr); // >> NOT DOING THIS WILL CAUSE LEAKS
}

If you need anything else please let me know. ?Hope you can shed light on what am I doing wrong, or if indeed this is a bug (we can currently tolerate this as it is just causing a 100-byte leak, but leak is a leak, we want code which 100% clean). ?Thanks!

Regards,
Miff
Post by Duncan Grisby
I think there is a bug on CosNaming::NamingContextExt::_narrow.? When
an omniORB::LOCATION_FORWARD happens, the initially allocated object
gets orphaned when trying to do a "GIOP::LOCATION_FORWARD -- retry
request.."? I think cleanup of the initially allocated object should
be done inside omni::locationForward()
What exactly are the circumstances, and what makes you think there is a
leak?
By design, when an invocation returns with a location forward, omniORB
remembers the original object reference. Then if invocations on the new
location fail, omniORB retries with the original object reference.
That's important for various implementation repository approaches and
for object migration support.
Duncan.
--
-- Duncan Grisby? ? ? ? --
? -- duncan at grisby.org? ? --
? -- http://www.grisby.org
--
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.omniorb-support.com/pipermail/omniorb-list/attachments/20131211/a76458a0/attachment-0001.html>
Duncan Grisby
2013-12-11 11:50:56 UTC
Permalink
Post by Duncan Grisby
Then if invocations on the new
location fail, omniORB retries with the original object reference.
That's important for various implementation repository approaches and
for object migration support.
What happens if invocations on the new location succeed? Is the
original object reference "deallocated", I think this is what's
missing
The original object reference is kept for as long as the application
code holds on to the object reference. The forwarded reference can fail
at any time, and if it does it reverts back to the original location.

[...]
Post by Duncan Grisby
Whenever a remote object is referenced, that too is causing leaks, but
I found a way to cleanup the leaks by incorporating some extra code,
see below (maybe the "allocation for every reference" is by design and
is included in the CORBA specs, but I used a _var (smart pointer)
which has been discussed as "self-cleaning / self-deallocating" during
destruction, yet it is leaving behind leaks)
[...]
Post by Duncan Grisby
CORBA::WStringValue* l_sayHelloPtr = TaskWork.m_HelloObj->sayHello();
You are responsible for releasing the WStringValue pointer. It's a leak
in your code, not in omniORB, if you don't release it.

[...]
Post by Duncan Grisby
// Cleanup to avoid leaks (this simply releases a reference, so that
the object can clean/deallocate itself)
CORBA::WStringValue_Helper::remove_ref(l_sayHelloPtr); // >> NOT DOING
THIS WILL CAUSE LEAKS
}
This is a non-standard way to release the pointer. You should call
_remove_ref directly:

l_sayHelloPtr->_remove_ref();

Or, probably better, use a _var that automatically calls _remove_ref
when it goes out of scope:

CORBA::WstringValue_var l_sayHelloPtr = ...
--
-- Duncan Grisby --
-- duncan at grisby.org --
-- http://www.grisby.org --
Mifflin Mabalot
2013-12-11 13:23:52 UTC
Permalink
Hi Duncan,
The original object reference is kept for as long as the application
code holds on to the object reference. The forwarded reference can fail
at any time, and if it does it reverts back to the original location.
Post by Mifflin Mabalot
CORBA::WStringValue* l_sayHelloPtr = TaskWork.m_HelloObj->sayHello();
You are responsible for releasing the WStringValue pointer. It's a leak
in your code, not in omniORB, if you don't release it.
module helloInterface {
? ? interface HelloInt {
? ? ? ? ::CORBA::WStringValue sayHello( );? ??
? ? };
#pragma ID HelloInt "RMI:helloInterface.HelloInt:0000000000000000"
};
When I compiled the IDL using omniidl, it produced the C++ header and implementation files containing this:
? ? CORBA::WStringValue* sayHello();
At first I was not expecting (DID NOT NOTICE) sayHello() would return a pointer since the method signature in the IDL file does not (or maybe this is my fault for not reading the CORBA specs)...I just came to realize when I eventually noticed that the return value is a pointer...that sayHello() method was probably doing some internal allocations. ?I am just wondering though, if you take a look at the declaration, I declared a _var object (m_HelloObj)..but the sayHello method (which is a member of the object m_HelloObj) isn't doing an automatic cleanup. ?In short, the _var object itself is automatically cleaning up it's allocations, but not allocations made by its member methods.
For a first time orb user like me, these two would look the same:
Version 1:
CORBA::WStringValue_var l_sayHello = TaskWork.m_HelloObj->sayHello();
*lClientRequest = l_sayHello->_boxed_out();

Version 2:
*lClientRequest = TaskWork.m_HelloObj->sayHello()->_boxed_out();


...but they don't perform the same, Version 1 doesn't cause leaks, Version 2 does. ?(Keep in mind m_HelloObj is declared as _var, so I was expecting that anything the object allocates, even those allocated through it's member methods, would automatically be deallocated upon destruction).

Or, probably better, use a _var that automatically calls _remove_ref
Post by Mifflin Mabalot
Thank you for this, I never thought of doing that because I was expecting something like Version 2 would work just fine without any leaks.
But going back to the original problem, why is this causing a leak when all objects are declared as _var?
m_NSObj = m_ORB->resolve_initial_references("NameService");
m_RootContext = CosNaming::NamingContextExt::_narrow(m_NSObj);
Post by Mifflin Mabalot
I think the LOCATION_FORWARD exception has something to do with this (upon "changing" location and retrying to resolve). ?I am still setting up my test environment so that no LOCATION_FORWARD exception will occur (or is this inevitable?, any suggestions on how to if not?) and see if it does not leak. ?I am using the "native" JAVA orb for the other end/server-side (both persistent and transient).
Thank you and I hope you stay with me to resolve this issue :) ...appreciate it!

Regards,
Miff
Post by Mifflin Mabalot
Then if invocations on the new
location fail, omniORB retries with the original object reference.
That's important for various implementation repository approaches and
for object migration support.
What happens if invocations on the new location succeed? Is the
original object reference "deallocated", I think this is what's
missing
The original object reference is kept for as long as the application
code holds on to the object reference. The forwarded reference can fail
at any time, and if it does it reverts back to the original location.
[...]
Whenever a remote object is referenced, that too is causing leaks, but
I found a way to cleanup the leaks by incorporating some extra code,
see below (maybe the "allocation for every reference" is by design and
is included in the CORBA specs, but I used a _var (smart pointer)
which has been discussed as "self-cleaning / self-deallocating" during
destruction, yet it is leaving behind leaks)
[...]
CORBA::WStringValue* l_sayHelloPtr = TaskWork.m_HelloObj->sayHello();
You are responsible for releasing the WStringValue pointer. It's a leak
in your code, not in omniORB, if you don't release it.
[...]
// Cleanup to avoid leaks (this simply releases a reference, so that
the object can clean/deallocate itself)
CORBA::WStringValue_Helper::remove_ref(l_sayHelloPtr); // >> NOT DOING
THIS WILL CAUSE LEAKS
}
This is a non-standard way to release the pointer. You should call
? l_sayHelloPtr->_remove_ref();
Or, probably better, use a _var that automatically calls _remove_ref
? CORBA::WstringValue_var l_sayHelloPtr = ...
? ? ? ?
--
-- Duncan Grisby? ? ? ? --
? -- duncan at grisby.org? ? --
? -- http://www.grisby.org --
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.omniorb-support.com/pipermail/omniorb-list/attachments/20131211/67e3ca09/attachment.html>
Duncan Grisby
2013-12-20 18:02:43 UTC
Permalink
On Wed, 2013-12-11 at 21:23 +0800, Mifflin Mabalot wrote:

[...]
Post by Mifflin Mabalot
module helloInterface {
interface HelloInt {
::CORBA::WStringValue sayHello( );
};
#pragma ID HelloInt "RMI:helloInterface.HelloInt:0000000000000000"
};
When I compiled the IDL using omniidl, it produced the C++ header and
CORBA::WStringValue* sayHello();
At first I was not expecting (DID NOT NOTICE) sayHello() would return
a pointer since the method signature in the IDL file does not (or
maybe this is my fault for not reading the CORBA specs)...
You really really have to understand the C++ mapping. It's horrible and
ugly, and has complex memory management rules. If you don't understand
the rules, you will get it wrong and your code will leak or, worse,
crash.
Post by Mifflin Mabalot
I just came to realize when I eventually noticed that the return value
is a pointer...that sayHello() method was probably doing some internal
allocations. I am just wondering though, if you take a look at the
declaration, I declared a _var object (m_HelloObj)..but the sayHello
method (which is a member of the object m_HelloObj) isn't doing an
automatic cleanup. In short, the _var object itself is automatically
cleaning up it's allocations, but not allocations made by its member
methods.
Yes, the object reference _var type (HelloInt_var) looks after ownership
of the object reference. It does not have any bearing at all on
ownership of values returned from methods on the object.
Post by Mifflin Mabalot
CORBA::WStringValue_var l_sayHello = TaskWork.m_HelloObj->sayHello();
*lClientRequest = l_sayHello->_boxed_out();
*lClientRequest = TaskWork.m_HelloObj->sayHello()->_boxed_out();
...but they don't perform the same, Version 1 doesn't cause leaks,
Version 2 does.
That is correct. It's awkward, but those are the rules of the standard
CORBA C++ mapping.

[...]
Post by Mifflin Mabalot
But going back to the original problem, why is this causing a leak
when all objects are declared as _var?
m_NSObj = m_ORB->resolve_initial_references("NameService");
m_RootContext = CosNaming::NamingContextExt::_narrow(m_NSObj);
If those really are both _var types, then I'm sure it is not actually
leaking.
Post by Mifflin Mabalot
I think the LOCATION_FORWARD exception has something to do with
this (upon "changing" location and retrying to resolve).
No, the LOCATION_FORWARD will not cause it to leak. For as long as the
object reference is alive (which because it's an initial reference is
likely to be for the whole lifetime of the process), it will have
storage for both the original location and the forwarded location, but
that's not a leak.

Duncan.
--
-- Duncan Grisby --
-- duncan at grisby.org --
-- http://www.grisby.org --
Mifflin Mabalot
2013-12-21 21:51:59 UTC
Permalink
Hi Duncan,

Thank you for all your reply.

If those really are both _var types, then I'm sure it is not actually
leaking.
Post by Duncan Grisby
I think I just have to trust you on this for now, even though VS is reporting it as a leak (yeah at times Microsoft's?debugger reports the weirdest things unlike any other).? Got to get some serious reading on the CORBA C++ mapping.? Thank you and more power. Merry Christmas!
Regards,
Miff
Post by Duncan Grisby
[...]
module helloInterface {
? ? interface HelloInt {
? ? ? ? ::CORBA::WStringValue sayHello( );? ?
? ? };
#pragma ID HelloInt "RMI:helloInterface.HelloInt:0000000000000000"
};
When I compiled the IDL using omniidl, it produced the C++ header and
? ? CORBA::WStringValue* sayHello();
At first I was not expecting (DID NOT NOTICE) sayHello() would return
a pointer since the method signature in the IDL file does not (or
maybe this is my fault for not reading the CORBA specs)...
You really really have to understand the C++ mapping. It's horrible and
ugly, and has complex memory management rules. If you don't understand
the rules, you will get it wrong and your code will leak or, worse,
crash.
I just came to realize when I eventually noticed that the return value
is a pointer...that sayHello() method was probably doing some internal
allocations.? I am just wondering though, if you take a look at the
declaration, I declared a _var object (m_HelloObj)..but the sayHello
method (which is a member of the object m_HelloObj) isn't doing an
automatic cleanup.? In short, the _var object itself is automatically
cleaning up it's allocations, but not allocations made by its member
methods.
Yes, the object reference _var type (HelloInt_var) looks after ownership
of the object reference. It does not have any bearing at all on
ownership of values returned from methods on the object.
CORBA::WStringValue_var l_sayHello = TaskWork.m_HelloObj->sayHello();
*lClientRequest = l_sayHello->_boxed_out();
*lClientRequest = TaskWork.m_HelloObj->sayHello()->_boxed_out();
...but they don't perform the same, Version 1 doesn't cause leaks,
Version 2 does.
That is correct. It's awkward, but those are the rules of the standard
CORBA C++ mapping.
[...]
But going back to the original problem, why is this causing a leak
when all objects are declared as _var?
m_NSObj = m_ORB->resolve_initial_references("NameService");
m_RootContext = CosNaming::NamingContextExt::_narrow(m_NSObj);
If those really are both _var types, then I'm sure it is not actually
leaking.
I think the LOCATION_FORWARD exception has something to do with
this (upon "changing" location and retrying to resolve).
No, the LOCATION_FORWARD will not cause it to leak. For as long as the
object reference is alive (which because it's an initial reference is
likely to be for the whole lifetime of the process), it will have
storage for both the original location and the forwarded location, but
that's not a leak.
Duncan.
--
-- Duncan Grisby? ? ? ? --
? -- duncan at grisby.org? ? --
? -- http://www.grisby.org/--
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.omniorb-support.com/pipermail/omniorb-list/attachments/20131222/86265aff/attachment.html>
Loading...