Объект в стеке функции `main` перезаписывается при запуске первой задачи (FreeRTOS) - PullRequest
0 голосов
/ 04 февраля 2020

Я пытаюсь объяснить мою проблему на простом примере

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

Если я проверяю значение строки long_string_test через отладчик в функции RunTask я обнаружил, что она имеет странное значение, как если бы строка была уничтожена. Но деструктор класса Task никогда не вызывался.

Если я изменю "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);
}

ps очевидно, что оптимизация компилятора отключена

Ответы [ 2 ]

3 голосов
/ 04 февраля 2020

Как часть вызова vTaskStartScheduler, prvPortStartFirstTask будет сбрасывать указатель стека . Я могу себе представить, что это в конечном итоге приведет к тому, что другой код перезапишет части объекта Task в отброшенном пространстве стека, выделенном для main. Вы можете установить точку останова данных с помощью отладчика, но я бы посчитал, что пространство стека main уничтожено при запуске первой задачи.

Я думаю, что лучшим решением здесь действительно является статическое выделение объекта Task или возможно с распределением кучи (если ваша система это позволяет).

1 голос
/ 04 февраля 2020

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