线程堆栈溢出

时间:2009-08-20 05:35:24

标签: c stack-overflow task vxworks

在像我们创建任务的vxworks这样的RTO中,指定了stacksize。我们可以在C中编写一个例程来检查堆栈是否溢出或者没有执行任务吗?

7 个答案:

答案 0 :(得分:4)

看看你的编译器,他们经常会让你添加prelude函数来执行此操作,或者他们甚至可以自己检查它,除非你操作堆栈指针寄存器。

并检查操作系统是否允许您安装“guard-pages”。将线程堆栈中的最后一页标记为非读取/非写入并捕获SIGSEGV信号并使用特定于OS / CPU的方式来确定它是否是失败的保护页面。为此,您必须确保函数的堆栈框架(堆栈传递参数,局部变量和分配的已分配空间)始终小于页面大小,否则您可以跳过“防护页面” 这是处理它的最佳方法,因为它在正常处理期间没有运行时开销。

您会看到这种高度的OS / CPU /编译器依赖。但我很确定google会为所有系统找到可用的代码和帮助程序,因为它是低级程序员(例如运行时或解释器实现者)的常用技术。

答案 1 :(得分:3)

如果你知道堆栈有多大,如果你小心,那么是(但不是便携)。如果没有其他方法可以获得堆栈的基址,则需要在线程的main函数中记录堆栈变量的地址;这使您可以近似堆栈的顶部。然后,在您的检查功能中,您获取局部变量的地址;这给了你堆栈的底部。如果顶部和底部之间的差异与您的堆栈大小有关,那么现在是时候担心;如果差异大于堆栈大小,则担心已经太晚了 - 损坏已经完成(但现在你需要考虑如何清理)。

答案 2 :(得分:3)

仅供参考,您可以使用checkStack()从VxWorks中的shell执行类似的操作。

答案 3 :(得分:0)

您可以使用一些技术 - 通常您有一个低优先级的任务,每隔一秒左右嗅探所有其他任务的堆栈状态。

a:确保在任务开始之前,堆栈空间已填充已知模式。然后,您可以通过检查模式找出剩余多少“未损坏的”堆栈。

  • 优点:让您检查堆栈使用的“高水位线”。
  • 缺点:如果你分配堆栈内存,但由于某种原因不写入它,这种技术可能无法检测到溢出。

b:您可以直接嗅探所有其他线程的堆栈指针。

  • 缺点:这只是“抽样”堆栈指针,因此可能不会注意到溢出的短暂情况
  • 优势:快捷方便。

我建议两者结合使用。因为你正在使用像VxWorks TaskInfoGet()函数那样做低级的东西,所以很难让它甚至可以远程移植。

答案 4 :(得分:0)

我不知道VxWorks,但我的回忆是Green Hill的Velosity / uVelosity内核提供了执行此操作的代码。即使他们没有,因为他们提供了用户可以修改的源,并且基础设施就在那里,所以很容易添加。

编辑:为了披露,我和他们一起做了一个夏季实习,将uVelosity移植到一个新的建筑。这就是我对线程堆栈处理的亲密关系。

答案 5 :(得分:0)

如果您的特定应用程序静态分配其线程,则可以将其堆栈放置在静态定义的区域中,并使用链接器映射在这些区域的末尾放置符号。然后,您只需要获取当前的堆栈指针(如其他答案中所述),并将“堆栈段结束”指针与该地址进行比较。如果每个线程都有一些地方可以存储作为其堆栈末尾提供给它的地址,那么这也适用于动态分配。

答案 6 :(得分:-2)

堆栈大小默认为1MB,具体取决于编译器。根据这些信息,您可以尝试使用以下内容捕获剩余的堆栈:


unsigned long remaining_stack_size() {
    char dummy;
    return 0x000fffff & (unsigned long)&dummy;
    // 0x000fffff is 1MB -1 (1048576 -1)
}

编辑:请注意,它实际上返回当前堆栈位置,这是一回事。

编辑(2):对于那些说我错了的人,这里有一个概念证明:


#include <stdio.h>
#include <windows.h>

unsigned long remaining_stack_size() {
    char dummy;
    return 0x001fffff & (unsigned long)&dummy + 1; // okay, some minor adjusts
}

void recurse_to_death(unsigned long used, char *p) {
    char buf[32*1024];
    used += 32*1024;
    printf("Used: 0x%08x Remaining: 0x%08x\n", used, remaining_stack_size());
    recurse_to_death(used, buf);
}

DWORD WINAPI my_thread(void *p) {
    printf("Total stack size of this Thread: 0x%08x bytes\n", remaining_stack_size() + 72);
    recurse_to_death(0, NULL);
    return 0;
}

int main(int argc, char *argv) {
    DWORD tid;
    // CreateThread's stack size actually defaults to 1MB+64KB and does not honor lower values
    CreateThread(NULL, NULL, my_thread, NULL, NULL, NULL);
    Sleep(30000);
    return 0;
}

remaining_stack_size()预测堆栈溢出完美。