libcoap icon indicating copy to clipboard operation
libcoap copied to clipboard

Is there a mmory leak or Am I using the lib wrongly ?

Open fbucafusco opened this issue 3 years ago • 5 comments

Environment

  • libcoap version: v4.3. something (not so sure, because is a precompiled lib but has the coap3 folder)

  • Build System: platformio

  • Operating System: Windows

  • Operating System Version: 10

  • Hosted Environment: platformio/espressif32

Problem Description

Hi ! I am re-opening this because I have a similar issue with a "memory leak" that I am experiencing. I have an application that sent 2 type of COAP_MESSAGE_CON. Everything goes well until I decided to change one of the to be a COAP_MESSAGE_NON. For this NON msg I am not waiting a response, so I dont call cop_io_process. I just only call coap_send. I have the libcoap usage in a class, but my code is something like this:

/* inside pdu_create calls coap_new_pdu and fills the pdu with data. The leak is not here because I check-it. msg_type has the info if COAP_MESSAGE_NON or not and that the rqst is a POST */
coap_pdu_t *pdu = this->pdu_create( payload , payloadsize ,  path , msg_type);   
coap_send(this->m_session, pdu );

When I configure the message as COAP_MESSAGE_CON and (after the code I copied) wait for a response, the leak is not there. But configuring it as NON, the leak appears reducing the heak size on every coap_send call.

I am using the ESP32 with ESPIDF framework and I am measuring the leak using esp_get_free_heap_size() before and after the "send receive" operation.

I tried to track the leak and discard if I was messing it, but as far I can tell, I did things right.

Maybe I am using the lib wrongly and I have to do some other stuff after calling coap_send.

Any help will be appreciated.

BTW. I am configuring the client like this:

this->m_ctx = coap_new_context(NULL);
coap_context_set_block_mode(this->m_ctx, COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY); 
coap_register_response_handler(this->m_ctx, message_hnd);    //used when the msg is COAP_MESSAGE_CON 
//creates the address object reference
coap_address_init( dst_addr );
this->m_session = coap_new_client_session(this->m_ctx, NULL, dst_addr, COAP_PROTO_UDP);
coap_session_set_app_data(this->m_session, this);

fbucafusco avatar Aug 01 '22 18:08 fbucafusco

When using coap_context_set_block_mode() and sending a PDU using NON, coap_send() sets up a coap_lg_crcv_t structure in case there is a large block of data being returned that has to be split across multiple PDUs using Block2 (RFC7959). This coap_lg_crcv_t structure gets deleted after EXCHANGE_LIFETIME (RFC7252, Section 4.8.2) of inactivity.

It is possible that you are seeing these coap_lg_crcv_t structures which have not had enough time to idle out (done by coap_io_process()), or alternatively, the hosted environment is not updating libcoap's notion of tick time (does coap_ticks(&now) when repeated several times increase the value of now?) which means that coap_lg_crcv_t does not get idled out.

mrdeep1 avatar Aug 01 '22 20:08 mrdeep1

Thanks for the fast response ! I reviewed the source for understanding better. It seems that structure is freed in coap_block_check_lg_crcv_timeouts. So, Should I call coap_io_process even If my client sends a NON pdu with block mode enabled? I ask this because it seems that coap_block_check_lg_crcv_timeouts is only called on coap_io_prepare_io. But for a NON, calling coap_io_process does not make sense to me (hit me if I am wrong). I tried it, and didn't work.

In the other hand, coap_ticks, as you say, depends on the hosted environment. For the espidf, time.h has defined _POSIX_TIMERS which leads to #define COAP_CLOCK CLOCK_REALTIME in coap_time.c. Then, coap_ticks uses clock_gettime. I added coap_clock_init that was missing in my code. But the problem is still there.

Maybe to call coap_context_set_block_mode(0) before sending the COAP_MESSAGE_NON, and setting to a desired mode when sending a COAP_MESSAGE_CON is the right thing to do.

fbucafusco avatar Aug 02 '22 16:08 fbucafusco

Yeap, I called coap_context_set_block_mode before each sendingwith boths settings, and works fine. No more leaks. Not so sure if it is the correct way to handle this tho.

fbucafusco avatar Aug 02 '22 17:08 fbucafusco

Do you mean that you are calling coap_context_set_block_mode(ctx, 0) before sending the NON and then coap_context_set_block_mode(ctx, COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY) before sending a CON? `` If you not expecting any Block based transfers, then there is no need to call coap_context_set_block_mode() at all.

Certainly coap_context_set_block_mode(ctx, 0) means that the coap_lg_crcv_t structure is not used and hence not generated.

I have found that sending a NON request where there is no response can cause the coap_lg_crcv_t to not get freed off in a timely manner - I am looking at this.

It would help if you are able to confirm calling coap_ticks(&now) several times with a time gap of a second or so actually causes now to increase? I have seen a misconfigured clock type in esp-idf cause an issue here.

coap_clock_init() gets called by coap_startup() which gets called by coap_new_context(), so that is not an issue.

In general, coap_io_process() should be periodically called to handle any (internal) timeouts or packets arriving - even for NON requests as there may be NON responses (or perhaps ICMP unreachable packets etc.).

mrdeep1 avatar Aug 02 '22 17:08 mrdeep1

Yes. I did that. And for sure, if then I don't need big messages I will remove the block mode. Thanks for the advice. Also thanks for letting me know about the coap_tick_init call.

I will test if coap_ticks works well using espidf. -> UPDATE: yes, time is updating correctly.

fbucafusco avatar Aug 03 '22 11:08 fbucafusco

@fbucafusco Can this be closed now?

mrdeep1 avatar Oct 14 '22 14:10 mrdeep1