Skip to content

Commit 87dc1dc

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#24714: util/check: Don't use a lambda for Assert/Assume
2ef47ba util/check: stop using lambda for Assert/Assume (Anthony Towns) 7c9fe25 wallet: move Assert() check into constructor (Anthony Towns) Pull request description: Using a lambda creates a couple of odd namespacing issues, in particular making clang's thread safety analysis less helpful, and confusing gcc when calling member functions. Fix this by not using a lambda. Fixes #21596 Fixes #24654 ACKs for top commit: MarcoFalke: ACK 2ef47ba 🚢 jonatack: Tested re-ACK 2ef47ba Tree-SHA512: 4bdbf3215f3d14472df0552362c5eebe8b7eea2d0928a8a41109edd4e0c5f95de6f8220eb2fee8506874e352c003907faf5ef344174795939306a618157b1bae
2 parents 74b011b + 2ef47ba commit 87dc1dc

File tree

6 files changed

+67
-9
lines changed

6 files changed

+67
-9
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ libbitcoin_util_a_SOURCES = \
620620
util/asmap.cpp \
621621
util/bip32.cpp \
622622
util/bytevectorhash.cpp \
623+
util/check.cpp \
623624
util/error.cpp \
624625
util/fees.cpp \
625626
util/getuniquepath.cpp \
@@ -838,6 +839,7 @@ bitcoin_chainstate_SOURCES = \
838839
uint256.cpp \
839840
util/asmap.cpp \
840841
util/bytevectorhash.cpp \
842+
util/check.cpp \
841843
util/getuniquepath.cpp \
842844
util/hasher.cpp \
843845
util/moneystr.cpp \

src/test/util_tests.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,31 @@ BOOST_AUTO_TEST_CASE(util_datadir)
7878
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
7979
}
8080

81+
namespace {
82+
class NoCopyOrMove
83+
{
84+
public:
85+
int i;
86+
explicit NoCopyOrMove(int i) : i{i} { }
87+
88+
NoCopyOrMove() = delete;
89+
NoCopyOrMove(const NoCopyOrMove&) = delete;
90+
NoCopyOrMove(NoCopyOrMove&&) = delete;
91+
NoCopyOrMove& operator=(const NoCopyOrMove&) = delete;
92+
NoCopyOrMove& operator=(NoCopyOrMove&&) = delete;
93+
94+
operator bool() const { return i != 0; }
95+
96+
int get_ip1() { return i + 1; }
97+
bool test()
98+
{
99+
// Check that Assume can be used within a lambda and still call methods
100+
[&]() { Assume(get_ip1()); }();
101+
return Assume(get_ip1() != 5);
102+
}
103+
};
104+
} // namespace
105+
81106
BOOST_AUTO_TEST_CASE(util_check)
82107
{
83108
// Check that Assert can forward
@@ -89,6 +114,14 @@ BOOST_AUTO_TEST_CASE(util_check)
89114
// Check that Assume can be used as unary expression
90115
const bool result{Assume(two == 2)};
91116
Assert(result);
117+
118+
// Check that Assert doesn't require copy/move
119+
NoCopyOrMove x{9};
120+
Assert(x).i += 3;
121+
Assert(x).test();
122+
123+
// Check nested Asserts
124+
BOOST_CHECK_EQUAL(Assert((Assert(x).test() ? 3 : 0)), 3);
92125
}
93126

94127
BOOST_AUTO_TEST_CASE(util_criticalsection)

src/util/check.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <util/check.h>
6+
7+
#include <tinyformat.h>
8+
9+
void assertion_fail(const char* file, int line, const char* func, const char* assertion)
10+
{
11+
auto str = strprintf("%s:%s %s: Assertion `%s' failed.\n", file, line, func, assertion);
12+
fwrite(str.data(), 1, str.size(), stderr);
13+
std::abort();
14+
}

src/util/check.h

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,26 @@ class NonFatalCheckError : public std::runtime_error
4747
#endif
4848

4949
/** Helper for Assert() */
50-
template <typename T>
51-
T get_pure_r_value(T&& val)
50+
void assertion_fail(const char* file, int line, const char* func, const char* assertion);
51+
52+
/** Helper for Assert()/Assume() */
53+
template <bool IS_ASSERT, typename T>
54+
T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion)
5255
{
56+
if constexpr (IS_ASSERT
57+
#ifdef ABORT_ON_FAILED_ASSUME
58+
|| true
59+
#endif
60+
) {
61+
if (!val) {
62+
assertion_fail(file, line, func, assertion);
63+
}
64+
}
5365
return std::forward<T>(val);
5466
}
5567

5668
/** Identity function. Abort if the value compares equal to zero */
57-
#define Assert(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); assert(#val && check); return std::forward<decltype(get_pure_r_value(val))>(check); }())
69+
#define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val)
5870

5971
/**
6072
* Assume is the identity function.
@@ -66,10 +78,6 @@ T get_pure_r_value(T&& val)
6678
* - For non-fatal errors in interactive sessions (e.g. RPC or command line
6779
* interfaces), CHECK_NONFATAL() might be more appropriate.
6880
*/
69-
#ifdef ABORT_ON_FAILED_ASSUME
70-
#define Assume(val) Assert(val)
71-
#else
72-
#define Assume(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); return std::forward<decltype(get_pure_r_value(val))>(check); }())
73-
#endif
81+
#define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val)
7482

7583
#endif // BITCOIN_UTIL_CHECK_H

src/wallet/test/wallet_test_fixture.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace wallet {
1010
WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
1111
: TestingSetup(chainName),
12+
m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args))},
1213
m_wallet(m_node.chain.get(), "", m_args, CreateMockWalletDatabase())
1314
{
1415
m_wallet.LoadWallet();

src/wallet/test/wallet_test_fixture.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct WalletTestingSetup : public TestingSetup {
2222
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
2323
~WalletTestingSetup();
2424

25-
std::unique_ptr<interfaces::WalletLoader> m_wallet_loader = interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args));
25+
std::unique_ptr<interfaces::WalletLoader> m_wallet_loader;
2626
CWallet m_wallet;
2727
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
2828
};

0 commit comments

Comments
 (0)