From 19e7e447c0dec65beef51508d54e8af279411613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20K=C3=BCthe?= Date: Wed, 13 Mar 2024 21:08:58 +0000 Subject: [PATCH] Fix memory leak See https://stackoverflow.com/questions/78143322/how-can-i-read-from-a-tap-device-via-posixstream-descriptor-simultaneously-w/78143690?noredirect=1#comment137772998_78143690 --- bindings/cpp/tuntap++.cc | 40 ++++++++++++++++------------------------ bindings/cpp/tuntap++.hh | 12 +++++++++--- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/bindings/cpp/tuntap++.cc b/bindings/cpp/tuntap++.cc index d0c3a70..3dee788 100644 --- a/bindings/cpp/tuntap++.cc +++ b/bindings/cpp/tuntap++.cc @@ -7,7 +7,7 @@ namespace tuntap { tuntap::tuntap(int mode, int id) - : _dev{::tuntap_init()}, _started{true} + : _dev{::tuntap_init()} { if (mode != TUNTAP_MODE_ETHERNET && mode != TUNTAP_MODE_TUNNEL) { throw std::invalid_argument("Unknown tuntap mode"); @@ -15,41 +15,33 @@ tuntap::tuntap(int mode, int id) if (id < 0 || id > TUNTAP_ID_MAX) { throw std::invalid_argument("Tunnel ID is invalid"); } - if (::tuntap_start(_dev, mode, id)) { + if (::tuntap_start(_dev.get(), mode, id)) { throw std::runtime_error("tuntap_start failed"); } } -tuntap::~tuntap() -{ - if (_started) { - ::tuntap_destroy(_dev); - } -} - tuntap::tuntap(tuntap &&t) noexcept - : _dev(nullptr) + : _dev() { - std::swap(t._dev, this->_dev); + t._dev.swap(this->_dev); } void tuntap::release() noexcept { - ::tuntap_release(_dev); - _started = false; + _dev.release(); } std::string tuntap::name() const noexcept { - return std::string(::tuntap_get_ifname(_dev)); + return std::string(::tuntap_get_ifname(_dev.get())); } void tuntap::name(std::string const &s) { - if (::tuntap_set_ifname(_dev, s.c_str())) { + if (::tuntap_set_ifname(_dev.get(), s.c_str())) { throw std::runtime_error("Failed to set ifname"); } } @@ -57,13 +49,13 @@ tuntap::name(std::string const &s) t_tun tuntap::native_handle() const noexcept { - return ::tuntap_get_fd(this->_dev); + return ::tuntap_get_fd(_dev.get()); } void tuntap::up() { - if (::tuntap_up(_dev)) { + if (::tuntap_up(_dev.get())) { throw std::runtime_error("Failed to bring up tuntap device"); } } @@ -71,7 +63,7 @@ tuntap::up() void tuntap::down() { - if (::tuntap_down(_dev)) { + if (::tuntap_down(_dev.get())) { throw std::runtime_error("Failed to bring down tuntap device"); } } @@ -79,7 +71,7 @@ tuntap::down() int tuntap::mtu() const noexcept { - return ::tuntap_get_mtu(_dev); + return ::tuntap_get_mtu(_dev.get()); } void @@ -88,7 +80,7 @@ tuntap::mtu(int m) if (m < 1 || m > 65535) { throw std::invalid_argument("Invalid mtu"); } - if (::tuntap_set_mtu(_dev, m)) { + if (::tuntap_set_mtu(_dev.get(), m)) { throw std::runtime_error("Failed to set mtu for tuntap device"); } } @@ -99,7 +91,7 @@ tuntap::ip(std::string const &s, int netmask) if (netmask > 128) { throw std::invalid_argument("Invalid netmask"); } - if (::tuntap_set_ip(_dev, s.c_str(), netmask)) { + if (::tuntap_set_ip(_dev.get(), s.c_str(), netmask)) { throw std::runtime_error("Failed to set ip for tuntap device"); } } @@ -107,19 +99,19 @@ tuntap::ip(std::string const &s, int netmask) int tuntap::read(void *buf, size_t len) noexcept { - return ::tuntap_read(_dev, buf, len); + return ::tuntap_read(_dev.get(), buf, len); } int tuntap::write(void *buf, size_t len) noexcept { - return ::tuntap_write(_dev, buf, len); + return ::tuntap_write(_dev.get(), buf, len); } void tuntap::nonblocking(bool b) { - if (::tuntap_set_nonblocking(_dev, int(b))) { + if (::tuntap_set_nonblocking(_dev.get(), static_cast(b))) { throw std::runtime_error("Failed to change non-blocking state for tuntap device"); } } diff --git a/bindings/cpp/tuntap++.hh b/bindings/cpp/tuntap++.hh index f546312..a33322f 100644 --- a/bindings/cpp/tuntap++.hh +++ b/bindings/cpp/tuntap++.hh @@ -3,6 +3,7 @@ #define LIBTUNTAP_ALY0MA60 #include +#include #include @@ -12,7 +13,6 @@ class tuntap { public: tuntap(int, int = TUNTAP_ID_ANY); - ~tuntap(); tuntap(tuntap const &) = delete; tuntap & operator = (tuntap const &) = delete; tuntap(tuntap &&) noexcept; @@ -37,8 +37,14 @@ class tuntap void release() noexcept; void nonblocking(bool); private: - struct device* _dev; - bool _started; + class TunTapDestroyer final { + public: + void operator()(device * dev) const noexcept { + if (dev) + ::tuntap_destroy(dev); + } + }; + std::unique_ptr _dev; }; } /* tuntap */