Arm Mbed OS support forum

Could memory leak or heap fragmentation be the issue?

Occasionally I am getting MBEDTLS_ERR_SSL_ALLOC_FAILED from mbedtls_ssl_setup() during repeated HTTP partial content download. Since this problem happens very rarely, it is a bit difficult to troubleshoot.

I am running mbedTLS on a Microchip PIC32MZ MCU, connected to a LTE-M/NB-IoT modem. I have 128K static memory reserved for the library with MBEDTLS_PLATFORM_MEMORY defined in the config.h file. The MCU runs two main tasks - MQTT client, talking to the AWS MQTT broker, and HTTPS client, for downloading new firmware image from the AWS S3 bucket over the air.

Due to the slowness and limited bandwidth of the LTE-M and NB-IoT technologies, the HTTP file download has to use the partial content GET, basically 2KB per request, until all ~700KB of data are received. During the course of the file download, one can see as many as 30 disconnect and reconnect, and each time the TLS session would close down and re-open once the cell network is established. Here are some of my functions:

#define MBEDTLS_MAX_MEMORY_ALLOCATED    (1024 * 128)
static uint8_t tls_memory_buf[MBEDTLS_MAX_MEMORY_ALLOCATED];

// called in main()
void mbedtls_mem_init(void)
{
    mbedtls_memory_buffer_alloc_init(tls_memory_buf, sizeof tls_memory_buf);
}

void HTTPS_TLS_CLOSE(void)
{
    if (server_fd_https.fd != -1)
    {        
        mbedtls_entropy_free(&entropy_https);
        mbedtls_x509_crt_free(&cacert_https);
        mbedtls_ctr_drbg_free(&ctr_drbg_https);
        mbedtls_ssl_config_free(&conf_https);
        mbedtls_ssl_free(&ssl_https);

        server_fd_https.fd = -1;
    }
}

bool HTTPS_TLS_OPEN(void)
{
    int ret;
    const char *pers = "https_tls_wrapper";


    server_fd_https.fd = 1;
    mbedtls_debug_set_threshold(1);

    mbedtls_ssl_init(&ssl_https);
    mbedtls_ssl_config_init(&conf_https);
    mbedtls_ctr_drbg_init(&ctr_drbg_https);
    mbedtls_x509_crt_init(&cacert_https);
    
    mbedtls_entropy_init(&entropy_https);    
    mbedtls_entropy_add_source(&entropy_https, my_https_entropy, NULL, sizeof my_https_random, MBEDTLS_ENTROPY_SOURCE_STRONG);
    
    ret = mbedtls_ctr_drbg_seed(&ctr_drbg_https, mbedtls_entropy_func, &entropy_https, (const unsigned char *)pers, strlen(pers));
    if (ret != 0)
    {
        printf("%s: mbedtls_ctr_drbg_seed ERROR -0x%x\r\n", __FUNCTION__, -ret);
        return false;
    }

    ret = mbedtls_x509_crt_parse(&cacert_https, TRUSTED_ROOT_CA, TRUSTED_ROOT_CA_SIZE);
    if (ret != 0)
    {
        printf("%s: mbedtls_x509_crt_parse cacert ERROR -0x%x\r\n", __FUNCTION__, -ret);
        return false;
    }
    
    ret = mbedtls_ssl_config_defaults(&conf_https, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
    if (ret != 0)
    {
        printf("%s: mbedtls_ssl_config_defaults ERROR -0x%x\r\n", __FUNCTION__, -ret);
        return false;
    }

    mbedtls_ssl_conf_verify(&conf_https, NULL, NULL);
    mbedtls_ssl_conf_authmode(&conf_https, MBEDTLS_SSL_VERIFY_REQUIRED);
    mbedtls_ssl_conf_rng(&conf_https, mbedtls_ctr_drbg_random, &ctr_drbg_https);
    mbedtls_ssl_conf_dbg(&conf_https, my_https_debug, stdout);
    mbedtls_ssl_conf_ca_chain(&conf_https, &cacert_https, NULL);
        
    mbedtls_ssl_conf_read_timeout(&conf_https, TLS_TIMEOUT_MS);

    HTTPS_SetHostname(); /* calling mbedtls_ssl_set_hostname */
    
    ret = mbedtls_ssl_setup(&ssl_https, &conf_https);
    if (ret != 0)
    {
        printf("%s: mbedtls_ssl_setup ERROR -0x%x\r\n", __FUNCTION__, -ret);
        return false;
    }

    mbedtls_ssl_set_bio(&ssl_https, &server_fd_https, mbedtls_https_send, mbedtls_https_recv, NULL);

    return true;
}

Can someone please tell me if I am doing something inappropriate here? I am speculating that perhaps there is a memory leak or the heap becomes so fragmented that it fails on mbedtls_calloc(). The exact error message in my case is:

…/mbedtls_lib/ssl_tls.c:5661: alloc(16717 bytes) failed