简体   繁体   中英

Why does printing to stderr cause segmentation fault when dealing with ucontext?

I was working on a project for a course on Operating Systems. The task was to implement a library for dealing with threads, similar to pthreads , but much more simpler. The purpose of it is to practice scheduling algorithms. The final product is a .a file. The course is over and everything worked just fine (in terms of functionality).

Though, I got curious about an issue I faced. On three different functions of my source file, if I add the following line, for instance:

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

I get a segmentation fault. The same doesn't happen if stdout is used instead, or if the formatting doesn't contain any variables.

That leaves me with two main questions:

  1. Why does it only happen in three functions of my code, and not the others?

  2. Could the creation of contexts using getcontext() and makecontext() , or the changing of contexts using setcontext() or swapcontext() mess up with the standard file descriptors?

My intuition says those functions could be responsible for that. Even more when given the fact that the three functions of my code in which this happens are functions that have contexts which other parts of the code switch to. Usually by setcontext() , though swapcontext() is used to go to the scheduler, for choosing another thread to execute.

Additionally, if that is the case, then:

  1. What is the proper way to create threads using those functions?

I'm currently doing the following:

/*------------------------------------------------------------------------------
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;
}

This code is probably a little modified, but it is originally an online example on how to use u_context.

Assuming glibc, the explanation is that fprintf with an unbuffered stream (such as stderr by default) internally creates an on-stack buffer which as a size of BUFSIZE bytes. See the function buffered_vfprintf in stdio-common/vfprintf.c . BUFSIZ is 8192, so you end up with a stack overflow because the stack you create is too small.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM