question

Upvotes
Accepted
129 12 16 27

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.

treprfarfa-api
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1 Answer

Upvotes
Accepted
53.2k 138 44 63

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.

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

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.


status.png (245.5 KiB)
code.png (432.1 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Thank you. I will modify the code to handle this message.