Почему печать в stderr вызывает ошибку сегментации при работе с ucontext?

Я работал над проектом для курса по операционным системам. Задача состояла в том, чтобы реализовать библиотеку для работы с потоками, аналогичную pthreads, но гораздо проще. Цель этого состоит в том, чтобы практиковать алгоритмы планирования. Конечный продукт .a файл. Курс окончен, и все работает просто отлично (с точки зрения функциональности).

Хотя мне стало любопытно, с какой проблемой я столкнулся. В трех разных функциях моего исходного файла, если я добавлю, например, следующую строку:

fprintf(stderr, "My lucky number is %d\n", 4);

Я получаю ошибку сегментации. То же самое не произойдет, если stdout используется вместо этого, или если форматирование не содержит никаких переменных.

Это оставляет меня с двумя основными вопросами:

  1. Почему это происходит только в трех функциях моего кода, а не в других?

  2. Может ли создание контекстов с помощью getcontext() а также makecontext()или изменение контекста с помощью setcontext() или же swapcontext() испортить стандартные файловые дескрипторы?

Моя интуиция говорит, что эти функции могут быть ответственны за это. Еще больше, если учесть тот факт, что три функции моего кода, в которых это происходит, являются функциями, которые имеют контексты, на которые переключаются другие части кода. Обычно setcontext(), хоть swapcontext() используется для перехода к планировщику, для выбора другого потока для выполнения.

Кроме того, если это так, то:

  1. Как правильно создавать потоки, используя эти функции?

В настоящее время я делаю следующее:

/*------------------------------------------------------------------------------
Funct:  Creates an execution context for the function and arguments passed.
Input:  uc      -> Pointer where the context will be created.
        funct   -> Function to be executed in the context.
        arg     -> Argument to the function.
Return: If the function succeeds, 0 will be returned. Otherwise -1.
------------------------------------------------------------------------------*/
static int create_context(ucontext_t *uc, void *funct, void *arg)
{
    if(getcontext(uc) != 0) // Gets a context "model"
    {
        return -1;
    }
    stack_t *sp = (stack_t*)malloc(STACK_SIZE); // Stack area for the execution context
    if(!sp) // A stack area is mandatory
    {
        return -1;
    }
    uc->uc_stack.ss_sp = sp; // Sets stack pointer
    uc->uc_stack.ss_size = STACK_SIZE; // Sets stack size
    uc->uc_link = &context_end; // Sets the context to go after execution

    makecontext(uc, funct, 1, arg); // "Makes everything work" (can't fail)
    return 0;
}

Этот код, вероятно, немного изменен, но изначально он представляет собой онлайн-пример использования u_context.

1 ответ

Предполагая, glibc, объяснение состоит в том, что fprintf с небуферизованным потоком (таким как stderr по умолчанию) внутренне создает буфер в стеке, который размером BUFSIZE байт. Смотрите функцию buffered_vfprintf в stdio-common/vfprintf.c, BUFSIZ 8192, так что в итоге вы переполняете стек, потому что созданный вами стек слишком мал.

Другие вопросы по тегам