diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2023-08-29 14:50:41 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2023-08-29 14:50:58 (GMT) |
commit | b938e7de9c21986a67dc54852ac971e5e1499be6 (patch) | |
tree | 4c864a3ecca4c606b7eb3adb86a00622071cfbec | |
parent | 9844219878165b468bc0d7cb48ea71393703e904 (diff) | |
parent | 27be5ccd45500c055288d4d4cfcdb675eca38fee (diff) | |
download | CMake-b938e7de9c21986a67dc54852ac971e5e1499be6.zip CMake-b938e7de9c21986a67dc54852ac971e5e1499be6.tar.gz CMake-b938e7de9c21986a67dc54852ac971e5e1499be6.tar.bz2 |
Merge topic 'cmuvstreamread-raii'
27be5ccd45 cmUVStreamRead: Return RAII handle to avoid memory leak
Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !8749
-rw-r--r-- | Source/cmUVStream.h | 40 | ||||
-rw-r--r-- | Tests/CMakeLib/testUVStreambuf.cxx | 58 |
2 files changed, 83 insertions, 15 deletions
diff --git a/Source/cmUVStream.h b/Source/cmUVStream.h index 5998256..db051b8 100644 --- a/Source/cmUVStream.h +++ b/Source/cmUVStream.h @@ -3,8 +3,11 @@ #pragma once #include <cassert> +#include <functional> #include <istream> +#include <cm/memory> + #include <cm3p/uv.h> #include "cmUVHandlePtr.h" @@ -104,28 +107,38 @@ void cmBasicUVPipeIStream<CharT, Traits>::close() using cmUVPipeIStream = cmBasicUVPipeIStream<char>; +class cmUVStreamReadHandle +{ +private: + std::vector<char> Buffer; + std::function<void(std::vector<char>)> OnRead; + std::function<void()> OnFinish; + + template <typename ReadCallback, typename FinishCallback> + friend std::unique_ptr<cmUVStreamReadHandle> cmUVStreamRead( + uv_stream_t* stream, ReadCallback onRead, FinishCallback onFinish); +}; + template <typename ReadCallback, typename FinishCallback> -void cmUVStreamRead(uv_stream_t* stream, ReadCallback onRead, - FinishCallback onFinish) +std::unique_ptr<cmUVStreamReadHandle> cmUVStreamRead(uv_stream_t* stream, + ReadCallback onRead, + FinishCallback onFinish) { - struct ReadData - { - std::vector<char> Buffer; - ReadCallback OnRead; - FinishCallback OnFinish; - }; - - stream->data = new ReadData{ {}, std::move(onRead), std::move(onFinish) }; + auto handle = cm::make_unique<cmUVStreamReadHandle>(); + handle->OnRead = std::move(onRead); + handle->OnFinish = std::move(onFinish); + + stream->data = handle.get(); uv_read_start( stream, [](uv_handle_t* s, std::size_t suggestedSize, uv_buf_t* buffer) { - auto* data = static_cast<ReadData*>(s->data); + auto* data = static_cast<cmUVStreamReadHandle*>(s->data); data->Buffer.resize(suggestedSize); buffer->base = data->Buffer.data(); buffer->len = suggestedSize; }, [](uv_stream_t* s, ssize_t nread, const uv_buf_t* buffer) { - auto* data = static_cast<ReadData*>(s->data); + auto* data = static_cast<cmUVStreamReadHandle*>(s->data); if (nread > 0) { (void)buffer; assert(buffer->base == data->Buffer.data()); @@ -134,7 +147,8 @@ void cmUVStreamRead(uv_stream_t* stream, ReadCallback onRead, } else if (nread < 0 /*|| nread == UV_EOF*/) { data->OnFinish(); uv_read_stop(s); - delete data; } }); + + return handle; } diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx index f3977d4..af06a8e 100644 --- a/Tests/CMakeLib/testUVStreambuf.cxx +++ b/Tests/CMakeLib/testUVStreambuf.cxx @@ -503,7 +503,7 @@ bool testUVStreamRead() std::string output; bool finished = false; - cmUVStreamRead( + auto handle = cmUVStreamRead( pipeSource, [&output](std::vector<char> data) { cm::append(output, data); }, [&output, &finished]() { @@ -524,6 +524,55 @@ bool testUVStreamRead() return true; } +bool testUVStreamReadLeak() +{ + int pipe[] = { -1, -1 }; + if (cmGetPipes(pipe) < 0) { + std::cout << "cmGetPipes() returned an error" << std::endl; + return false; + } + + cm::uv_loop_ptr loop; + loop.init(); + cm::uv_pipe_ptr pipeSink; + pipeSink.init(*loop, 0); + uv_pipe_open(pipeSink, pipe[1]); + + std::string str = "Hello world!"; + uv_write_t writeReq; + uv_buf_t buf; + buf.base = &str.front(); + buf.len = str.length(); + uv_write(&writeReq, pipeSink, &buf, 1, nullptr); + uv_run(loop, UV_RUN_DEFAULT); + pipeSink.reset(); + + cm::uv_pipe_ptr pipeSource; + pipeSource.init(*loop, 0); + uv_pipe_open(pipeSource, pipe[0]); + + std::string output; + bool finished = false; + auto handle = cmUVStreamRead( + pipeSource, + [&output](std::vector<char> data) { cm::append(output, data); }, + [&output, &finished]() { + if (output != "Hello world!") { + std::cout << "Output was \"" << output + << "\", should be \"Hello world!\"" << std::endl; + return; + } + finished = true; + }); + + if (finished) { + std::cout << "finished was set" << std::endl; + return false; + } + + return true; +} + int testUVStreambuf(int argc, char** const argv) { if (argc < 2) { @@ -547,7 +596,12 @@ int testUVStreambuf(int argc, char** const argv) } if (!testUVStreamRead()) { - std::cout << "While executing testUVPipeIStream().\n"; + std::cout << "While executing testUVStreamRead().\n"; + return -1; + } + + if (!testUVStreamReadLeak()) { + std::cout << "While executing testUVStreamReadLeak().\n"; return -1; } |