隔离崩溃倾向 (SEGV),但将关键遗留代码加速到单独的二进制文件中

Posted

技术标签:

【中文标题】隔离崩溃倾向 (SEGV),但将关键遗留代码加速到单独的二进制文件中【英文标题】:Isolate crash prone (SEGV) but speed critical legacy code into a separate binary 【发布时间】:2016-03-28 15:11:34 【问题描述】:

我有一个经过良好测试且无崩溃的代码库(主要是 C++)。大多。代码的一部分——不可替代、难以维护或改进以及链接到仅二进制库*——会导致所有崩溃。这些不会经常发生,但一旦发生,整个程序就会崩溃。

          +----------------------+
          | Shiny new sane       |
          |  code base           |
          |                      |
          |  +-----------------+ |   If the legacy code crashes,
          |  |                 | |   the entire program does, too.
          |  |   Legacy Code   | |
          |  | * Crash prone * | |
          |  | int abc(data)   | |
          |  +-----------------+ |
          |                      |
          +----------------------+

是否可以将那部分代码提取到一个单独的程序中,从主程序启动,在这些程序之间移动数据(在 Linux、OS X 和,如果可能的话,Windows 上),容忍子程序崩溃处理并重新启动孩子?像这样的:

        +----------------+         // start,
        | Shiny new sane | ------. // re-start on crash
        |  code base     |       | //   and
        |                |       v // input data
        |                |    +-----------------+
        |   return       |    |                 |
        |   results <-------- |   Legacy Code   |
        +----------------+    | * Crash prone * |
                              |  int abc(data)  |
       (or not results        +-----------------+
        because abc crashed)

理想情况下,通信应该足够快,以便可以用包装器透明地替换对int abc(char *data) 的同步调用(假设非崩溃情况)。并且由于轻微的内存泄漏,遗留程序应该每隔一小时左右重新启动一次。崩溃是确定性的,因此不应发送两次错误的输入数据。

代码库是 C++11 和 C,著名的外部库是 Qt 和 boost。它可以在 Linux、OSX 和 Windows 上运行。

-- *:一些崩溃/泄漏源于该库,该库没有可用的源代码。

【问题讨论】:

我的建议是重写遗留代码 - 这将是一个比试图解决它崩溃的问题更好的解决方案。 很遗憾,重写是绝对不可能,它需要太多非常专业的知识,而编写它的人已经不在了。 你有密码。你可以看到它的作用。可能需要多少专业知识?它是否可提取取决于代码 - 如果您对它的理解不足以重写它,那么您对它的理解就不足以确定您对它所做的任何事情都是安全的。 您可以使用一些套接字,如果Shiny 无法连接,他会启动旧版。旧版收听、等待数据并使用int 回答。客户端等待应答,万一连接丢失,数据触发bug,请勿重试。 Catch Segfault or any other errors/exceptions/signals in C++ like catching exceptions in Java的可能重复 【参考方案1】:

好吧,如果我是你,我不会从这里开始......

然而,你在哪里。是的,你可以做到。你将不得不序列化你的输入参数,发送它们,在子进程中反序列化它们,运行函数,序列化输出,返回它们,然后反序列化它们。 Boost 将有很多有用的代码来帮助解决这个问题(参见 asio)。

全局变量将使生活更加“有趣”。遗留代码是否使用 Qt? - 那可能不喜欢被分成两个进程。

如果您只使用 Windows,我会说“使用 DCOM”——它使这变得非常简单。

如果仅从一个线程使用遗留系统,则重新启动非常简单(处理“返回”的代码只是查看它是否需要重新启动,并终止进程。)如果您有多个线程,那么闪亮的代码将需要检查是否需要重新启动,阻塞任何其他线程,等待所有调用返回,重新启动进程,然后解除阻塞。

Boost::interprocess 看起来拥有通信所需的一切——它有共享内存、互斥体和条件变量。 Boost::serialization 将完成编组和解组的工作。

【讨论】:

在遗留方面没有全局变量或 Qt,只有一两个纯函数感兴趣。 tcp/udp 套接字是唯一的可移植方式吗?共享内存和信号会想到其他低级工具。 sockets 无疑是最便携的方式。 Boost 有一个共享内存库,所以它应该可以工作。不了解信号,它们在 posix/Windows 世界中非常不同。如果您的参数/结果包含指针或具有虚函数,您仍然需要序列化/反序列化(无论如何这可能是个好主意 - 否则版本偏差会导致噩梦般的问题)。

以上是关于隔离崩溃倾向 (SEGV),但将关键遗留代码加速到单独的二进制文件中的主要内容,如果未能解决你的问题,请参考以下文章

MobileAds.initialize(this) 崩溃 致命信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR)

SIGSEGV SEGV_ACCERR 崩溃报告 - 怎么办?

sigsegv segv_accerr 在 ios7 中崩溃 mkmapview

当自动释放池耗尽时,NSFileAttributes dealloc 中的 SIGSEGV SEGV_ACCERR 崩溃?

信号11(SIGSEGV),代码1(SEGV_MAPERR),故障地址0x7f4485ff1820

java.lang.Error:信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR) Android 应用