Compiler optimization problem with FreeRTOS

I try to explain my problem with a simple example

typedef function<bool()> TaskCallback;

class Task
{
public:
	Task(TaskCallback task_callback) : task_callback(task_callback)
	{
		long_string_test = "This is a long string 0123456789ABCDEF 0123456789ABCDEF 0123456789ABCDEF";
		
		xTaskCreate(Task::RunTask, "task_name", 2560, this, 3, &task_handle);
	}
	
	~Task()
	{
		while(1); //Breakpoint: The destructor is never called
	}
	
private:
	static void RunTask(void* params)
	{
		Task* _this = static_cast<Task*>(params);
			
		_this->task_callback(); //The program crashes here because task_callback doesn't exist
	}
	
	string long_string_test;
	
	TaskCallback task_callback;
	
	TaskHandle_t task_handle;
};

main.cpp

static bool Init_task() { }

void main()
{
    Task task(Init_task);

    vTaskStartScheduler();
    
    //We should never get here as control is now taken by the FreeRTOS scheduler
    while(1);
}

If I check the value of the string long_string_test through the debbuger in the RunTask function I find that it has a strange value, as if the string had been destroyed.
But the destructor of Task class was never called.

If I change the “main.cpp” as below the program works correctly, I think the compiler does some sort of optimization:

static bool Init_task() { }

Task task(Init_task);

void main()
{
    vTaskStartScheduler();
    
    //We should never get here as control is now taken by the FreeRTOS scheduler
    while(1);
}

p.s. obviously compiler optimizations are disabled

First thing I note is Task task(Init_task) is declared on the stack of main. Depending on the FreeRTOS port you are using you may find that stack is recovered for re-use as an interrupt stack - that will cause you lots of issues.

Other than that I recommend you re-post with C++ in the subject line - then those who use FreeRTOS in CPP applications (which I don’t) are more likely to see and reply.

1 Like

Looks like like this may already be resolved here: https://stackoverflow.com/questions/60060627/compiler-optimization-problem-with-freertos

1 Like

As Richard Barry said, objects on the main stack can cause problems as some ports reclaim that stack for the interrupts, which could yield to the corruption you saw.

Another thing to watch out for, string will internally use new which will call malloc. Unless you do something about it, malloc is likely not thread safe (unless your implementation is designed to use FreeRTOS), but depending on the platform and the libraries they use, it may be possible to make it thread safe.

1 Like

I know, Indeed I made the “malloc()” and the “free(…)” thread safe by defining the functions “__malloc_lock(…)” and “__malloc_unlock(…)”.

Did you verify that the locks are really used i.e. your cross toolchain (newlib ?) supports the malloc locks ?

yes, I checked through the debuger. Whenever I create/destroy a string, vector, make_shared<>(), make_unique<>(), new, new[], malloc(), free() etc. it is called “__malloc_lock(…)” and “__malloc_unlock(…)”.