【问题标题】:Crashing C++ application on production machine due to segmentation fault由于分段错误,生产机器上的 C++ 应用程序崩溃
【发布时间】:2013-01-08 07:28:05
【问题描述】:

由于 RED hat Linux 上的分段错误,我们面临 C++ 应用程序崩溃问题。我们在 C++ 中使用嵌入式 python。

请在下面找到我的限制

  1. 我无法访问应用程序崩溃的生产机器。当应用程序崩溃时,客户端会向我们发送核心转储文件。
  2. 问题在我们的测试机器上无法重现,它的配置与生产机器完全相同。
  3. 有时应用程序在 1 小时、4 小时 ....1 天或 1 周后崩溃。我们没有得到应用程序崩溃的时间框架或任何特定模式。
  4. 应用程序很复杂,应用程序内的许多地方都使用了嵌入式 Python 代码。我们进行了广泛的代码审查,但无法通过代码审查找到解决办法。
  5. 根据核心转储中的堆栈跟踪,它在乘法操作附近崩溃,在代码中审查了此类操作的代码,我们没有得到任何执行此类操作的代码。可能是此类操作是通过从我们无法控制或无法查看的嵌入式 python 执行的 python 脚本调用的。
  6. 我们无法在 Valgrind 等生产环境中使用任何分析工具。
  7. 我们在本地机器上使用 gdb 来分析核心转储。我们无法在生产机器上运行 gdb。

请在下方查看我们所做的努力。

  1. 我们已经分析了日志并不断地向我们的测试环境中的应用程序发出请求以重现问题。
  2. 我们没有在日志中发现崩溃点。每次我们得到不同的日志。我认为这是由于;内存在其他地方被破坏,应用程序在一段时间后崩溃。
  3. 我们在应用程序的任何时候都检查过负载,并且从未超过我们的应用程序限制。
  4. 我们的应用程序的内存利用率也很正常。
  5. 我们在 Valgrind 的帮助下在我们的测试机器中分析了我们的应用程序,并删除了 valgrind 错误,但应用程序仍然崩溃。

感谢任何帮助指导我们进一步解决问题的帮助。

以下是版本详情

红帽 linux 服务器 5.6 (Tikanga) Python 2.6.2 GCC 4.1

以下是我从他们共享的核心转储文件中获得的堆栈跟踪(在我的机器上)。仅供参考,我们无权访问生产机器以在核心转储文件上运行 gdb。

0  0x00000033c6678630 in ?? ()
1  0x00002b59d0e9501e in PyString_FromFormatV (format=0x2b59d0f2ab00 "can't multiply sequence by non-int of type '%.200s'", vargs=0x46421f20) at Objects/stringobject.c:291
2  0x00002b59d0ef1620 in PyErr_Format (exception=0x2b59d1170bc0, format=<value optimized out>) at Python/errors.c:548
3  0x00002b59d0e4bf1c in PyNumber_Multiply (v=0x2aaaac080600, w=0x2b59d116a550) at Objects/abstract.c:1192
4  0x00002b59d0ede326 in PyEval_EvalFrameEx (f=0x732b670, throwflag=<value optimized out>) at Python/ceval.c:1119
5  0x00002b59d0ee2493 in call_function (f=0x7269330, throwflag=<value optimized out>) at Python/ceval.c:3794
6  PyEval_EvalFrameEx (f=0x7269330, throwflag=<value optimized out>) at Python/ceval.c:2389
7  0x00002b59d0ee2493 in call_function (f=0x70983f0, throwflag=<value optimized out>) at Python/ceval.c:3794
8  PyEval_EvalFrameEx (f=0x70983f0, throwflag=<value optimized out>) at Python/ceval.c:2389
9  0x00002b59d0ee2493 in call_function (f=0x6f1b500, throwflag=<value optimized out>) at Python/ceval.c:3794
10 PyEval_EvalFrameEx (f=0x6f1b500, throwflag=<value optimized out>) at Python/ceval.c:2389
11 0x00002b59d0ee2493 in call_function (f=0x2aaab09d52e0, throwflag=<value optimized out>) at Python/ceval.c:3794
12 PyEval_EvalFrameEx (f=0x2aaab09d52e0, throwflag=<value optimized out>) at Python/ceval.c:2389
13 0x00002b59d0ee2d9f in ?? () at Python/ceval.c:2968 from /usr/local/lib/libpython2.6.so.1.0
14 0x0000000000000007 in ?? ()
15 0x00002b59d0e83042 in lookdict_string (mp=<value optimized out>, key=0x46424dc0, hash=40722104) at Objects/dictobject.c:412
16 0x00002aaab09d5458 in ?? ()
17 0x00002aaab09d5458 in ?? ()
18 0x00002aaab02a91f0 in ?? ()
19 0x00002aaab0b2c3a0 in ?? ()
20 0x0000000000000004 in ?? ()
21 0x00000000026d5eb8 in ?? ()
22 0x00002aaab0b2c3a0 in ?? ()
23 0x00002aaab071e080 in ?? ()
24 0x0000000046422bf0 in ?? ()
25 0x0000000046424dc0 in ?? ()
26 0x00000000026d5eb8 in ?? ()
27 0x00002aaab0987710 in ?? ()
28 0x00002b59d0ee2de2 in PyEval_EvalFrame (f=0x0) at Python/ceval.c:538
29 0x0000000000000000 in ?? ()

【问题讨论】:

  • 跟踪总是一样的吗?该错误消息看起来非常具体。在某处你正试图做类似(1, 2, 3) * 2.5 的事情。这本身不是一个错误,应该很容易追踪,因为这是一种不寻常的表达方式?
  • 你使用的是什么版本的g++
  • 是的,当我们得到堆栈跟踪时,它的方式是相同的。我们已经查看了我们在 C++ 应用程序中使用的嵌入式 python 代码,但找不到这样的操作。我们还尝试从我们嵌入的 python 代码中执行 python 脚本,该代码具有无效的乘法运算,但导致 scipt 执行不成功;它不会使我们的应用程序崩溃。感谢您的评论
  • 停止!于 2007 年 2 月 13 日发布。gcc.gnu.org/releases.html
  • 使用 GCC 4.1 实在是太疯狂了。它甚至不是很好地符合 C++ 标准。它的优化很差,有一个错误的不符合标准的stdc++ 库;从那以后,GCC 取得了很多的进步。除了使用最近的 GCC (4.7) 之外,您还可以使用最近的 Clang(来自 LLVM 3.2)进行编译,以获得更多警告等......

标签: c++ python linux segmentation-fault


【解决方案1】:

您几乎可以肯定在您的 C++ 代码中做了一些使用指针的坏事,这可能很难调试。

  • 不要假设堆栈跟踪是相关的。这可能是相关的,但指针滥用通常会导致崩溃一段时间后
  • 构建时开启完整警告。编译器可以指出一些不明显的指针误用,例如返回对本地的引用。
  • 调查您的阵列。尝试用std::vector (C++03) 或std::array (C++11) 替换数组,这样您就可以使用begin()end() 进行迭代,并且可以使用at() 进行索引。
  • 调查您的指针。尽可能用std::unique_ptr(C++11) 或boost::scoped_ptr 替换它们(发布版本中应该没有开销)。将其余部分替换为 shared_ptrweak_ptr。任何无法替代的东西都可能是有问题的逻辑的根源。

由于您所看到的问题,现代 C++ 允许完全删除几乎所有原始指针使用。试试看。

【讨论】:

  • 对于固定常量维度的数组 C++2011(和 GCC 4.7)给出std::array
  • @BasileStarynkevitch 是的!我不想假设版本,但我认为这值得一提。谢谢。
【解决方案2】:

首先,使用调试符号编译您的二进制文件和libpython,然后将其推出。堆栈跟踪将更容易跟踪。

g++ 的相关参数是-g

【讨论】:

  • 是的,我们已经用 -g 选项编译了它(因为编译器是 g++)。但是我们只得到了我给出的堆栈跟踪
  • @Jack 跟踪显然来自 Python 的二进制文件,而不是您的 C++ 代码。关闭符号时,链可能会中断,因此即使您的代码此时正在调用 Python,GDB 也可能无法一直追溯到它。这可以通过将 Python 的调试版本加载到生产机器上来解决……尽管这可能会严重影响性能和/或吓坏客户。
  • 我还建议使用 g++ -Wall -g 编译您的 C++ 代码并使用最新的 GCC(例如 4.7,或即将发布的 4.8)。我建议至少使用 Python 2.7(也许是 Python 3)。
  • 最新版本的 GCC(例如 4.7)更符合 C++ 标准并提供更好的警告(尤其是 -Wall -Wextra)和更好的优化。 Python 2.6 是古老的,没有更多的工作。
  • 但是您应该使用最近的 GCC(例如 4.7)和最近的 GDB(例如 7.5)和最近的 Valgrind(3.8)。不要使用 2007 时代的软件进行开发!
【解决方案3】:

建议:

  • 如前所述,提供完整的调试版本
  • 提供内存测试工具和CPU折磨测试
  • 分析核心转储时加载python库的调试符号
  • stacktrace 显示了一些与 eval() 相关的信息,所以我猜您会进行动态代码生成和评估/执行。如果是这样,在此代码或传递的参数中,可能存在实际错误。在代码和代码转储的任何接口上的断言可能会有所帮助。

【讨论】:

  • 感谢您的建议,我将审查它周围的代码。我将与客户核实他们是否允许在生产机器上使用建议的工具。
猜你喜欢
  • 2020-07-04
  • 2023-03-26
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-09
  • 1970-01-01
相关资源
最近更新 更多