防御用户脚本的堆栈溢出

Defending against stack overflow by user scripts

C++ 的堆栈有限 space 但函数无法检查是否有足够的 space 留给它们 运行。我在编写脚本绑定时不知道该怎么做。

例如:

class Container : Widget {
  void addChild(WidgetPtr child) { ... }

  void draw(Canvas& canvas) {
    for (auto child : m_children) {
      child.draw();
    }
  }
};

恶意脚本可以执行此操作使程序崩溃:

var a = new Container()
for (i = 0; i < 10000000; i++) {
  var b = new Container()
  a.addChild(b)
  a = b
}

a.draw() // 10000000 nested calls ---> stack overflow

还有回调问题:

void doSomething(std::function<void()> callback) {
  callback();
}

如果使用这样的方式包装:

ScriptValue doSomething_Wrapper(ScriptArgs args) {
  doSomething([&]() { args[0].callAsFunction(); });
}

崩溃使用:

function badCallback() { doSomething(badCallback) }
doSomething(badCallback)

...
doSomething_Wrapper
doSomething
ScriptValue::callAsFunction
...
doSomething_Wrapper
doSomething
ScriptValue::callAsFunction
...
BOOM!

以最少的不便来抵御这种情况的最惯用的方法是什么?

用 C++(Firefox、Chrome)编写的浏览器有什么作用?

我该怎么做才能不意外地引入这样的漏洞?

虽然 "malicious" 脚本可能会导致堆栈溢出,就像您所描述的那样,但它对程序的危害不会超过导致崩溃的方式(至少在堆栈限制的现代 OS实际上已经过检查,因此可以安全地防止覆盖其他重要数据)。

如果程序一直 运行 至关重要,则必须有另一个进程监视它(并在必要时重新启动它。不仅因为堆栈溢出,还有更多潜在问题。) .
除此之外,如果使用 OS 堆栈,则无能为力。为堆栈中的单个指针动态分配一个大内存块并在此块中手动进行整个内存管理是可能的,但可能不切实际。

关于例如。 FIrefox:至少部分程序使用了自己的内存管理(但我不确定它是否与插件、脚本等相关)。此外,还有一个单独的进程 plugin-container.exe(至少在 Windows 上),杀死不会杀死 Firefox(只有 Flash 等插件部分不再工作,用户会收到一条消息关于插件崩溃)。