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.
util/check: Don't use a lambda for Assert/Assume #24714
pull ajtowns wants to merge 2 commits into bitcoin:master from ajtowns:202203-assume changing 6 files +67 −9-
ajtowns commented at 3:15 AM on March 30, 2022: member
- ajtowns added the label Refactoring on Mar 30, 2022
- ajtowns requested review from MarcoFalke on Mar 30, 2022
- ajtowns requested review from practicalswift on Mar 30, 2022
- ajtowns force-pushed on Mar 30, 2022
-
in src/wallet/test/wallet_test_fixture.h:25 in a26daad358 outdated
18 | @@ -19,10 +19,13 @@ namespace wallet { 19 | /** Testing setup and teardown for wallet. 20 | */ 21 | struct WalletTestingSetup : public TestingSetup { 22 | - explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); 23 | + WalletTestingSetup() : WalletTestingSetup(CBaseChainParams::MAIN) { } 24 | + explicit WalletTestingSetup(const std::string& chainName); 25 | + WalletTestingSetup(const WalletTestingSetup&) = delete; 26 | + WalletTestingSetup(WalletTestingSetup&&) = delete;
MarcoFalke commented at 6:10 AM on March 30, 2022:The changes look unrelated? Also, anything with a unique_ptr member should have them deleted already, before and after the changes here.
in src/wallet/test/wallet_test_fixture.h:25 in a26daad358 outdated
25 | + WalletTestingSetup(const WalletTestingSetup&) = delete; 26 | + WalletTestingSetup(WalletTestingSetup&&) = delete; 27 | ~WalletTestingSetup(); 28 | 29 | - std::unique_ptr<interfaces::WalletLoader> m_wallet_loader = interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args)); 30 | + std::unique_ptr<interfaces::WalletLoader> m_wallet_loader;
MarcoFalke commented at 6:10 AM on March 30, 2022:I presume this is to silence clang TS warnings? If so, could mention it in the commit body.
ajtowns commented at 6:48 AM on March 30, 2022:Assertuses__func__which is not defined outside of a function body, but the initializer list counts as part of the constructor body.in src/test/util_tests.cpp:85 in b4d788499e outdated
77 | @@ -78,6 +78,29 @@ BOOST_AUTO_TEST_CASE(util_datadir) 78 | BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase()); 79 | } 80 | 81 | +namespace { 82 | +class NoCopyOrMove 83 | +{ 84 | +public: 85 | + int i = 0;
MarcoFalke commented at 6:13 AM on March 30, 2022:int i;nit: Can leave un-initialized for clarity, since the default value is never used.
in src/test/util_tests.cpp:121 in b4d788499e outdated
111 | @@ -89,6 +112,14 @@ BOOST_AUTO_TEST_CASE(util_check) 112 | // Check that Assume can be used as unary expression 113 | const bool result{Assume(two == 2)}; 114 | Assert(result); 115 | + 116 | + // Check that Assert doesn't require copy/move 117 | + NoCopyOrMove x{9}; 118 | + Assert(x).i += 3; 119 | + Assert(x).test();
MarcoFalke commented at 6:15 AM on March 30, 2022:Maybe check the return value, if that was the point?
ajtowns commented at 7:23 AM on March 30, 2022:Point was mostly to call
test()in src/test/util_tests.cpp:99 in b4d788499e outdated
94 | + int getp1() { return i + 1; } 95 | + int test() { 96 | + // Check that Assume can be used within a lambda and still call methods 97 | + [&]() { Assume(getp1()); }(); 98 | + if (Assume(getp1() != 5)) return 3; 99 | + return 9;
MarcoFalke commented at 6:15 AM on March 30, 2022:Looks like it would be sufficient to return a
boolwith eithertrueorfalse, here?in src/test/util_tests.cpp:122 in b4d788499e outdated
117 | + NoCopyOrMove x{9}; 118 | + Assert(x).i += 3; 119 | + Assert(x).test(); 120 | + 121 | + // Check nested Asserts 122 | + Assert( Assert(x).i != 5 );
MarcoFalke commented at 6:15 AM on March 30, 2022:clang-format new code?
MarcoFalke approvedMarcoFalke commented at 6:17 AM on March 30, 2022: memberLooks good, some nits.
7c9fe25c16wallet: move Assert() check into constructor
This puts it in a function body, so that __func__ is available for reporting any assertion failure.
ajtowns force-pushed on Mar 30, 2022ajtowns commented at 7:24 AM on March 30, 2022: memberNits picked
MarcoFalke commented at 11:27 AM on March 30, 2022: memberTested with diff:
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 1881573e7a..d7328ff450 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(util_check) const std::unique_ptr<int> p_two = Assert(std::make_unique<int>(2)); // Check that Assert works on lvalues and rvalues const int two = *Assert(p_two); - Assert(two == 2); + Assert(two != 2); Assert(true); // Check that Assume can be used as unary expression const bool result{Assume(two == 2)};Before:
$ ./src/test/test_bitcoin -t util_tests/util_check --catch_system_errors=no Running 1 test case... test_bitcoin: test/util_tests.cpp:87: auto util_tests::util_check::test_method()::(anonymous class)::operator()() const: Assertion `"two != 2" && check' failed. Aborted (core dumped)With this pull:
$ ./src/test/test_bitcoin -t util_tests/util_check --catch_system_errors=no Running 1 test case... test/util_tests.cpp:87 test_method: Assertion `two != 2' failed. Aborted (core dumped)in src/test/util_tests.cpp:97 in 3bcffa1146 outdated
92 | + NoCopyOrMove& operator=(NoCopyOrMove&&) = delete; 93 | + 94 | + operator bool() const { return i != 0; } 95 | + 96 | + int get_ip1() { return i + 1; } 97 | + bool test() {
MarcoFalke commented at 11:31 AM on March 30, 2022:clang-format nit (in case you retouch for other reasons)
bool test() {in src/util/check.h:54 in 3bcffa1146 outdated
50 | +void assertion_fail(const char* file, int line, const char* func, const char* assertion); 51 | + 52 | /** Helper for Assert() */ 53 | template <typename T> 54 | -T get_pure_r_value(T&& val) 55 | +inline T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion)
MarcoFalke commented at 11:31 AM on March 30, 2022:nit: All
templates are inline.T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion)in src/util/check.h:56 in 3bcffa1146 outdated
52 | /** Helper for Assert() */ 53 | template <typename T> 54 | -T get_pure_r_value(T&& val) 55 | +inline T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) 56 | { 57 | + if (!val) assertion_fail(file, line, func, assertion);
MarcoFalke commented at 11:34 AM on March 30, 2022:nit: I think it is better to use a new line unless it is a trivial single statement like
returnorcontinueorbreak...if (!val) { assertion_fail(file, line, func, assertion); }MarcoFalke approvedMarcoFalke commented at 11:35 AM on March 30, 2022: memberLeft some more nits (can be ignored).
ACK 3bcffa1146beb40e28bd1bcfaccf72e0d138c9c0 🐤
<details><summary>Show signature</summary>
Signature:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 ACK 3bcffa1146beb40e28bd1bcfaccf72e0d138c9c0 🐤 -----BEGIN PGP SIGNATURE----- iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p pUgTQgv9HP5fwUc67QUWBjyLMXITzFCx7fUOKh97aePdHaegYMjauudEKiY5TOTi Ks9HFnnirQmNq23B21wTGlkJBRkGIG16v3S5dS7iDGETGepXDBc1myBJv5u2AElG l4IKxqWPVs9EUAzpDaNo9nxXrz0O3xPlUVDPA46zVl+IUDM8gZ3t8uqEoJAly7Jj 9FMreyD2riiKrZ9+dEIhAsJ08/Ski9lwxforRvVvk5a8dIztKgScjHWP+TcL5bTA ICA6d5TF6Zbl1SpTgNFNM+Yw9rCiND+4Z/k8zDUYnrt0dF13I4uDHG1FX8xgTvL/ yxj/0/PC8gZfphOPWnL++06MMtKuplTY5TJD3pcC2MJZORU/fJp+w1RKvhaaf0/W ZZzK2rj9kGeKOofSRKvqWq7zgd+8L8GK1xtV6AsCzuMGoEruXZlF0BI/CiLF1b0z hzunflN07ltCAl0R2LpAJ1YDazE/vY+A25K6iktkAhXpB0+6WGNGFjk1BKeXU3lX xDrgwPRG =7L0O -----END PGP SIGNATURE-----</details>
in src/util/check.h:68 in 3bcffa1146 outdated
65 | +/** Helper for Assume() */ 66 | +template <typename T> 67 | +inline T&& skip_assumption_check(T&& val) 68 | +{ 69 | + return std::forward<T>(val); 70 | +}
MarcoFalke commented at 12:09 PM on March 30, 2022:It might be possible to remove the separate helpers and just use the same function for both:
diff --git a/src/util/check.h b/src/util/check.h index 3fa49c0a3e..4c2ee4501b 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -51,21 +51,22 @@ void assertion_fail(const char* file, int line, const char* func, const char* as /** Helper for Assert() */ template <typename T> -inline T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) +T&& maybe_abort_on_check(bool IS_ASSERT, T&& val, const char* file, int line, const char* func, const char* assertion) { - if (!val) assertion_fail(file, line, func, assertion); + if (!val) { + if (IS_ASSERT // Abort inside Assert() +#ifdef ABORT_ON_FAILED_ASSUME + || true // Abort inside Assume() +#endif + ) { + assertion_fail(file, line, func, assertion); + } + } return std::forward<T>(val); } /** Identity function. Abort if the value compares equal to zero */ -#define Assert(val) inline_assertion_check(val, __FILE__, __LINE__, __func__, #val) - -/** Helper for Assume() */ -template <typename T> -inline T&& skip_assumption_check(T&& val) -{ - return std::forward<T>(val); -} +#define Assert(val) maybe_abort_on_check(true, val, __FILE__, __LINE__, __func__, #val) /** * Assume is the identity function. @@ -77,10 +78,6 @@ inline T&& skip_assumption_check(T&& val) * - For non-fatal errors in interactive sessions (e.g. RPC or command line * interfaces), CHECK_NONFATAL() might be more appropriate. */ -#ifdef ABORT_ON_FAILED_ASSUME -#define Assume(val) Assert(val) -#else -#define Assume(val) skip_assumption_check(val) -#endif +#define Assume(val) maybe_abort_on_check(false, val, __FILE__, __LINE__, __func__, #val) #endif // BITCOIN_UTIL_CHECK_H
ajtowns commented at 1:14 PM on March 30, 2022:Made it a template argument instead of a function param, used
if constexprand left the!valas the innerif, but otherwise taken up.jonatack commented at 12:25 PM on March 30, 2022: memberConcept ACK, testing
MarcoFalke commented at 12:30 PM on March 30, 2022: memberLooks like this also intentionally or accidentally fixes #21596, as the value is no longer evaluated inside the function, but before passing it to the function as parameter?
Also, it fixes the nesting issue that is fixed only in C++20 (#23363)?
Quite amazing that this relatively simple patch fixes three bugs.
MarcoFalke added this to the milestone 24.0 on Mar 30, 2022util/check: stop using lambda for Assert/Assume 2ef47ba6c5ajtowns force-pushed on Mar 30, 2022jonatack commented at 1:15 PM on March 30, 2022: memberACK 3bcffa1146beb40e28bd1bcfaccf72e0d138c9c0
If #24672 is reverted with the following diff
--- a/src/init.cpp +++ b/src/init.cpp @@ -1541,7 +1541,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 8: start indexers if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) { + if (const auto error{CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db))}) { return InitError(*error); }then with this pull Clang thread safety analysis is now able to detect the missing lock that on current master was previously undetected
CXX node/libbitcoin_node_a-blockstorage.o init.cpp:1544:77: error: passing variable 'm_block_tree_db' by reference requires holding mutex 'cs_main' [-Werror,-Wthread-safety-reference] if (const auto error{CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db))}) { ^ 1 error generated.ajtowns commented at 1:17 PM on March 30, 2022: memberNits picked again
MarcoFalke approvedMarcoFalke commented at 1:20 PM on March 30, 2022: memberCouldn't find more nits.
ACK 2ef47ba6c57a12840499a13908ab61aefca6cb55 🚢
<details><summary>Show signature</summary>
Signature:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 ACK 2ef47ba6c57a12840499a13908ab61aefca6cb55 🚢 -----BEGIN PGP SIGNATURE----- iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p pUjUxwv7BclwGFAkVZZoIl0/IF1gA7gkGSNIRdHWw0oS+fOvd7SLO369yYsTParO DdQ8FLTNoptoKsSJ2C6CyNl1zZ0WV7Wvndj66uFjsHntn5N4OWwBm+731zyBMRJo xbOloJXrcLj5Aw1KXBCuKN4mylLN/PFythzdq2+VnAtjOTjw59JYKpqktfSQAXS3 +51l9BCZJf/F2G4pa1y8yKqyeuAr+IGsC/4SvFybXCaFLiRAR8A+4/TFsAmTJnYn T3csvAXoLJDfdn0/mGV2d5pSlPwxqvIMJdhW01cm4Oj2BDgPdsSUizLiTATtTvIG 69a2nOO9mDBNbtfj7Wy/BATVRMQDVBxZeafdbCYtUO7/BjyAzAE7hSOODAMtv98p XQFfDvhBZSsuYEaADQELDx1FqNn7fqz7I/NjiWZbz9+onINH8t+IDlO+qUcChQ3w aIX/q1FjmZVxWtqf/kiKyann0Gx3plqjnBFSv/54P0K3D5s4yS1BWNSZOGyciGb+ Cm6dc3hb =xsn6 -----END PGP SIGNATURE-----</details>
jonatack commented at 2:04 PM on March 30, 2022: memberTested re-ACK 2ef47ba6c57a12840499a13908ab61aefca6cb55
Nice updates in the last push.
<details><summary>couple of nits</summary><p>
not worth changing unless you retouch for something else
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index b5d8411e1d..95d84593aa 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -79,9 +79,8 @@ BOOST_AUTO_TEST_CASE(util_datadir) -class NoCopyOrMove +struct NoCopyOrMove { -public: int i; explicit NoCopyOrMove(int i) : i{i} { } diff --git a/src/util/check.cpp b/src/util/check.cpp index 2a9f885560..56d66f78c6 100644 --- a/src/util/check.cpp +++ b/src/util/check.cpp @@ -8,7 +8,7 @@ void assertion_fail(const char* file, int line, const char* func, const char* assertion) { - auto str = strprintf("%s:%s %s: Assertion `%s' failed.\n", file, line, func, assertion); + const auto str = strprintf("%s:%s %s: Assertion `%s' failed.\n", file, line, func, assertion); fwrite(str.data(), 1, str.size(), stderr); std::abort(); }</p></details>
MarcoFalke merged this on Mar 31, 2022MarcoFalke closed this on Mar 31, 2022jnewbery commented at 7:28 AM on March 31, 2022: memberThis appears to have introduced build warnings for me on master, when building with gcc 9:
./util/check.h: In instantiation of ‘T&& inline_assertion_check(T&&, const char*, int, const char*, const char*) [with bool IS_ASSERT = false; T = bool]’: ./validation.h:207:13: required from here ./util/check.h:54:49: warning: parameter ‘file’ set but not used [-Wunused-but-set-parameter] 54 | T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) | ~~~~~~~~~~~~^~~~ ./util/check.h:54:59: warning: parameter ‘line’ set but not used [-Wunused-but-set-parameter] 54 | T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) | ~~~~^~~~ ./util/check.h:54:77: warning: parameter ‘func’ set but not used [-Wunused-but-set-parameter] 54 | T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) | ~~~~~~~~~~~~^~~~ ./util/check.h:54:95: warning: parameter ‘assertion’ set but not used [-Wunused-but-set-parameter] 54 | T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) | ~~~~~~~~~~~~^~~~~~~~~ CXX test/test_bitcoin-txrequest_tests.oconfigure options:
Options used to compile and link: external signer = yes multiprocess = no with experimental syscall sandbox support = yes with libs = yes with wallet = no with gui / qt = yes with qr = no with zmq = yes with test = yes with fuzz binary = yes with bench = yes with upnp = no with natpmp = no use asm = yes USDT tracing = no sanitizers = debug enabled = no gprof enabled = no werror = no LTO = no target os = linux-gnu build os = linux-gnu CC = /usr/bin/ccache gcc CFLAGS = -pthread -g -O2 CPPFLAGS = -fmacro-prefix-map=$(abs_top_srcdir)=. -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -DHAVE_BUILD_INFO -DPROVIDE_FUZZ_MAIN_FUNCTION CXX = /usr/bin/ccache g++ -std=c++17 CXXFLAGS = -fdebug-prefix-map=$(abs_top_srcdir)=. -fstack-reuse=none -Wstack-protector -fstack-protector-all -fcf-protection=full -fstack-clash-protection -Wall -Wextra -Wformat -Wformat-security -Wvla -Wredundant-decls -Wdate-time -Wduplicated-branches -Wduplicated-cond -Wlogical-op -Woverloaded-virtual -Wsuggest-override -Wimplicit-fallthrough -Wno-unused-parameter -Wno-deprecated-copy -g -O2 -fno-extended-identifiers LDFLAGS = -lpthread -Wl,-z,relro -Wl,-z,now -Wl,-z,separate-code -pie ARFLAGS = cr→ gcc --version gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. → g++ --version g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.Updating to gcc-10 removes the warnings.
MarcoFalke commented at 7:39 AM on March 31, 2022: memberOther workarounds for gcc-9:
- Replace
if constexprwithif - Revert #24714 (review)
- Mark them "used" (see diff below in this comment)
- (edit) Mark them
[[maybe_unused]](see diff below in another comment)
diff --git a/src/util/check.h b/src/util/check.h index 80e973e7e..dea498293 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -53,6 +53,7 @@ void assertion_fail(const char* file, int line, const char* func, const char* as template <bool IS_ASSERT, typename T> T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) { + (void)file,(void)line,(void)func,(void)assertion; if constexpr (IS_ASSERT #ifdef ABORT_ON_FAILED_ASSUME || truejnewbery commented at 7:49 AM on March 31, 2022: memberI'd vote for the third (mark them used), with a comment that this is to workaround behaviour in gcc-9 and can be removed when the minimum gcc version is 10 or higher.
ajtowns commented at 7:51 AM on March 31, 2022: memberThis appears to have introduced build warnings for me on master, when building with gcc 9:
Looks like this is https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81676 which wasn't fixed until gcc 10
ajtowns commented at 8:05 AM on March 31, 2022: memberLooks like another workaround might be to say
inline_assertion_check(T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion)-- https://en.cppreference.com/w/cpp/language/attributes/maybe_unusedsidhujag referenced this in commit 2cd931a679 on Apr 3, 2022DrahtBot locked this on Mar 31, 2023
github-metadata-mirror
This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-02 15:13 UTC
This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me