Browse Source

Fix virtual call in ClientImpl::~ClientImpl() (#942)

* Fix virtual call in ClientImpl::~ClientImpl()

This fixes a warning in clang tidy:

> Call to virtual method 'ClientImpl::shutdown_ssl' during
> destruction bypasses virtual dispatch

ClientImpl::~ClientImpl() calls lock_socket_and_shutdown_and_close()
that itself calls shutdown_ssl().  However, shutdown_ssl() is virtual
and C++ does not perform virtual dispatch in destructors, which results
in the wrong overload being called.

This change adds a non-virtual shutdown_ssl_impl() function that is
called from ~SSLClient().  We also inline sock_socket_and_shutdown_and_close()
and removes the virtual call in ~ClientImpl().

* Inline and remove lock_socket_and_shutdown_and_close()

The function only has one caller.
Mathias Laurin 4 years ago
parent
commit
089b9daa1c
1 changed files with 15 additions and 14 deletions
  1. 15 14
      httplib.h

+ 15 - 14
httplib.h

@@ -1050,10 +1050,6 @@ protected:
   void shutdown_socket(Socket &socket);
   void shutdown_socket(Socket &socket);
   void close_socket(Socket &socket);
   void close_socket(Socket &socket);
 
 
-  // Similar to shutdown_ssl and close_socket, this should NOT be called
-  // concurrently with a DIFFERENT thread sending requests from the socket
-  void lock_socket_and_shutdown_and_close();
-
   bool process_request(Stream &strm, Request &req, Response &res,
   bool process_request(Stream &strm, Request &req, Response &res,
                        bool close_connection, Error &error);
                        bool close_connection, Error &error);
 
 
@@ -1412,6 +1408,7 @@ public:
 private:
 private:
   bool create_and_connect_socket(Socket &socket, Error &error) override;
   bool create_and_connect_socket(Socket &socket, Error &error) override;
   void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override;
   void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override;
+  void shutdown_ssl_impl(Socket &socket, bool shutdown_socket);
 
 
   bool process_socket(const Socket &socket,
   bool process_socket(const Socket &socket,
                       std::function<bool(Stream &strm)> callback) override;
                       std::function<bool(Stream &strm)> callback) override;
@@ -5258,7 +5255,11 @@ inline ClientImpl::ClientImpl(const std::string &host, int port,
       host_and_port_(host_ + ":" + std::to_string(port_)),
       host_and_port_(host_ + ":" + std::to_string(port_)),
       client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
       client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
 
 
-inline ClientImpl::~ClientImpl() { lock_socket_and_shutdown_and_close(); }
+inline ClientImpl::~ClientImpl() {
+  std::lock_guard<std::mutex> guard(socket_mutex_);
+  shutdown_socket(socket_);
+  close_socket(socket_);
+}
 
 
 inline bool ClientImpl::is_valid() const { return true; }
 inline bool ClientImpl::is_valid() const { return true; }
 
 
@@ -5356,13 +5357,6 @@ inline void ClientImpl::close_socket(Socket &socket) {
   socket.sock = INVALID_SOCKET;
   socket.sock = INVALID_SOCKET;
 }
 }
 
 
-inline void ClientImpl::lock_socket_and_shutdown_and_close() {
-  std::lock_guard<std::mutex> guard(socket_mutex_);
-  shutdown_ssl(socket_, true);
-  shutdown_socket(socket_);
-  close_socket(socket_);
-}
-
 inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
 inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
                                            Response &res) {
                                            Response &res) {
   std::array<char, 2048> buf;
   std::array<char, 2048> buf;
@@ -5911,7 +5905,10 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
     // mutex during the process. It would be a bug to call it from a different
     // mutex during the process. It would be a bug to call it from a different
     // thread since it's a thread-safety issue to do these things to the socket
     // thread since it's a thread-safety issue to do these things to the socket
     // if another thread is using the socket.
     // if another thread is using the socket.
-    lock_socket_and_shutdown_and_close();
+    std::lock_guard<std::mutex> guard(socket_mutex_);
+    shutdown_ssl(socket_, true);
+    shutdown_socket(socket_);
+    close_socket(socket_);
   }
   }
 
 
   // Log
   // Log
@@ -6864,7 +6861,7 @@ inline SSLClient::~SSLClient() {
   // Make sure to shut down SSL since shutdown_ssl will resolve to the
   // Make sure to shut down SSL since shutdown_ssl will resolve to the
   // base function rather than the derived function once we get to the
   // base function rather than the derived function once we get to the
   // base class destructor, and won't free the SSL (causing a leak).
   // base class destructor, and won't free the SSL (causing a leak).
-  SSLClient::shutdown_ssl(socket_, true);
+  shutdown_ssl_impl(socket_, true);
 }
 }
 
 
 inline bool SSLClient::is_valid() const { return ctx_; }
 inline bool SSLClient::is_valid() const { return ctx_; }
@@ -7043,6 +7040,10 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
 }
 }
 
 
 inline void SSLClient::shutdown_ssl(Socket &socket, bool shutdown_gracefully) {
 inline void SSLClient::shutdown_ssl(Socket &socket, bool shutdown_gracefully) {
+  shutdown_ssl_impl(socket, shutdown_gracefully);
+}
+
+inline void SSLClient::shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully) {
   if (socket.sock == INVALID_SOCKET) {
   if (socket.sock == INVALID_SOCKET) {
     assert(socket.ssl == nullptr);
     assert(socket.ssl == nullptr);
     return;
     return;