Skip to content

malloc unexpected behaviour on GCC_ARM compiler #5386

@maciejbocianski

Description

@maciejbocianski

Description

  • Type: Bug
  • Priority: Major

Bug

Target
all

Toolchain:
GCC_ARM

Toolchain version:
gcc version 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437] (GNU Tools for ARM Embedded Processors 6-2017-q2-update)

mbed-cli version:
1.2.0

mbed-os sha:
38ba693

Expected behavior
When try to allocate more memory than heap can handle we get NULL from malloc and further allocations (within heap size) work fine

Actual behavior
When try to allocate more memory than heap can handle we get NULL from malloc and any further allocation (within heap size) return NULL

Steps to reproduce

Compile and run below code
Program find maximum memory which malloc can allocate

extern unsigned char *mbed_heap_start;
extern uint32_t mbed_heap_size;
uint32_t max_mbed_heap_size = mbed_heap_size;

int main()
{
	void *data = NULL;

	while(true)
	{
		data = malloc(max_mbed_heap_size);
		if(data || max_mbed_heap_size == 0) {
			break;
		} else {
			max_mbed_heap_size--;
		}
	}

	printf("max_mbed_heap_size: %lu \r\n", max_mbed_heap_size);
	printf("mbed_heap_start: %X \r\n", mbed_heap_start);
	printf("mbed_heap_size: %lu \r\n", mbed_heap_size);
	printf("data: %p \r\n\r\n", data);
}

Output from NUCLEO_F070RB


GCC_ARM
max_mbed_heap_size: 0
mbed_heap_start: 2000275C
mbed_heap_size: 5284
data: 0x0

ARM
max_mbed_heap_size: 6556
mbed_heap_start: 2000224C
mbed_heap_size: 6580
data: 20002260

IAR
max_mbed_heap_size: 4044
mbed_heap_start: 200006E8
mbed_heap_size: 4096
data: 200006f0

Test program 2

extern unsigned char *_sbrk_ret_1;
extern unsigned char *_sbrk_ret_2;
extern int _sbrk_incr;
extern uint32_t _sbrk__end__;
extern unsigned char *_sbrk_prev_heap;
extern unsigned char *_sbrk_new_heap;

extern unsigned char *mbed_heap_start;
extern uint32_t mbed_heap_size;
const uint32_t size = 100;
uint32_t max_mbed_heap_size = 0;

int main()
{
	void *data = NULL;

	printf("*** main begin ***\r\n");
	printf("\r\n");
	printf("_sbrk_incr: %i\r\n", _sbrk_incr);
	printf("_sbrk__end__: %lu\r\n", _sbrk__end__);
	printf("prev_heap: %X\r\n", _sbrk_prev_heap);
	printf("new_heap: %X\r\n\r\n", _sbrk_new_heap);

	printf("*** test begin ***\r\n");
	while(max_mbed_heap_size <= mbed_heap_size)
	{
		_sbrk_ret_1 = 0;
		_sbrk_ret_2 = 0;
		_sbrk_incr = 12345;
		_sbrk__end__ = 12345;
		_sbrk_prev_heap = NULL;
		_sbrk_new_heap = NULL;

		void *tmp_data = malloc(size);

		if(_sbrk_incr != 12345)
			printf("_sbrk_incr: %i\r\n", _sbrk_incr);
		if(_sbrk__end__ != 12345)
			printf("_sbrk__end__: %lu\r\n", _sbrk__end__);
		if(_sbrk_prev_heap != NULL)
			printf("prev_heap: %X\r\n", _sbrk_prev_heap);
		if(_sbrk_new_heap != NULL)
			printf("new_heap: %X\r\n", _sbrk_new_heap);
		if(_sbrk_ret_1 != NULL)
			printf("_sbrk_ret_1: %X\r\n", _sbrk_ret_1);
		if(_sbrk_ret_2 != NULL)
			printf("_sbrk_ret_2: %X\r\n", _sbrk_ret_2);

		if(NULL == tmp_data) {
			break;
		} else {
			data = tmp_data;
			max_mbed_heap_size += size;
			printf("allocated: %lu\r\n", size);
			printf("allocated total: %lu\r\n", max_mbed_heap_size);
			printf("\r\n");
		}
	}
	printf("*** test end ***\r\n\r\n");

	printf("max_mbed_heap_size: %lu \r\n", max_mbed_heap_size);
	printf("mbed_heap_start: %X \r\n", mbed_heap_start);
	printf("mbed_heap_size: %lu \r\n", mbed_heap_size);
	printf("data: %p \r\n", data);
	printf("__get_MSP(): %X \r\n", __get_MSP());
	printf("*** main end ***\r\n");
	printf("\r\n");
}

Test program 2 additional changes in platform/mbed_retarget.cpp

diff --git a/platform/mbed_retarget.cpp b/platform/mbed_retarget.cpp
index 6c5f12031..5d5b323a8 100644
--- a/platform/mbed_retarget.cpp
+++ b/platform/mbed_retarget.cpp
@@ -744,24 +744,37 @@ extern "C" caddr_t _sbrk(int incr) {
 }
 #else
 // Linker defined symbol used by _sbrk to indicate where heap should start.
+unsigned char * _sbrk_ret_1 = 0;
+unsigned char * _sbrk_ret_2 = 0;
+int _sbrk_incr = 12345;
+uint32_t _sbrk__end__ = 12345;
+unsigned char *_sbrk_prev_heap = (unsigned char*)0x12345;
+unsigned char *_sbrk_new_heap = (unsigned char*)0x12345;
 extern "C" uint32_t __end__;
 extern "C" caddr_t _sbrk(int incr) {
     static unsigned char* heap = (unsigned char*)&__end__;
     unsigned char*        prev_heap = heap;
     unsigned char*        new_heap = heap + incr;

+    _sbrk_incr = incr;
+    _sbrk__end__ = __end__;
+    _sbrk_prev_heap = prev_heap;
+    _sbrk_new_heap = new_heap;
+
 #if defined(TARGET_CORTEX_A)
     if (new_heap >= (unsigned char*)&__HeapLimit) {     /* __HeapLimit is end of heap section */
 #else
     if (new_heap >= (unsigned char*)__get_MSP()) {
 #endif
         errno = ENOMEM;
+        _sbrk_ret_1 = new_heap;
         return (caddr_t)-1;
     }

     // Additional heap checking if set
     if (mbed_heap_size && (new_heap >= mbed_heap_start + mbed_heap_size)) {
         errno = ENOMEM;
+        _sbrk_ret_2 = new_heap;
         return (caddr_t)-1;
     }

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions