Bug 1521

Summary: Demarshalling error in Real Time Event Service for small events
Product: TAO Reporter: srottoo
Component: Real-Time Event ServiceAssignee: DOC Center Support List (internal) <tao-support>
Status: ASSIGNED ---    
Severity: normal    
Priority: P3    
Version: 1.3.1   
Hardware: All   
OS: All   

Description srottoo 2003-06-02 07:51:39 CDT
If the example for Custom Marshal in $ACE_ROOT/orbsvcs/tests/EC_Custom_Marshal
is run with the default parameters for the supplier ,the consumer receives the
events as pushed by the supplier. By default the event size is 32. However
reducing the event_size to say 10 causes the consumer to print out a "No Data in
event" error message. 

    DESCRIPTION: 
Small-size events are not demarshalled correctly in the
rtecdefaulteventdatac.cpp file. This is the cause of the bug that causes a "no
data in event" error in the Custom Marshal example when -b < 27. 

The test that fails in the example is: 

      if (e.data.payload.mb () == 0) 
          ACE_DEBUG ((LM_DEBUG, "No data in event[%d]\n", i)); 

This happens for small events because the message block into which the data is
placed is processed differently for large events.

There are two cases when an event is received 

1. The event is small enough so that the whole message is read in one go. 
2. The event is too big and another read needs to be performed to get  the message. 

Eventually the following demarshalling code is executed at the following method
in rtecdefaulteventdatac.cpp 

CORBA::Boolean operator>> ( 
    TAO_InputCDR &strm, 
    EventPayload &_tao_sequence 
  ) 
{ 
<snip> 

      if (ACE_BIT_DISABLED (strm.start ()->flags (), 
      ACE_Message_Block::DONT_DELETE)) 
      { 
        TAO_ORB_Core* orb_core = strm.orb_core (); 
        if (orb_core != 0 && 
        strm.orb_core ()->resource_factory ()-> 
        input_cdr_allocator_type_locked () == 1) 
        { 
          TAO_Unbounded_Sequence<CORBA::Octet> *oseq = 
            ACE_static_cast(TAO_Unbounded_Sequence<CORBA::Octet>*, &_tao_sequence); 
          oseq->replace (_tao_seq_len, strm.start ()); 
          oseq->mb ()->wr_ptr (oseq->mb()->rd_ptr () + _tao_seq_len); 
          strm.skip_bytes (_tao_seq_len); 
          return 1; 
        } 
      } 
        return strm.read_octet_array (_tao_sequence.get_buffer (), _tao_seq_len); 

In the case where the event is not obtained in one read the DONT_DELETE bit of
the strm start message block 
is set to 0 and the if part of the code is executed. This has the effect of 
replacing the buffer in _tao_sequence with an ACE_Message_Block which sets the
mb_ field in _tao_sequence appropriately and everything works fine.

However if the event is small enough to be read in one go, the DONT_DELETE bit
stays at 
1 and the if part of the code is not executed. Instead the
strm.read_octet_array() code is executed. However this code does NOT set the mb_
field. Instead it allocates a buffer of octets and only the buffer_ field is
set. The result is that when the client tries to access the data from the mb()
method the latter will return a value of 0 hence the "No data in event" message.

To see why the DONT_DELETE flags are different here is the relevant part of the
call stack when an event is received. This is the call stack when a big event is
received and which will clear the flag. 

        C++ 
        TAOd.dll!TAO_GIOP_Message_Base::process_request_message(TAO_Transport *
transport=0x00eaf9e0, TAO_Queued_Data * qd=0x0012f564)  Line 685 + 0x1e C++

        TAOd.dll!TAO_Transport::process_parsed_messages(TAO_Queued_Data *
qd=0x0012f564, TAO_Resume_Handle & rh={...})  Line 1950 + 0x33        C++

        TAOd.dll!TAO_Transport::consolidate_message(ACE_Message_Block &
incoming={...}, int missing_data=0, TAO_Resume_Handle & rh={...}, ACE_Time_Value
* max_wait_time=0x00000000)  Line 1639 C++

        TAOd.dll!TAO_Transport::parse_consolidate_messages(ACE_Message_Block &
block={...}, TAO_Resume_Handle & rh={...}, ACE_Time_Value *
max_wait_time=0x00000000)  Line 1452 + 0x1b  C++

        TAOd.dll!TAO_Transport::handle_input_i(TAO_Resume_Handle & rh={...},
ACE_Time_Value * max_wait_time=0x00000000, int __formal=0)  Line 1386 + 0x17   
   C++

  
As we can see the consolidate_message method is called. This method calls 

  // Grow the buffer to the size of the message 
  ACE_CDR::grow (&incoming, 
                 payload); 

which clears the DONT_DELETE bit  in the incoming message block's flag. 



However in the case of a small event, consolidate_message is not called and the
flags stays at 1 causing the problem described above.

    REPEAT BY: 
[What you did to get the error; include test program or session 
transcript if at all possible.  ] 

    SAMPLE FIX/WORKAROUND: 
One fix is to remove the if check so that the if part of the code is always
executed. I did this and it works. 

The other way is to change the TAO_Unbounded_Sequence<CORBA::Octet> class so
that only ACE_Message_Blocks are used to store the data. Right now message
blocks are only used if the replace method of the class is called but that may
be by design.

Yet another way would be to clear the DONT_DELETE flag event explicitly in all
cases. However that has implications in terms of ownership. 

It looks to me that the problem is in the TAO_Unbounded_Sequence<CORBA_Octet>
class which should always use message blocks instead of using them only
when the replace method is called.
Comment 1 Johnny Willemsen 2003-06-02 07:52:55 CDT
Accepting this bug
Comment 2 Johnny Willemsen 2003-12-21 06:57:53 CST
We should also make sure that the test is changed so that such kind of error 
is detected by our regression tests.
Comment 3 Johnny Willemsen 2004-05-10 13:51:12 CDT
Set it to tao-support, no time at this moment to fix this.
Comment 4 Ossama Othman 2004-06-08 23:52:19 CDT
Accepted on behalf of tao-support.