如何捕捉C++代码中的奇怪未定义行为?

4

我在服务器程序中遇到了奇怪的行为。在简单的示例中,它可以正常工作(我在pion和asio中添加了跟踪)。

#include <pion/http/server.hpp>
#include <pion/http/response_writer.hpp>
#include <pion/http/response_reader.hpp>
#include <pion/http/request_writer.hpp>
#include <pion/logger.hpp>
#include <pion/scheduler.hpp>

int main()
{
   pion::single_service_scheduler shed;
   shed.set_num_threads(1);
   boost::shared_ptr<pion::http::server> server
   (new pion::http::server(shed, 5000));
   server->add_resource("/", handlerFunction);
   server->start();
   sleep(5);
}

输出如下。构造接收器套接字,为客户端构造套接字,创建TCP连接,一切正常运行。
basic io object constructor
after service construct
basic io object constructor
after service construct
basic io object constructor
Address of socket is: 0x9855fa4 value: -1
after service construct
1422519945 INFO pion.http.server Added request handler for HTTP resource: 
1422519945 INFO pion.http.server Starting server on port 5000
before connection create
before connection constructor called
basic io object constructor
basic_stream_socket::construct
Address of socket is: 0x9857514 value: -1
after impl.construct
after service construct
basic io object constructor
after service construct
basic io object constructor
after service construct
ssl socket constructed
connection constructor, is_ssl: 0
after connection create: 0x98574f8
before accept
after accept

在使用 Oracle 和许多其他库的更复杂的程序中,相同的代码输出如下。
basic io object constructor
after service construct
basic io object constructor
after service construct
basic io object constructor
Address of socket is: 0xbfe47a64 value: -1
after service construct
1422525476 INFO pion.http.server Added request handler for HTTP resource: 
before connection create
basic io object constructor
after service construct
basic io object constructor
after service construct
after connection create: 0x8fe8b88
before accept
in connection::async_accept
after accept

实际上,并没有创建第二个socket,也没有调用connection::create函数,但是您可以看到连接已经有地址。我的想法是,某个地方可能会将函数connection::create的地址写入(或类似的操作)。请问如何捕获这种情况?


3
假设clanggcc拥有sanitizer在这里在这里 - Shafik Yaghmour
@ShafikYaghmour 谢谢,但是目前Ubuntu还没有gcc 4.9版本(在稳定仓库中),而且重新构建所有gcc 4.9的库需要一些时间。从我所看到的情况来看,应该使用clang sanitizer,并加上-stdlib=libc++参数,但是pion内部使用的是tr1/unordered_map。 - ForEveR
只是构建时出了些问题,有些库使用了C++11,有些没有... 没有C++11的一切都正常... - ForEveR
哦,有趣,这个问题是相关的。 - Shafik Yaghmour
1个回答

2
在Ubuntu上,我喜欢使用valgrindhttp://valgrind.org/)进行运行。
sudo apt-get install valgrind
valgrind ./mypgrogram

虽然它不能报告所有问题,但当它报告时,它会报告问题的性质和来源。

同时建议:

valgrind --db-attach=yes ./myprogram

当检测到违规/未初始化内存引用时,它允许您进行调试(backtrace、检查)并继续程序。

On some older Ubunti I had to use sudo to make valgrind be able to attach gdb:

sudo -E valgrind --db-attach=yes ./myprogram
如果要将tr1/unordered_map替换为std::unordered_map,应该是非常简单的。
例如,可以通过快速的hack实现。
#include <unordered_map>

namespace std { namespace tr1 {

    using std::unordered_map;
    using std::hash;
    // etc...
} }
    

当然,这不是一个好的做法,你可能只想在std::unordered_mapstd::tr1::unordered_map之间进行typedef,但为了快速检查...


你提到的Oracle库可能存在抑制规则。此外,你也可以将Oracle从循环中剔除(分而治之)。 - sehe
实际上,现在我无法在我的机器上重现这种情况,删除所有痕迹等等,但是不行... 可能是月相被替换了... - ForEveR
复现了问题,但是使用Valgrind和db-attach只显示实现中未初始化的变量,对于connection::create没有任何想法...它根本没有被调用。 - ForEveR
仅提供一种方式,我个人认为:保持不断缩减(通过逐步消除更多内容或从新项目开始并添加内容直到出现故障)。特别注意共享库的兼容性等问题。 - sehe
有点困难,但我会尝试做到。谢谢。 - ForEveR
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接