This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Tiva-C / CCS Ver.6.1.2 / C++ => dynamic allocation

Hello folks,

i have the follwoing toolchain: Tiva-C / CCS Ver.6.1.2 / C++
My starting point was the Kentec demo project delivered in Tiva Ware for EK-T4MC1294XL evalboard.

I try to do dynamic allocation and have already set the heapsize to 2048 (Properties->CCS Build->ARM Linker->Basic Options).
I have checked, that i don´t get a Null pointer.
My FW has a "ItemFactory.cpp" file from where "Items" can be requested. The FW works fine if simply return a pointer to an instance
of an classes instance allocated at compile time.


So, is there anything else i have to consider than the mentioned heap size? Some kind of some other setting?  Regarding my starting point demo-project,
do i have to add something to the startup file? May be an Heap Offset for example?

best regads,
Jasson

  • Hello Jasson

    I am sure this should be on the Compiler Forum. However what is the size of the class allocation requested?

    Regards
    Amit
  • Hello Amit,

    I don´t know how to check the size. In an array of staticly allocated instances the first one is at 0x20002318 and the second one at 0x20002340 so it´s a difference of 0x22. Considering the 32Bit architecture, does it mean the class is 0x12*4 => 136 Bytes in size?
    So does your question about the classes size imply, i´m not missing a environment parameter to set?

    i don´t think the classes size is the reason. Until now it´s just a note class for a binary tree to build up a menu. So it contains parent, child, next and previous pointers together with their related Set and Get functions. Actually the final base class is derived from a "BaseClass" which implements a virtual class and contains method implementations for all but one methods. Finaly the "NodeClass" is derived from that BaseClass and implements "the" last missing SetControls() method of the interface.

    best regads,
    Jasson
  • user4221161 said:
    I try to do dynamic allocation and have already set the heapsize to 2048 (Properties->CCS Build->ARM Linker->Basic Options).
    I have checked, that i don´t get a Null pointer.
    My FW has a "ItemFactory.cpp" file from where "Items" can be requested. The FW works fine if simply return a pointer to an instance
    of an classes instance allocated at compile time.

    Can you describe in more detail what happens when the firmware doesn't work, when dynamic allocation is attempted.

  • I also noticed, it makes a difference, if i declare the static allocated Node (mentioned in the starting post) is defined in the header or source file. If i define it in the header it doesn´t work as well.

    My estimation is, that "something" with a running pointer goes wrong - but as mentiond only does when allocated dynamically.
    I guess describing the symptoms more exact, won´t go somewhere. The requested node is placed inside the binary tree architecture for the menu by an iterator i have written myself (no STL Iterator). When the iterator is finished some canvaces (collected in an array) of the GUI are updated. The FW goes down, when WidgetMessageQueueProcess(); of the grLib is performed on the first canvas.
    Thats why i think it´s a running pointer messing around when i allocate dynamically. It feels like it´s corrupting the canvas.
  • EDIT:
    I have followed the reference pointers (starting from where the item is alocated )in the iterator when it inserts the allocated item - they´re ok.
  • I don´t know how to check the size. In an array of staticly allocated instances the first one is at 0x20002318 and the second one at 0x20002340 so it´s a difference of 0x22. Considering the 32Bit architecture, does it mean the class is 0x12*4 => 136 Bytes in size?

    You can check the size af a variable in the map file (advice the linker to generate one), or at runtime with "sizeof".

    Addresses are always byte addresses. The difference between 0x18 and 0x40 is 0x28, not 0x22. This address difference is not necessary equal to the size, as it includes padding bytes for alignment. Both addresses (0x20002318 and 0x20002340) are longword aligned, and suggest padding.

    In general, I would think twice before using dynamic memory allocation features (malloc(), new, etc.) on such a MCU. This idea stems from large systems with virtual memory (with MMU), and swapping capability. You MUST know the maximal memory usage at compile time, or limit allocation (inlcuding error handling) at runtime, or your  application fails catastrophically. And dependent on the toolchain, the malloc functionality is often implemented as stub, requiring you to implement the important rest (_sbrk()).

  • It came to my mind, when i worked over the main file of the demo project to make it c++ compilant, i commented out this line
    "#pragma DATA_ALIGN(i16DMAControlTable, 1024)"
    To be honest i didn´t understand what it does. It´s reading like it has something to do with DMA, but i can´t even estimate, if it has impact.

    I´m aware about the issue with dynamic allocations on MCU´s. I have a special application where i can accept to perform a software reset to clear the fragmented heap.
  • user4221161 said:
    It came to my mind, when i worked over the main file of the demo project to make it c++ compilant, i commented out this line
    "#pragma DATA_ALIGN(i16DMAControlTable, 1024)"
    To be honest i didn´t understand what it does. It´s reading like it has something to do with DMA, but i can´t even estimate, if it has impact.

    That aligns address of the i16DMAControlTable to be a multiple of 1024 bytes, which is a requirement for the DMA controller.

    If not aligned correctly, maybe the DMA controller will overwrite something else in memory - leading to corruption of other adjacent variables.

  • user4221161 said:
    It came to my mind, when i worked over the main file of the demo project to make it c++ compilant, i commented out this line
    "#pragma DATA_ALIGN(i16DMAControlTable, 1024)"

    The syntax of the DATA_ALIGN pragma is different for C and C++. From the compiler user's guide:

    5.9.5. The DATA_ALIGN Pragma

    The DATA_ALIGN pragma aligns the symbol in C, or the next symbol declared in C++, to an alignment boundary. The alignment boundary is the maximum of the symbol's default alignment value or the value of the constant in bytes. The constant must be a power of 2.

    The syntax of the pragma in C is:

    #pragma DATA_ALIGN (symbol, constant);

    The syntax of the pragma in C++ is:

    #pragma DATA_ALIGN (constant);

    Therefore, try changing the pragma to be C++ compliant rather than commenting it out.

  • I´m aware about the issue with dynamic allocations on MCU´s. I have a special application where i can accept to perform a software reset to clear the fragmented heap.

    I'm not in a position to assess if a reset would be "acceptable behavior" for your target device and the (end) user. It is not for the devices I'm working on.

    ...to make it c++ compilant,

    That suggests significant influence on the memory handling strategy from your side. Porting "hardcore" C++ applications from larger systems (PC) would IMHO be much more critical here. Software engineers/architects for such systems often cannot imagine that a system can run out of memory ...

  • I tried making the pragma c++ compilant, but that seems not to be the source of problem. I also tried the dirty thing to use malloc and cast the void pointer, but malloc is not recognized as key word in my cpp file.

    I more and more think it´s a definition issue:
    in the start up file where the function table is defined the very first thing is a function pointer to " __STACK_TOP" => (did i read it right? ((void (*)(void))((uint32_t)&__STACK_TOP))

    Searching for __STACK_TOP i get a hit in .map file in the global symbol section. There i also found matches for malloc, free, realloc , calloc -
    but no matches for new/delete

    I would expect i´d need a definition like "__HEAP_TOP" and mappings of new/delete in the global symbols?

    In the project propertie=>CCS General the compiler version is TI v 5.1.6


    best regards,
    Jasson
  • user4221161 said:
    There i also found matches for malloc, free, realloc , calloc - but no matches for new/delete

    The linker map file shows mangled names. e.g. created the following simple C++ test using TI ARM compiler v15.12.2:

    class test
    {
    public:
    	void set (int data_in)
    	{
    		data = data_in;
    	}
    
    	int get (void)
    	{
    		return data;
    	}
    
    	test(): data(-1) {};
    private:
    	int data;
    };
    
    int main(void) {
    	test *local_instance = new (test);
    	
    	local_instance->set (4);
    
    	return local_instance->get ();
    }
    

    When I stepped into the new() call the debugger showed entry into the following function in the new_.cpp source file in the run time library:

    extern void *operator new(size_t size) THROW(STD_NAMESPACE::bad_alloc)
    

    However, the map file reported the mangled name of _Znwj for the new operator.

    The armdem C++ Name Demangler may be used to process the linker map file and report the demangled names.

    user4221161 said:
    I would expect i´d need a definition like "__HEAP_TOP" and mappings of new/delete in the global symbols?

    For the TI compiler the heap (for malloc and new allocations) is stored in the .sysmem section. In the linker map file:

    • The symbol _sys_memory gives the base address of the heap
    • The symbol __SYSMEM_SIZE gives the size of the heap

  • That seems an egregious difference

    Robert
  • user4221161 said:
    malloc is not recognized as key word in my cpp file.

    It's not a key word, it's a library function.

    Robert

  • Robert Adsett said:
    That seems an egregious difference

    Robert, can you clarify which difference you are referring to?

  • The pragma C/C++ difference Chester

    Robert
  • I also tried the dirty thing to use malloc and cast the void pointer, but malloc is not recognized as key word in my cpp file.

    "malloc" is not a keyword, but a library function. If the usage of malloc throws an error (probably a linker error), you might have a problem with the project setup. Usually, project "wizards" automatically select the link libraries (some version of the clib) depending on other settings. And with most IDEs, you must decide the kind of project (C or C++) in this "wizard", and can't change it once finished. Both types have different startup files and libs, so mixing usually ends in a disaster ...

    in the start up file where the function table is defined the very first thing is a function pointer to " __STACK_TOP" ...

    malloc() allocates memory from the heap, not from the stack. STACK_TOP is most probably the stack start address (I'm not a CCS user). And since the ARM Cortex stack grows downwards, I do not assume any relation to memory allocation (malloc, etc.).

  • I don´t get the information behind that

    "When I stepped into the new() call the debugger showed entry into the following function in the new_.cpp source file in the run time library:

    extern void *operator new(size_t size) THROW(STD_NAMESPACE::bad_alloc)
    

    However, the map file reported the mangled name of _Znwj for the new operator.

    The armdem C++ Name Demangler may be used to process the linker map file and report the demangled names."


    To be honest, i don´t understand, what the listing extern void *operator new(size_t size) THROW(STD_NAMESPACE::bad_alloc) means
    i understand so far, that "something" is defined somewhere else. I don´t understand the THROW behind the new without a semicolon -
    Does it mean, new() always throws an exception? I know, i get it wrong, but i can´t "read" the meaning of the listing.

    Actually i´m wondering a bit, this new() thing is so complicated, since i´m for sure not the only one using it. That´s why i can imagine that i oversee something very simple like an offset or size definition...

    best regards!

  • user4221161 said:
    To be honest, i don´t understand, what the listing extern void *operator new(size_t size) THROW(STD_NAMESPACE::bad_alloc) means
    i understand so far, that "something" is defined somewhere else. I don´t understand the THROW behind the new without a semicolon -
    Does it mean, new() always throws an exception? I know, i get it wrong, but i can´t "read" the meaning of the listing.

    It is standard C++ - see http://www.cplusplus.com/reference/new/operator%20new/

    The point my previous post was trying to make was a program can use the C++ new() operator, yet "new" doesn't appear in the TI linker map file due to the linker map file reported C++ "mangled" names.

    To be honest, the TI ARM compiler and linker user manuals describe this in more detail than my posts, so not sure how I can better describe it.

  • Hello Chester,

    i don´t really get, what you mean by this: yet "new" doesn't appear in the TI linker map file due to the linker map file reported C++ "mangled" names.
    What do you mean by "yet"? Not implemented "Yet"?
    Do you mean, new doesn´t appear in the linker´s map file, because the map file only states mangled names? Do you want to imply,  that allthough "new" is used in sourcecode, the executing code behind new is not transfered to the flash and thereby not mangled?
    I found the compiler manual, but not the linker manual. And even though, i don´t know, what information to look for.

    What i wrote earlier, that malloc is not recognized as a keyword - i ment, that it´s not highlighted and also marked as unknown identifier.

  • I'm not a C++ expert, but I bet there is no "new" function or library symbol - it is a C++ keyword, which the compiler maps to existing memory allocation functions - like alloc().