eclipse-threadx/samples

STM32L4+ CubeIDE: Incorrect malloc behavior in OOM case

Closed this issue · 9 comments

This issue is observed with Azure_RTOS_6.1_STM32L4+-DISCO_STM32CubeIDE_Samples_2020_10_10.zip

I either have some bug in my example or newlib-nano malloc implementation seems to be experiencing some unexpected malloc behavior.

I expect malloc to return null if it runs our of ram. In the code below:

  • If the malloc line in main is left as-is, all malloc and frees succeed, which should not be the case because there should not be enough RAM. Line is printed ====Allocated 100 blocks of size 102400 (of max 100)=== (that's ~10 megabytes)
  • If the malloc line in main is commented out, an exception handler catches an exception once it runs out of ram. It should simply return null when it does.

This is the injected code from sample_azure_iot_embedded_sdk main.c:

#define MEMORY_TEST
#ifdef MEMORY_TEST
#define TEST_BLOCK_SIZE  (100 * 1024)
#define TEST_BLOCK_COUNT 100
static void *blocks[TEST_BLOCK_COUNT];
void memory_test() {
    int i = 0;
    for (; i < TEST_BLOCK_COUNT; i++) {
        void *ptr = malloc(TEST_BLOCK_SIZE);
        if (NULL == ptr) {
            break;
        }
        blocks[i] = ptr;
    }
    printf("====Allocated %d blocks of size %d (of max %d)===\r\n", i, TEST_BLOCK_SIZE, TEST_BLOCK_COUNT);
    for (int j = 0; j < i; j++) {
        free(blocks[j]);
    }
}
#endif /* MEMORY_TEST */

/* Define main entry point.  */
int main(void)
{
    /* Setup platform. */
    board_setup();


    if (NULL == malloc(1UL * TEST_BLOCK_SIZE * TEST_BLOCK_SIZE)) return 1;

    memory_test();

    /* Enter the ThreadX kernel.  */
    tx_kernel_enter();
}
bo-ms commented

@nik-markovic first using malloc for embedded software is not encouraged. If you do want to use malloc, you can increase the heap size in iar\common_hardware_code\stm32l4s5xx_flash.icf.

define symbol ICFEDIT_size_heap = 0x200;

@bo-ms The decision use or not to use malloc should be differed to the developers. Malloc has its uses in embedded development. You are using it in the Azure C SDK which is being used across many embedded products. I also want to use the cJSON library (I don't want to use the alternatives) and I am willing ignore fragmentation because there's plenty of heap available.

I an using the Cube IDE project. I don't see how "increasing" heap size would help with malloc behavior that does not behave per C standard. The default project is already using all available ram for heap. I never said that I needed more heap. I would just hope that you can fix the issue in your SDK.

Hi @nik-markovic - we don't provide/maintain the malloc implementation. Have you talked to the folks who wrote it?

hi @nik-markovic , the C0SDK was designed to not use the heap in any way, if you are seeing heap allocation in the C-SDK, then this is a bug.

Are you able to point and where the heap allocation is?

@goldscott I think that I understand what you are saying now. You are not providing a malloc implementation in the SDK, but I was expecting that the customer projects (deriving form your sample) would be able to use malloc.

For the STM32L4+ CubeIDE flaveor, the malloc implementation coming from the CubeIDE's toolchain. For example, found in sample_azure_iot_embedded_sdk/Debug/sample_azure_iot_embedded_sdk.map if malloc is linked in:

/opt/st/stm32cubeide_1.6.0/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.linux64_1.5.0.202011040924/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc_nano.a(lib_a-findfp.o) (_malloc_r)

Since you are providing the reference project and STM32L4 configuration, I probably incorrectly assumed that you would configure newlib (that comes with he toolchain that comes with the IDE) and provide malloc functionality... I'm no embedded expert, but I'm under the impression that _sbrk may need to be implanted to limit heap to the boundaries set by the linker configuration file.

I ok with assuming that am on my own here, and that I should figure this out, as it falls out of scope and supported features of AzureRTOS. Though... it would probably be the first development environment for a device that I've encountered that doesn't support it. Even though you do not use malloc in your implementation or provide an actual implementation for it, it would be nice if malloc was at least supported in the sample reference project configuration.

@ryanwinter I wasn't referring to the AzureRTOS Azure C SDK port. I was referring to
azure-iot-sdk-c on github

Thanks!

Hi @nik-markovic,

Thanks for pointing out the azure-iot-sdk-c implementation.

That SDK is not meant for embedded devices, although it is still used in that way. Please use the Azure SDK for C for embedded devices which doesn't use heap allocation. The Azure RTOS middleware is built on top of this SDK. (I know, the names are confusingly similar).

@ryanwinter Oh I see...

Though comment "Please use the Azure SDK for C for embedded devices" does not apply to me. I never used the Azure C SDK nor do I have intention to use it currently. I need to use the AzureRTOS and cJSON library in my application (which needs malloc).
I was just trying to point out (with a bad example) that comment "don't use malloc in embedded" is a bit harsh and that malloc is sometimes used in embedded devices nowadays, so that memory can be more efficiently shared - compared to overhead of fixed buffers or implementing a sharing mechanism for those buffers. More often than not the underlying (RT)OS provides efficient mechanisms to deal with fragmentation... FreeRTOS and Zephyr comes to mind.

Anyways, thanks for pointing out my Azure C SDK confusion.

I don't think anybody harshly said "don't use malloc." Bo stated "using malloc for embedded software is not encouraged." Obviously, there are cases when malloc is needed, but we encourage people to avoid it if possible.

Malloc is typically provided in the libraries included with the compiler.

bo-ms commented

@goldscott thanks for clarifying it.