处理的异常可能导致内存泄漏? (使用调用 exit() 的异常处理。)

Possible memory leak from a handled exception? (With exception handling that calls exit().)

我正在开发一个 C++ 应用程序(大学的 OpenSSL 作业),并且我正在 运行 通过 valgrind 完成它,正如我所做的那样。当程序由于无效输入而失败时,我注意到一些相当奇怪的输出:

==1739== HEAP SUMMARY:
==1739==     in use at exit: 588 bytes in 6 blocks
==1739==   total heap usage: 52 allocs, 46 frees, 99,206 bytes allocated
==1739== 
==1739== 44 bytes in 1 blocks are possibly lost in loss record 3 of 6
==1739==    at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1739==    by 0x4C20378: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==1739==    by 0x4C03187: std::logic_error::logic_error(char const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==1739==    by 0x4C0325C: std::invalid_argument::invalid_argument(char const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==1739==    by 0x10FB6D: lab2::cryptoEngine::CBCCryptoEngine::encrypt() (CBCCryptoEngine.cpp:39)
==1739==    by 0x10E355: main (main.cpp:135)
==1739== 
==1739== 144 bytes in 1 blocks are possibly lost in loss record 4 of 6
==1739==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1739==    by 0x4BDB1F3: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==1739==    by 0x10FB5B: lab2::cryptoEngine::CBCCryptoEngine::encrypt() (CBCCryptoEngine.cpp:39)
==1739==    by 0x10E355: main (main.cpp:135)
==1739== 
==1739== LEAK SUMMARY:
==1739==    definitely lost: 0 bytes in 0 blocks
==1739==    indirectly lost: 0 bytes in 0 blocks
==1739==      possibly lost: 188 bytes in 2 blocks
==1739==    still reachable: 400 bytes in 4 blocks
==1739==                       of which reachable via heuristic:
==1739==                         stdstring          : 44 bytes in 1 blocks
==1739==         suppressed: 0 bytes in 0 blocks
==1739== Reachable blocks (those to which a pointer was found) are not shown.
==1739== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==1739== 
==1739== For lists of detected and suppressed errors, rerun with: -s

导致它的代码只是在输入文件无效时抛出的常规异常。像这样正确捕获异常:

try {
    engine.encrypt(bad_argument); // Placeholder. The exception type stands, though...
}
catch (const std::invalid_argument &e) {
    std::cerr << "Exception while encrypting file: " << e.what() << std::endl;
    delete (engine);
    exit(EXIT_FAILURE);
}

我不是 100% 确定它是什么意思,如果它甚至是一个问题,因为无论如何内存都会被 OS 回收。但是我从来没有见过这种东西,想看看。

所以,我的问题是,它是由什么引起的?我应该修理它吗?如果可以,怎么做?

exit 或多或少会丢失静态存储持续时间对象不递归拥有的所有内容。当然,这包括堆栈上事物递归拥有的所有内容,还包括活动异常对象(其内存以未指定的方式分配)。在这种特殊情况下,您丢失了一个由活动异常对象拥有的 std::string 拥有的缓冲区。

如果您关心这些事情,请不要在事情中间使用 exit。重新抛出异常,在 main 中捕获它,让处理程序完成,然后 然后 调用 exit (或者自然地退出 main )。你可能不应该,因为这不是真正的泄漏(即程序 没有分配和丢失内存,而它仍然是 运行)。

std::logic_error's constructor 为“解释字符串”分配了内存。这对你来说是 what() returns,在异常处理程序中(std::invalid_argument 继承自 std::logic_error)。

观察回溯显示构造函数重载采用 const char * 作为参数。如果那个文字 const char * 被藏起来,然后从 what() 交还给你,那是可以接受的。然而,构造函数被编码为复制“解释性字符串”以使其内容完全由构造的 std::logic_error.

拥有的原因有很多。

您的异常处理程序悄悄地调用了 exit() 并且进程终止了。此时 valgrind 通知您上述分配的内存未被破坏。这是真的,内存没有被释放。

如果您的异常处理程序的作用域自然结束(不调用 exit()),std::logic_error 的析构函数会删除分配的内存,从此以后每个人都会过上幸福的生活。

TLDR:这只是技术性内存泄漏。这在技术上是正确的,只是因为地毯是通过调用 exit.

从过程中拉出来的

请注意,valgrind 说的是“可能”而不是“肯定”。毫无疑问,当 valgrind“肯定”声称存在内存泄漏时,您会发生内存泄漏。如果它只是“可能”,那么可能存在也可能不存在真正的内存泄漏。