【问题标题】:C Thread scheduling (and asm)C 线程调度(和 asm)
【发布时间】:2017-11-12 11:27:13
【问题描述】:

我目前正在编写自己的线程库。而且我无法调试未处理的异常“堆栈 cookie 检测代码检测到基于堆栈的缓冲区溢出”。下面是导致未处理异常的代码

void Scheduler()
{

  void *curr_esp;
  TCB* next_thread = ready_queue->data;
  popFront(&ready_queue);
  __asm
  {
pushad
mov curr_esp, esp
  }
  curr_thread->esp = curr_esp;

  if (curr_thread->status == RUNNING)
  {
    curr_thread->status = READY;
    Enqueue(curr_thread, &ready_queue);

  }

  curr_thread = next_thread;

  if (curr_thread->status == READY)
  {
    curr_thread->status = RUNNING;

    curr_esp = next_thread->esp;
__asm
{
  mov esp, curr_esp
  popad
}

 }

 else if (curr_thread->status == NEW)
 {
    curr_thread->status = RUNNING;
    curr_thread->params = (curr_thread->fn)(curr_thread->params);
    __asm
    {
      mov esp,curr_esp
    }
    if (curr_thread->status == RUNNING)
    {
       thread_exit(curr_thread->params);
    }

  }
}

这是执行应该运行 threadlib 和 thd_yield 的主要自旋功能,基本上只是调用我的调度程序

void *spin1(void *a)
{
    int i;
    for(i=0;i< 20; i++)
    {
        printf("SPIN1\n");
        if((i+1)%4==0)
            thd_yield();
    }
    return NULL;
}

void* spin2(void *a)
{
    int i;
    for(i=0;i< 20; i++)
    {
        printf("SPIN2\n");
        if((i+1)%4==0)
            thd_yield();
    }
    return NULL;
}


 int main()
{       
    thread_id_ id;
    thd_init();
    id = new_thd(spin2, NULL);
    spin1(NULL);
}

输出应该是5组4个“spin1”s和“spin2”s交替。

旋转1 自旋1 自旋1 自旋1 自旋2 自旋2 自旋2 自旋2 自旋1 ..

该代码对于前两组“spin1”和 1 工作得非常好,但在第二组“spin2”上给了我一个未处理的异常。我检查了正在存储和检索的堆栈指针,它们被正确存储和检索,链表存储和内存分配。更糟糕的是,我没有显示哪条线导致了错误。

注意:我不允许使用任何线程系统调用,它必须在 C 中。

如果有帮助,这是我的 TCB 结构

typedef struct _TCB_
{
  /* Unique ID*/
  thread_id_ id;
  /* Thread status*/
  enum ThreadState status;
  /* ID of next thread*/
  thread_id_ wait_id;

  void *esp;

  void *(*fn)(void*);

  void *params;

  void *stack;

}TCB;

如果我的源文件能帮助你解决这个问题,我很乐意分享。

【问题讨论】:

标签: c multithreading assembly variable-assignment


【解决方案1】:

简而言之,堆栈 cookie 受到了干扰。

堆栈cookie在执行函数代码之前计算并存储在当前堆栈帧的末尾。当功能代码执行结束时,它正在被验证。如果缓冲区溢出,它将被覆盖并且验证失败。这就是它无法向您报告导致问题的线路的原因。

在您的情况下,此异常可能有多种原因。由于没有完整的代码很难判断,我会做一些假设:

  • 您实际上可能有一个缓冲区溢出。最简单的测试方法是禁用 stack cookie 安全检查,看看是否有“访问冲突”异常。即使您不这样做,它仍然可能是缓冲区溢出
  • 不同线程的堆栈指针指向重叠的内存区域。如果您没有为堆栈分配足够的内存,则可能会发生这种情况 - 这无论如何都是缓冲区溢出
  • 不太可能,但您的代码可能是正确的,但它与 stack cookie 安全检查不兼容,因此您必须使其兼容或禁用检查。这里唯一的建议是启用 Assembler Output 并检查它。

【讨论】:

  • 嗨!感谢您的回答。如果可能的话,我可以把我的源文件发给你吗?也许你能发现一些我几个小时都看不到的东西。
  • 我真的觉得你的学习最好自己发现。
  • 我已经尝试了我能想到的一切,这就是我在这里发帖的原因。我通常能够调试自己的工作,但这真的感觉就像把我的头撞到墙上一样。我已经做了我能想到的一切。重写我的链表,重写整个调度程序(现在 4 次),使用内存诊断工具检查无意的内存分配和释放,所有检查都正确。检查我通过 asm 操作的堆栈指针。而且我仍然看不出有什么不对。
  • @DanA:尝试禁用堆栈 cookie。您正在使用内联汇编来交换线程堆栈,所以我认为 clover 的第三点最有可能并且堆栈检查可能会破坏您原本可以的代码。 OTOH,在访问一些局部变量的代码中间换出 ​​esp 和 ebp 似乎很冒险。一定要检查编译器生成的 asm。您可能需要在 asm 中编写更多的上下文切换。
猜你喜欢
  • 1970-01-01
  • 2018-08-14
  • 2012-04-23
  • 2017-05-15
  • 1970-01-01
  • 2017-03-24
  • 2013-02-24
  • 2011-02-09
  • 1970-01-01
相关资源
最近更新 更多