`main` 函数堆栈中的对象在第一个任务运行时被覆盖 (FreeRTOS)

Object in stack of `main` function is overwritten when first task runs (FreeRTOS)

我试着用一个简单的例子来解释我的问题

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);
}

如果我通过 RunTask 函数中的调试器检查字符串 long_string_test 的值,我发现它有一个奇怪的值,就好像该字符串已被破坏。 但是 Task class 的析构函数从未被调用过。

如果我按如下所示更改 "main.cpp",程序将正常运行,我认为编译器会进行某种优化:

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。显然编译器优化被禁用

作为 vTaskStartScheduler 调用的一部分,prvPortStartFirstTaskreset the stack pointer。我可以想象,这最终会导致其他代码覆盖分配给 main 的废弃堆栈 space 上的 Task 对象的部分内容。您可以使用调试器设置数据断点,但我会认为 main 堆栈 space 在第一个任务开始时被丢弃。

我认为这里最好的解决方案确实是静态分配 Task 对象或可能使用堆分配(如果您的系统允许的话)。

@Botje 你是对的我改变了我的例子来验证你说的。

main.cpp

int* test;

static void RunTask(void* params)
{
    Print(*test);  //The "test" pointer has a random value
}

void main()
{
    int temp = 9999;

    test = &temp;

    xTaskCreate(RunTask, "task_name", 2560, NULL, 3, NULL);

    vTaskStartScheduler(); //It seems that FreeRTOS clears the main() stack

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