【问题标题】:Why does printing to stderr cause segmentation fault when dealing with ucontext?为什么在处理ucontext时打印到stderr会导致分段错误?
【发布时间】:2018-12-23 01:34:23
【问题描述】:

我正在为操作系统课程做一个项目。任务是实现一个处理线程的库,类似于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的在线示例。

【问题讨论】:

  • 我猜你有某种形式的内存损坏或竞争条件;这通常是添加或删除看似无害的行导致错误的原因。
  • STACK_SIZE的值是多少?
  • STACK_SIZE 是 8192 字节。此外,context_end 的创建方式也很相似。
  • @YuriJ:这可能不足以调用fprintf 函数。您使用的是什么操作系统(如果是 Linux,则使用什么 libc)?
  • @YuriJ,尝试解决这些泄漏。您可能会发现错误!

标签: c posix ucontext


【解决方案1】:

假设 glibc,解释是 fprintf 带有一个无缓冲的流(例如默认为 stderr)在内部创建一个大小为 BUFSIZE 字节的堆栈缓冲区。请参阅stdio-common/vfprintf.c 中的函数buffered_vfprintfBUFSIZ 是 8192,所以你最终会出现堆栈溢出,因为你创建的堆栈太小了。

【讨论】:

  • 这发生在我的 arm-linux 目标上(在 x86-64 Linux 上运行良好),将 stderr 更改为 stdout 确实阻止了崩溃。虽然我不明白为什么会发生这种情况,因为这只发生在一个函数的一个实例中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-25
  • 2021-07-18
  • 2020-04-15
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多