Consumer application crashed in RFA_String::set() when processing a refresh message

My consumer application bases on Consumer example in RFA package. Last week, it crashed with the following call stack.

rfa::common::RFA_String::set(char const*, unsigned int, bool) () 
rfa::common::RFA_String::RFA_String(rfa::common::RFA_String const&, rfa::common::RFA_String const&) ()
rfa::common::operator+(rfa::common::RFA_String const&, rfa::common::RFA_String const&) ()
MarketPriceClient::displayServiceAndItemName (this=…, respMsg=..., cacheItem=..., temp=...)
MarketPriceClient::processRefreshRespMsg (this=…, respMsg=..., cacheItem=..., temp=...)
MarketPriceClient::processEvent (this=…, event=...) rfa::common::EventQueueImpl::dispatch(long)

From the code, it crashed at this line.

void MarketPriceClient::displayServiceAndItemName( const RespMsg& respMsg, ConsumerItem& cacheItem, RFA_String& temp )
{
...

temp += cacheItem.getName() + RFA_String( " :\n", 0, false );
}

It seems that cacheItem is invalid. The application log before crash was:

11:32:30
RDMConsumerClient : Status Msg : ELEKTRON_EDGE – TRI.N :
Status :
DataState : Suspect
StreamState : Open
StatusCode : None
StatusText : Item is stale

11:33:40
RDMConsumerClient: Received Final Stream State : 'Closed' for MarketPrice item: 'TRI.N'
RDMConsumerClient : Status Msg : ELEKTRON_EDGE - TRI.N:

However, another instance of the application running on a different machine didn’t crash. Both applications connected to the same server. The log of this application at that time was:

11:32:30
RDMConsumerClient : Status Msg : ELEKTRON_EDGE - TRI.N :
Status :
DataState : Suspect
StreamState : Open
StatusCode : None
StatusText : Item is stale
11:33:40
RDMConsumerClient : Status Msg : ELEKTRON_EDGE - TRI.N:
11:55:35
RDMConsumerClient: Received Final Stream State : 'Closed' for MarketPrice item: 'TRI.N'
RDMConsumerClient : Status Msg : ELEKTRON_EDGE - TRI.N:
Status :
DataState : Suspect
StreamState : Closed
StatusCode : None
StatusText : Record dropped from network

Please let me know the cause of this issue and how to fix this problem.

Tagged:

Best Answer

  • Jirapongse
    Jirapongse ✭✭✭✭✭
    Answer ✓

    From the application log, at 11:33:40, both applications
    received the status message of TRI.N. The crash application logged this status
    message as CLOSED stream state while the non-crash application logged it as the
    status message without response status information (stream state, data status,
    and status, and status text).

    I assume that
    at 11:33:40, the applications received the status message without RespStatus
    information from the server, as shown below.

    <statusMsg domainType="RSSL_DMT_MARKET_PRICE" streamId="5" containerType="RSSL_DT_NO_DATA" flags="0x0" dataSize="0">
    <dataBody>
    </dataBody>
    </statusMsg>

    According to RDM usage guide, RespStatus is optional.
    Therefore, the above status message is valid.

    image

    I have verified the Consumer example code in RFA package and
    found that the code is unable to handle this status message (without
    RespStatus).

    image

    At line 146-147, the code verifies the presence of
    RespStatus before displaying it. However, the code at line 154 – 159 doesn’t
    verify the presence of RespStatus before using it. The application will get the
    invalid or outdated RespStatus which causes the application behaves
    unexpectedly.

    For the problem, I assume that the crash application
    retrieved the CLOSED stream state from the outdated RespStatus and then it
    closed the stream and destroyed the closure. After that, the application
    received and processed the refresh message of the TRI.N sent by the server, and
    then it crashed when accessing the destroyed closure.

    To handle this scenario, the application must be modified to
    verify the presence of RespStatus before using it.

    // Check for final stream states viz. 'Closed', ClosedRecover etc.  
    // These states are usually reported in status messages.
    if (respMsg.getHintMask() & RespMsg::RespStatusFlag){
    const RespStatus &respSt = respMsg.getRespStatus();
    const RespStatus::StreamState strState = respSt.getStreamState();
    if (strState == RespStatus::ClosedEnum ||
    strState == RespStatus::ClosedRecoverEnum)
    {
    ...

    Please verify the application code to make sure that it has verified the presence of RespStatus before accessing it. Hope this help.

Answers