Skip to main content
juliuscaesar
Associate III
June 24, 2018
Question

C++ no bad alloc exception for vector class

  • June 24, 2018
  • 3 replies
  • 3856 views
Posted on June 24, 2018 at 21:34

Hey guys,

I'm using C++ on my STM32F429 with G++ compiler.

I was trying to test the limits of the vector class. However I'm always running into a hard fault. I'm expecting a bad alloc exception instead.

http://www.cplusplus.com/reference/vector/vector/emplace_back/

states that:

If a reallocation happens, the storage is allocated using the container's

http://www.cplusplus.com/vector::get_allocator

, which may throw exceptions on failure (for the default

http://www.cplusplus.com/allocator

, bad_alloc is thrown if the allocation request does not succeed).

vector<int> test_vector;

        try

        {

            for (int i = 0; i < 50000; i++)

            {

                test_vector.emplace_back(i);

                if (0 == (i % 10))

                {

                    //alle 10 mal 1 ms pause

                    osDelay(1);

                }

            }

        }

        catch (const exception& ex)

        {

            //Stop right here

            configASSERT(0);

        }

So where is my exception?

Exceptions are enabled in both the compiler and linker.

Compiler flags:

Invoking: MCU GCC Compiler

 

xxx\Debug

arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=c11 '-D__weak=__attribute__((weak))' '-D__packed=__attribute__((__packed__))' -DUSE_HAL_DRIVER -DSTM32F429xx -I'xxx/Giessomat/Inc' -I'xxx/Giessomat/Inc/User' -I'xxx/Giessomat/Inc/User/debug' -I'xxx/Giessomat/Inc/User/Testcases' -I'xxx/Giessomat/Inc/User/display' -I'xxx/Giessomat/Inc/User/display/img' -I'xxx/Giessomat/Inc/User/SD' -I'xxx/Giessomat/Inc/User/SD/XML' -I'xxx/Giessomat/Drivers/STM32F4xx_HAL_Driver/Inc' -I'xxx/Giessomat/Drivers/STM32F4xx_HAL_Driver/Inc/Legacy' -I'xxx/Giessomat/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F' -I'xxx/Giessomat/Middlewares/ST/STM32_USB_Device_Library/Core/Inc' -I'xxx/Giessomat/Middlewares/ST/STemWin/Config' -I'xxx/Giessomat/Middlewares/ST/STemWin/inc' -I'xxx/Giessomat/Middlewares/ST/STM32_USB_Device_Library/Class/CustomHID/Inc' -I'xxx/Giessomat/Drivers/CMSIS/Device/ST/STM32F4xx/Include' -I'xxx/Giessomat/Middlewares/Third_Party/FatFs/src' -I'xxx/Giessomat/Middlewares/Third_Party/FreeRTOS/Source/include' -I'xxx/Giessomat/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS' -I'xxx/Giessomat/Drivers/CMSIS/Include'  -Og -g3 -pedantic -Wall -Wextra -fmessage-length=0 -ffunction-sections -c -fmessage-length=0 -MMD -MP -MF'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.d' -MT'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.o' -o 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.o' '../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c'

Building file: ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c

Linker flags:

Building target: Giessomat.elf

Invoking: MCU G++ Linker

arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -L'xxx/\Giessomat\Middlewares\ST\STemWin\Lib'  -specs=nosys.specs -specs=nano.specs -u_printf_float -T'../STM32F429ZITx_FLASH.ld' -Wl,-Map=output.map -Wl,--gc-sections -fno-rtti -o 'Giessomat.elf' @'objects.list'  -lSTemWin540_CM4_OS_GCC -lm

Finished building target: Giessomat.elf

With these flags exceptions should be enabled right? So why am i not catching this exception?

    This topic has been closed for replies.

    3 replies

    Tesla DeLorean
    Guru
    June 24, 2018
    Posted on June 24, 2018 at 22:52

    >>However I'm always running into a hard fault. I'm expecting a bad alloc exception instead.

    So *what* is actually faulting? See processor registers and disassemble faulting instructions.

    Does the compiler expect some additional handlers or infrastructure to implement the functionality you expect?

    Structures that need to be initialized in the start up code?

    Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
    juliuscaesar
    Associate III
    June 25, 2018
    Posted on June 25, 2018 at 23:26

    hey,

    the faulty part is that my vector get's larger than the available free heap. The vector probably trys to allocate memory from some protected area.

    How can i diagnose the hard fault further. There is no stack trace. (But I'm very sure that the vector allocation is the problem. If i reduce the number of elements added to the vector (i.e instead of 50000 only 10000) everything works fine)

    This is just a test to check out the limits of the vector class.

    This code is not being used in the actual project.Therefore this code does not require any initialisation.

    However how can i safely use a vector if i am always running into a hard fault once the vector is too large?

    I'm using gcc/g++ compiler. My settings are as followed:

    0690X0000060LT6QAM.png0690X0000060LIdQAM.png

    Both of them have exceptions enabled.

    But you did ask the right question

    Does the compiler expect some additional handlers or infrastructure to implement the functionality you expect?

    I tested exception handling

        try

        {

            //Test Exception

            throw invalid_argument(''test exception'');

        }

        catch (const exception& ex)

        {

            configASSERT(0);

        }

    why am i not running into an exception but into the termination handler?

    Tesla DeLorean
    Guru
    June 25, 2018
    Posted on June 25, 2018 at 23:56

     ,

     ,

    How about instrumenting the HardFault_Handler so you get useful data?

     ,

    And adding code into _sbrk in syscalls.c or whatever is acting as the allocator. Figure out where the pool is, and how large it is.

    If you can isolate where it fails you can try an unwind the call stack, or perform static analysis of the call tree.

    >,>,why am i not running into an exception but into the termination handler?

    I don't know, you're coding user side try/catch exception handling, but that requires system side implementation to make the plumbing actually work. If all your fault handlers and abort()/exit() functionalities goes into while(1) loops, or just explodes, you'll will likely end up in the trap of last resort, ie HardFault_Handler or Default_Handler.

    Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
    Cyril FENARD
    ST Employee
    June 27, 2018
    Posted on June 27, 2018 at 15:44

    Hi

    Lampe.Julian

    ‌,

    Let me share what i did to make it work.

    I generated the project thanks to CubeMX tool, targeting SW4STM32 project.

    I changed the nature of the eclipse project to C++.

    I renamed main.c as main.cpp, to get c++ build for this file that tests the C++ exception.

    I added a main_misc.c file that implements:

    - _write for the output of std::cout to UART line,

    - _sbrk to check for lack of memory, from

    https://community.st.com/external-link.jspa?url=http%3A%2F%2Fsourceware.org%3A%2Fgit%2Fnewlib-cygwin.git

    source files.

    I added -fexceptions in the build options

    I put the stack value at 0x1000 and the heap value at 0x5000.

    ...

    printf('main(): with printf()\n');

    std::cout << 'main(): with std::cout' << std::endl;

    try {

    std::cout << 'Throwing an integer exception...\n';

    throw 42;

    } catch (int i) {

    std::cout << ' the integer exception was caught, with value: ' << i << '\n';

    }

    while (1){

    std::vector<int> test_vector;

    size_t capacity = test_vector.capacity();

    size_t size = 0;

    std::cout << 'test_vector.capacity() returned: ' << capacity << std::endl;

    for (int i = 0; i < 5000000; i++) {

    try {

    test_vector.emplace_back(i);

    capacity = test_vector.capacity();

    size = test_vector.size();

    }catch (const std::exception& ex){

    std::cout << ' the vector emplace_back() exception was caught, with value: ' << ex.what() << std::endl;

    Error_Handler();

    }

    std::cout << 'test_vector.size() returned: ' << size << std::endl;

    std::cout << 'test_vector.capacity() returned: ' << capacity << std::endl;

    And i could have the following

    $ cat /dev/ttyS18

    main(): with printf()

    main(): with std::cout

    Throwing an integer exception...

    the integer exception was caught, with value: 42

    test_vector.capacity() returned: 0

    test_vector.size() returned: 1

    test_vector.capacity() returned: 1

    ...

    test_vector.size() returned: 256

    test_vector.capacity() returned: 256

    _sbrk(): heap_end is incremented

    ...

    test_vector.size() returned: 4095

    test_vector.capacity() returned: 4096

    test_vector.size() returned: 4096

    test_vector.capacity() returned: 4096

    _sbrk: Heap and stack collision

    the vector emplace_back() exception was caught, with value: std::bad_alloc

    Hoping it helps.

    Regards.

    Cyril.

    juliuscaesar
    Associate III
    July 9, 2018
    Posted on July 09, 2018 at 22:38

    @

    Turvey.Clive.002

    I used True Studio to reproduce the error.

    0690X0000060LdqQAE.png

    Looks like I&39m allocating memory from some protected regions.

    I did track down the problem. The problem is C++ new operator which is probably used internally in the STL. Trying to allocate a large object using new causes the same error. Trying to allocate a large object using malloc() successfully returns a nullpointer.

    In my opinion this is a really stupid behaviour. We got the great STL with all those exceptions but none of them are thrown.

    I know the implementation of the STL is very much platform depended but still...

    Looks like i&39m having the same problems as this guy here:

    https://community.st.com/0D50X00009XkWCcSAN

     

    @

    Fenard.Cyril

    thx for your interesting post. Would you mind to post your main_misc.c file as well, so that i can have a look?

    That would be very great

    AvaTar
    Senior III
    July 10, 2018
    Posted on July 10, 2018 at 08:16

    Looks like I'm allocating memory from some protected regions.

    I wouldn't think so. Memory protection needs to be setup explicitly, and would cause a MPU fault.