[omniORB] sequence_var return passing

Poilpret Jean Francois jfpoilpret@hn.vnn.vn
Sat, 11 Sep 1999 09:05:10 +0700


Hello Tom,

the behavior you describe seems normal, because you misunderstood the =
usage of "T_var" types. You should remember that T_var is not a T, but =
rather behaves like a T*. Moreover, to give meaning to a T_var, you have =
to give it a pointer to T that YOU already allocated.
In your example, you use your octetSequence_var as if it was an =
octetSequence ! Particularly, you misused its constructor. The only =
constructors existing for T_var types are T_var() (default constructor: =
doesn't own any pointer to T yet), T_var(T*) (takes ownership of an =
already existing already allocated pointer to T), and T_var(const =
T_var&) (which duplicates -ie, allocates a copy- the T variables holded =
by the argument T_var and takes ownership of this duplicate).
In your sample code, the line:
     octetSequence_var dummy(0);
calls the following constructor: octetSequence_var(octetSequence*)
telling it that your var is the owner of a null pointer ! (ie, not of an =
already allocated sequence of max size 0, as you may think).
After this, when you return with dummy._retn(), the ownership of your =
null pointer to sequence is given to the calling ORB, which will delete =
it later. delete null is not a problem (according to C++ spec, delete 0 =
does nothing).
BUT BEFORE arriving to the delete line of code in the ORB, the ORB will =
already have taken for granted that the pointer to octetSequence is =
valid (ie, not garbage, nor NULL). When the ORB will try to marshall it =
it will certainly core-dump.
The CORBA specification is very clear about the mapping to the ORB (in =
C++ at least, I don't know much about the other mappings): you should =
NEVER pass a null pointer to the ORB.
As stated in section 1.22 (Parameter passing considerations), page 1-102 =
of the latest "C++ Language Mapping Specification" as of June 1999, from =
the OMG :

<<
"For parameters that are passed or returned as a pointer (T*) or =
reference to pointer
"(T*&), except for valuetypes, a compliant program is not allowed to =
pass or return a
"null pointer; the result of doing so is undefined. In particular, a =
caller may not pass a
"null pointer under any of the following circumstances:
"=95 in and inout string
"=95 in and inout array (pointer to first element)
"A caller may pass a reference to a pointer with a null value for out =
parameters,
"however, since the callee does not examine the value but rather just =
overwrites it.
"Furthermore, conforming applications may also pass and return null =
pointers for all
"valuetype parameters and return types, and may embed null valuetype =
pointers
"within constructed types that are passed as parameters or return =
values, such as structs,
"unions, arrays, sequences, Any, and other valuetypes. A callee may not =
return a null
"pointer under any of the following circumstances:
"=95 out and return variable-length struct
"=95 out and return variable-length union
"=95 out and return string
"=95 out and return sequence
"=95 out and return variable-length array, return fixed-length array
"=95 out and return any
"Since OMG IDL has no concept of pointers in general or null pointers in =
particular,
"except for valuetypes, allowing the passage of null pointers to or from =
an operation
"would project C++ semantics onto OMG IDL operations.17 A compliant
"implementation is allowed but not required to raise a BAD_PARAM =
exception if it
"detects such an error.
" =20

Now here is one way you could have written your code
------
wib_i.cc:

#include "wib.hh"

class wib_i : public virtual _sk_wib{
public:
  wib_i(){}
  virtual ~wib_i(){}
  virtual octetSequence * fib(){
     // allocate a new sequence with max items=3D0
     // NB: it will have length =3D 0 by default
     octetSequence* dummy =3D new octetSequence(0);
     return dummy;}
};
------

You may also user T_var types (in case your code may throw exceptions)
------
wib_i.cc:

#include "wib.hh"

class wib_i : public virtual _sk_wib{
public:
  wib_i(){}
  virtual ~wib_i(){}
  virtual octetSequence * fib(){
     // allocate a new sequence with max items=3D0
     // NB: it will have length =3D 0 by default
     octetSequence_var dummy =3D new octetSequence(0);
     // here do some stuff that may throw exceptions
     //...
     // return a pointer to octetSequence
     // we use _retn() so as to release ownership of pointer from T_var =
(ie, do not have T_var=20
     // automatically release its pointer just after the return =
statement
     return dummy._retn();}
};
------

Now a few words about why your code works with collocated client and =
implementation. In this case, the ORB doen't do anything on your =
arguments (no marshalling needed), these are directly passed between =
caller and callee, thus when calling objref->fib() it gets a null =
pointer, puts it in a T_var whill will deallocate it further (at the end =
of scope), but as I already told, delete 0 does not hurt.

What is really important here is to understand WHEN arguments (and =
return values) are passed by value, pointer, or even reference to =
pointer, according to direction of parameter (in, out, inout, return =
value) and according to its type (basic, complex, fixed-sized, =
variable-sized).
I think you should read the C++ Mapping specification about this, or =
better (for those people like me who cannot read more than 5 pages of =
spec without getting headache ;-) read the great book by Henning and =
Vinoski (Advanced CORBA Programming with C++, Addison-Wesley).

And don't forget to differentiate type T, T_ptr and T_var, this is one =
of the key foundations of the C++ mapping !

I hope that I was clear, that I did not make any mistakes in my =
explanation, and that this will help.

    Jean-Francois

-----Original Message-----
From: Tom Kelly <thomas.kelly@queens.oxford.ac.uk>
To: omniorb-list@uk.research.att.com <omniorb-list@uk.research.att.com>
Date: samedi 11 septembre 1999 04:47
Subject: [omniORB] sequence_var return passing


>
>I have a problem sending a zero length sequence of octets through a =
return
>type. Consider the following source as a testcase:
>
>wib.idl:
>
>typedef sequence<octet> octetSequence;
>
>interface wib{
>  octetSequence fib();
>};
>
>------
>
>wib_i.cc:
>
>#include "wib.hh"
>
>class wib_i : public virtual _sk_wib{
>public:
>  wib_i(){}
>  virtual ~wib_i(){}
>  virtual octetSequence * fib(){
> octetSequence_var dummy(0);=20
> return dummy._retn();}
>};
>
>------
>
>If I now have on the client side:
>octetSequence_var dummy(0);
>wib_var objref =3D ... // get object reference somehow
>dummy =3D objref->fib();
>
>This causes the server to die with a segmentation fault.=20
>Collocating the client and server solves the problem.=20
>Am I allowed to pass back a zero length (is that the same as null)
>sequence of octets?=20
>
>Thanks in advance,
>Tom
>
>p.s. platform: Redhat 6.0 with errata patches on i686 and =
omniORB2.8pre2
>
>