Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix std::functional problems. #677

Merged
merged 4 commits into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
- If CMake can't find libpq, fall back to pkg-config. (#664)
- Work around spurious compile error on g++ pre-gcc-10. (#665)
- Include `<pqxx/range>` and `<pqxx/time>` headers in `<pqxx/pqxx>`. (#667)
- Don't use `std::function` as deleter for smart pointers.
- Work around gcc compile error with regex + address sanitizer + analyzers.
7.7.4
- `transaction_base::for_each()` is now called `for_stream()`. (#580)
- New `transaction_base::for_query()` is similar, but non-streaming. (#580)
Expand Down
3 changes: 1 addition & 2 deletions include/pqxx/connection.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

#include <cstddef>
#include <ctime>
#include <functional>
#include <initializer_list>
#include <list>
#include <map>
Expand Down Expand Up @@ -1056,7 +1055,7 @@ private:
void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept;

friend struct internal::gate::connection_stream_from;
std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>
std::pair<std::unique_ptr<char, void(*)(void const *)>, std::size_t>
read_copy_line();

friend class internal::gate::connection_stream_to;
Expand Down
1 change: 0 additions & 1 deletion include/pqxx/internal/statement_parameters.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#define PQXX_H_STATEMENT_PARAMETER

#include <cstring>
#include <functional>
#include <iterator>
#include <string>
#include <vector>
Expand Down
2 changes: 1 addition & 1 deletion include/pqxx/internal/stream_query.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class stream_query_end_iterator
template<typename... TYPE> class stream_query : transaction_focus
{
public:
using line_handle = std::unique_ptr<char, std::function<void(char *)>>;
using line_handle = std::unique_ptr<char, void(*)(void const *)>;

/// Execute `query` on `tx`, stream results.
inline stream_query(transaction_base &tx, std::string_view query);
Expand Down
7 changes: 6 additions & 1 deletion include/pqxx/internal/stream_query_impl.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ template<typename... TYPE> class stream_query_input_iterator
public:
using value_type = std::tuple<TYPE...>;

explicit stream_query_input_iterator(stream_t &home) : m_home(home)
explicit stream_query_input_iterator(stream_t &home) :
m_home(home),
m_line{
typename stream_query<TYPE...>::line_handle(
nullptr, pqxx::internal::pq::pqfreemem)
}
{
consume_line();
}
Expand Down
3 changes: 1 addition & 2 deletions include/pqxx/stream_from.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#endif

#include <cassert>
#include <functional>
#include <variant>

#include "pqxx/connection.hxx"
Expand Down Expand Up @@ -80,7 +79,7 @@ class PQXX_LIBEXPORT stream_from : transaction_focus
{
public:
using raw_line =
std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>;
std::pair<std::unique_ptr<char, void(*)(void const *)>, std::size_t>;

/// Factory: Execute query, and stream the results.
/** The query can be a SELECT query or a VALUES query; or it can be an
Expand Down
7 changes: 7 additions & 0 deletions include/pqxx/util.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -593,4 +593,11 @@ error_string(int err_num, std::array<char, BYTES> &buffer)
#endif
}
} // namespace pqxx::internal


namespace pqxx::internal::pq
{
/// Wrapper for `PQfreemem()`, with C++ linkage.
PQXX_LIBEXPORT void pqfreemem(void const *) noexcept;
} // namespace pqxx::internal::pq
#endif
4 changes: 2 additions & 2 deletions src/binarystring.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ PQXX_COLD pqxx::binarystring::binarystring(field const &F)
{
unsigned char const *data{
reinterpret_cast<unsigned char const *>(F.c_str())};
m_buf =
std::shared_ptr<unsigned char>{PQunescapeBytea(data, &m_size), PQfreemem};
m_buf = std::shared_ptr<unsigned char>{
PQunescapeBytea(data, &m_size), pqxx::internal::pq::pqfreemem};
if (m_buf == nullptr)
throw std::bad_alloc{};
}
Expand Down
57 changes: 39 additions & 18 deletions src/connection.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@ extern "C"

using namespace std::literals;


std::string PQXX_COLD
pqxx::encrypt_password(char const user[], char const password[])
{
std::unique_ptr<char, std::function<void(char *)>> p{
PQencryptPassword(password, user), PQfreemem};
std::unique_ptr<char, void(*)(void const *)> p{
PQencryptPassword(password, user), pqxx::internal::pq::pqfreemem};
return {p.get()};
}

Expand Down Expand Up @@ -464,10 +465,20 @@ bool pqxx::connection::is_busy() const noexcept
}


namespace
{
/// Wrapper for `PQfreeCancel`, with C++ linkage.
void wrap_pgfreecancel(PGcancel *ptr)
{
PQfreeCancel(ptr);
}
} // namespace


void PQXX_COLD pqxx::connection::cancel_query()
{
using pointer = std::unique_ptr<PGcancel, std::function<void(PGcancel *)>>;
pointer cancel{PQgetCancel(m_conn), PQfreeCancel};
std::unique_ptr<PGcancel, void(*)(PGcancel *)> cancel{
PQgetCancel(m_conn), wrap_pgfreecancel};
if (cancel == nullptr)
PQXX_UNLIKELY
throw std::bad_alloc{};
Expand Down Expand Up @@ -529,13 +540,13 @@ pqxx::connection::set_verbosity(error_verbosity verbosity) &noexcept
namespace
{
/// Unique pointer to PGnotify.
using notify_ptr = std::unique_ptr<PGnotify, std::function<void(PGnotify *)>>;
using notify_ptr = std::unique_ptr<PGnotify, void(*)(void const *)>;


/// Get one notification from a connection, or null.
notify_ptr get_notif(pqxx::internal::pq::PGconn *conn)
{
return notify_ptr(PQnotifies(conn), PQfreemem);
return notify_ptr(PQnotifies(conn), pqxx::internal::pq::pqfreemem);
}
} // namespace

Expand Down Expand Up @@ -680,8 +691,8 @@ std::string pqxx::connection::encrypt_password(
char const user[], char const password[], char const *algorithm)
{
auto const buf{PQencryptPasswordConn(m_conn, password, user, algorithm)};
std::unique_ptr<char const, std::function<void(char const *)>> ptr{
buf, [](char const *x) { PQfreemem(const_cast<char *>(x)); }};
std::unique_ptr<char const, void(*)(void const *)> ptr{
buf, pqxx::internal::pq::pqfreemem};
return std::string(ptr.get());
}

Expand Down Expand Up @@ -800,7 +811,7 @@ void pqxx::connection::unregister_transaction(transaction_base *t) noexcept
}


std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>
std::pair<std::unique_ptr<char, void(*)(void const *)>, std::size_t>
pqxx::connection::read_copy_line()
{
char *buf{nullptr};
Expand All @@ -817,7 +828,10 @@ pqxx::connection::read_copy_line()

case -1: // End of COPY.
make_result(PQgetResult(m_conn), q, *q);
return {};
return std::make_pair(
std::unique_ptr<char, void(*)(void const *)>{
nullptr, pqxx::internal::pq::pqfreemem},
0u);

case 0: // "Come back later."
throw internal_error{"table read inexplicably went asynchronous"};
Expand All @@ -828,7 +842,8 @@ pqxx::connection::read_copy_line()
// Line size includes a trailing zero, which we ignore.
auto const text_len{static_cast<std::size_t>(line_len) - 1};
return std::make_pair(
std::unique_ptr<char, std::function<void(char *)>>{buf, PQfreemem},
std::unique_ptr<char, void(*)(void const *)>{
buf, pqxx::internal::pq::pqfreemem},
text_len);
}
}
Expand Down Expand Up @@ -939,8 +954,8 @@ std::string PQXX_COLD pqxx::connection::unesc_raw(char const text[]) const
std::size_t len;
auto bytes{const_cast<unsigned char *>(
reinterpret_cast<unsigned char const *>(text))};
std::unique_ptr<unsigned char, std::function<void(unsigned char *)>> const
ptr{PQunescapeBytea(bytes, &len), PQfreemem};
std::unique_ptr<unsigned char, void(*)(void const *)> const
ptr{PQunescapeBytea(bytes, &len), pqxx::internal::pq::pqfreemem};
return std::string{ptr.get(), ptr.get() + len};
}
}
Expand Down Expand Up @@ -974,9 +989,9 @@ std::string pqxx::connection::quote(std::basic_string_view<std::byte> b) const

std::string pqxx::connection::quote_name(std::string_view identifier) const
{
std::unique_ptr<char, std::function<void(char *)>> buf{
std::unique_ptr<char, void(*)(void const *)> buf{
PQescapeIdentifier(m_conn, identifier.data(), std::size(identifier)),
PQfreemem};
pqxx::internal::pq::pqfreemem};
if (buf.get() == nullptr)
PQXX_UNLIKELY
throw failure{err_msg()};
Expand Down Expand Up @@ -1152,6 +1167,13 @@ char const *get_default(PQconninfoOption const &opt) noexcept
// The environment variable is the prevailing default.
return var;
}


/// Wrapper for `PQconninfoFree()`, with C++ linkage.
void pqconninfofree(PQconninfoOption *ptr)
{
PQconninfoFree(ptr);
}
} // namespace


Expand All @@ -1161,9 +1183,8 @@ std::string pqxx::connection::connection_string() const
PQXX_UNLIKELY
throw usage_error{"Can't get connection string: connection is not open."};

std::unique_ptr<
PQconninfoOption, std::function<void(PQconninfoOption *)>> const params{
PQconninfo(m_conn), PQconninfoFree};
std::unique_ptr<PQconninfoOption, void(*)(PQconninfoOption *)>
const params{PQconninfo(m_conn), pqconninfofree};
if (params.get() == nullptr)
PQXX_UNLIKELY
throw std::bad_alloc{};
Expand Down
3 changes: 2 additions & 1 deletion src/stream_from.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ pqxx::stream_from::raw_line pqxx::stream_from::get_raw_line()
}
else
{
return {};
return std::make_pair(
std::unique_ptr<char, void(*)(void const *)>{nullptr, nullptr}, 0u);
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/util.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,14 @@ pqxx::internal::unesc_bin(std::string_view escaped_data)
unesc_bin(escaped_data, buf.data());
return buf;
}


namespace pqxx::internal::pq
{
void pqfreemem(void const *ptr) noexcept
{
// Why is it OK to const_cast here? Because this is the C equivalent to a
// destructor. Those apply to const objects as well as non-const ones.
PQfreemem(const_cast<void *>(ptr));
}
} // namespace pqxx::internal::pq
33 changes: 16 additions & 17 deletions test/test_types.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -121,24 +121,23 @@ template<> struct string_traits<ipv4>
ipv4 ts;
if (std::data(text) == nullptr)
internal::throw_null_conversion(type_name<ipv4>);
std::regex ipv4_regex{R"--((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}))--"};
std::smatch match;
// Need non-temporary for `std::regex_match()`
std::string sstr{text};
if (not std::regex_match(sstr, match, ipv4_regex) or std::size(match) != 5)
throw std::runtime_error{"Invalid ipv4 format: " + std::string{text}};
try
std::vector<std::size_t> ends;
for (std::size_t i{0}; i < std::size(text); ++i)
if (text[i] == '.') ends.push_back(i);
ends.push_back(std::size(text));
if (std::size(ends) != 4)
throw conversion_error{pqxx::internal::concat(
"Can't parse '", text, "' as ipv4: expected 4 octets, "
"found ",std::size(ends), "."
)};
std::size_t start{0};
for (int i{0}; i < 4; ++i)
{
for (std::size_t i{0}; i < 4; ++i)
ts.set_byte(int(i), uint32_t(std::stoi(match[i + 1])));
}
catch (std::invalid_argument const &)
{
throw std::runtime_error{"Invalid ipv4 format: " + std::string{text}};
}
catch (std::out_of_range const &)
{
throw std::runtime_error{"Invalid ipv4 format: " + std::string{text}};
auto idx{static_cast<std::size_t>(i)};
std::string_view digits{&text[start], ends[idx] - start};
auto value{pqxx::from_string<uint32_t>(digits)};
ts.set_byte(i, value);
start = ends[idx] + 1;
}
return ts;
}
Expand Down
2 changes: 1 addition & 1 deletion test/unit/test_blob.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ namespace
/** This is just here to stop Visual Studio from advertising its own
* alternative.
*/
std::unique_ptr<FILE, std::function<int(FILE *)>>
std::unique_ptr<FILE, int(*)(FILE *)>
my_fopen(char const *path, char const *mode)
{
#if defined(_MSC_VER)
Expand Down