【问题标题】:libuv + C++ segfaultslibuv + C++ 段错误
【发布时间】:2015-03-28 16:11:58
【问题描述】:

我正在使用 libuv 为 C++ 中的流编写一个包装器,但它会出现段错误,我无法找出原因。流类:

class Stream{
  public:
  Stream(int fd);

  void Write(const std::string& data, const std::function<void(void)>& callback);


  const static int STDIN = 0;
  const static int STDOUT = 1;
  private:
  static void OnWrite(uv_write_t *req, int status);
  uv_pipe_t pipe;
};

以及实现

Stream::Stream(int fd){
  uv_pipe_init(uv_default_loop(), &pipe, 0);
  uv_pipe_open(&pipe, fd);
}

void Stream::Write(const std::string& data, const std::function<void(void)>& callback){
  uv_write_t request;
  uv_buf_t buffer = uv_buf_init((char*)malloc(data.length()*sizeof(char)), data.length());
  strcpy(buffer.base, data.c_str());
  buffer.len = data.length();
  uv_write(&request, (uv_stream_t*)&pipe, &buffer, 1, OnWrite);
}

void Stream::OnWrite(uv_write_t *req, int status){

}

在主文件中我这样做:

Stream* out = new Stream(Stream::STDOUT);
  out->Write("Hello, World!", []() {
});

uv_run(uv_default_loop(), RUN_DEFAULT);

但是,一旦我运行它,它就会在 uv_run 语句上出现段错误。回溯:

#0  0x00007ffff7bcac94 in uv__write_callbacks (stream=stream@entry=0x603010) at src/unix/stream.c:907
#1  0x00007ffff7bcb0a1 in uv__stream_io (loop=<optimized out>, w=0x603098, events=<optimized out>) at src/unix/stream.c:1243
#2  0x00007ffff7bc31eb in uv__run_pending (loop=0x7ffff7dd98c0 <default_loop_struct>) at src/unix/core.c:710
#3  uv_run (loop=0x7ffff7dd98c0 <default_loop_struct>, mode=UV_RUN_DEFAULT) at src/unix/core.c:316
#4  0x0000000000400fcd in main ()

但是,如果我将 uv_run 放在 Stream::Write 方法中,它就可以正常工作。我该如何解决这个问题?


编辑

我现在在堆上而不是在堆栈上分配管道,但它仍然给我一个段错误。我把header里的uv_pipe_t改成了uv_pipe_t*,现在实现改成这样:

Stream::Stream(int fd){
  pipe = new uv_pipe_t;
  uv_pipe_init(uv_default_loop(), pipe, 0);
  uv_pipe_open(pipe, fd);
}

void Stream::Write(const std::string& data, const std::function<void(void)>& callback){
  uv_write_t request;
  uv_buf_t buffer = uv_buf_init((char*)data.c_str(), data.length());
  uv_write(&request, (uv_stream_t*)pipe, &buffer, 1, OnWrite);
}

void Stream::OnWrite(uv_write_t *req, int status){
  delete req;
}

来自 GDB 的回溯:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bcac94 in uv__write_callbacks (stream=stream@entry=0x603030) at src/unix/stream.c:907
907         uv__req_unregister(stream->loop, req);
(gdb) backtrace
#0  0x00007ffff7bcac94 in uv__write_callbacks (stream=stream@entry=0x603030) at src/unix/stream.c:907
#1  0x00007ffff7bcb0a1 in uv__stream_io (loop=<optimized out>, w=0x6030b8, events=<optimized out>) at src/unix/stream.c:1243
#2  0x00007ffff7bc31eb in uv__run_pending (loop=0x7ffff7dd98c0 <default_loop_struct>) at src/unix/core.c:710
#3  uv_run (loop=0x7ffff7dd98c0 <default_loop_struct>, mode=UV_RUN_DEFAULT) at src/unix/core.c:316
#4  0x0000000000400f4d in main ()

【问题讨论】:

    标签: c++ libuv


    【解决方案1】:

    你的“写请求”(uv_write_t)是在栈上分配的,当 libuv 试图将它的指针传递给写回调函数时(或者,事实上当 libuv 自己试图使用它时),你的“写请求”(uv_write_t)将不存在。请记住,libuv 中的一切都是异步的;这可能就是你使用它的原因!

    您应该在堆上分配您的uv_write_t(或作为全局/类变量或从池或其他任何地方)并记住在写回调中释放它。

    您的程序中还有另一个内存/生命周期错误,但这不是崩溃错误,而是产生垃圾的错误。你malloc 放入uv_buffer_t 的缓冲区是不需要的,可以在调用后立即释放(这是同步的!)真的,你甚至不需要分配一个单独的缓冲区;您可以将data.c_str() 作为第一个参数传递给uv_buf_init()

    【讨论】:

    • 我更改了您建议的内容,但现在仍然存在段错误。请查看我的(已编辑)原帖
    • 对不起,财产没有阅读你的答案,但它确实修复了它。 (我在堆上分配了管道而不是请求)
    猜你喜欢
    • 1970-01-01
    • 2018-07-04
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    相关资源
    最近更新 更多