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:Assert
uses__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:0 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 calltest()
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 abool
with eithertrue
orfalse
, 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.wallet: 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 pickedMarcoFalke commented at 11:27 am on March 30, 2022: memberTested with diff:
0diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp 1index 1881573e7a..d7328ff450 100644 2--- a/src/test/util_tests.cpp 3+++ b/src/test/util_tests.cpp 4@@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(util_check) 5 const std::unique_ptr<int> p_two = Assert(std::make_unique<int>(2)); 6 // Check that Assert works on lvalues and rvalues 7 const int two = *Assert(p_two); 8- Assert(two == 2); 9+ Assert(two != 2); 10 Assert(true); 11 // Check that Assume can be used as unary expression 12 const bool result{Assume(two == 2)};
Before:
0$ ./src/test/test_bitcoin -t util_tests/util_check --catch_system_errors=no 1Running 1 test case... 2test_bitcoin: test/util_tests.cpp:87: auto util_tests::util_check::test_method()::(anonymous class)::operator()() const: Assertion `"two != 2" && check' failed. 3Aborted (core dumped)
With this pull:
0$ ./src/test/test_bitcoin -t util_tests/util_check --catch_system_errors=no 1Running 1 test case... 2test/util_tests.cpp:87 test_method: Assertion `two != 2' failed. 3Aborted (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)
0 bool test() 1 {
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
template
s are inline.0T&& 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
return
orcontinue
orbreak
…0 if (!val) { 1 assertion_fail(file, line, func, assertion); 2 }
MarcoFalke approvedMarcoFalke commented at 11:35 am on March 30, 2022: memberLeft some more nits (can be ignored).
ACK 3bcffa1146beb40e28bd1bcfaccf72e0d138c9c0 🐤
Signature:
0-----BEGIN PGP SIGNED MESSAGE----- 1Hash: SHA512 2 3ACK 3bcffa1146beb40e28bd1bcfaccf72e0d138c9c0 🐤 4-----BEGIN PGP SIGNATURE----- 5 6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p 7pUgTQgv9HP5fwUc67QUWBjyLMXITzFCx7fUOKh97aePdHaegYMjauudEKiY5TOTi 8Ks9HFnnirQmNq23B21wTGlkJBRkGIG16v3S5dS7iDGETGepXDBc1myBJv5u2AElG 9l4IKxqWPVs9EUAzpDaNo9nxXrz0O3xPlUVDPA46zVl+IUDM8gZ3t8uqEoJAly7Jj 109FMreyD2riiKrZ9+dEIhAsJ08/Ski9lwxforRvVvk5a8dIztKgScjHWP+TcL5bTA 11ICA6d5TF6Zbl1SpTgNFNM+Yw9rCiND+4Z/k8zDUYnrt0dF13I4uDHG1FX8xgTvL/ 12yxj/0/PC8gZfphOPWnL++06MMtKuplTY5TJD3pcC2MJZORU/fJp+w1RKvhaaf0/W 13ZZzK2rj9kGeKOofSRKvqWq7zgd+8L8GK1xtV6AsCzuMGoEruXZlF0BI/CiLF1b0z 14hzunflN07ltCAl0R2LpAJ1YDazE/vY+A25K6iktkAhXpB0+6WGNGFjk1BKeXU3lX 15xDrgwPRG 16=7L0O 17-----END PGP SIGNATURE-----
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:
0diff --git a/src/util/check.h b/src/util/check.h 1index 3fa49c0a3e..4c2ee4501b 100644 2--- a/src/util/check.h 3+++ b/src/util/check.h 4@@ -51,21 +51,22 @@ void assertion_fail(const char* file, int line, const char* func, const char* as 5 6 /** Helper for Assert() */ 7 template <typename T> 8-inline T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) 9+T&& maybe_abort_on_check(bool IS_ASSERT, T&& val, const char* file, int line, const char* func, const char* assertion) 10 { 11- if (!val) assertion_fail(file, line, func, assertion); 12+ if (!val) { 13+ if (IS_ASSERT // Abort inside Assert() 14+#ifdef ABORT_ON_FAILED_ASSUME 15+ || true // Abort inside Assume() 16+#endif 17+ ) { 18+ assertion_fail(file, line, func, assertion); 19+ } 20+ } 21 return std::forward<T>(val); 22 } 23 24 /** Identity function. Abort if the value compares equal to zero */ 25-#define Assert(val) inline_assertion_check(val, __FILE__, __LINE__, __func__, #val) 26- 27-/** Helper for Assume() */ 28-template <typename T> 29-inline T&& skip_assumption_check(T&& val) 30-{ 31- return std::forward<T>(val); 32-} 33+#define Assert(val) maybe_abort_on_check(true, val, __FILE__, __LINE__, __func__, #val) 34 35 /** 36 * Assume is the identity function. 37@@ -77,10 +78,6 @@ inline T&& skip_assumption_check(T&& val) 38 * - For non-fatal errors in interactive sessions (e.g. RPC or command line 39 * interfaces), CHECK_NONFATAL() might be more appropriate. 40 */ 41-#ifdef ABORT_ON_FAILED_ASSUME 42-#define Assume(val) Assert(val) 43-#else 44-#define Assume(val) skip_assumption_check(val) 45-#endif 46+#define Assume(val) maybe_abort_on_check(false, val, __FILE__, __LINE__, __func__, #val) 47 48 #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, usedif constexpr
and left the!val
as the innerif
, but otherwise taken up.jonatack commented at 12:25 pm on March 30, 2022: memberConcept ACK, testingMarcoFalke 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
0--- a/src/init.cpp 1+++ b/src/init.cpp 2@@ -1541,7 +1541,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) 3 4 // ********************************************************* Step 8: start indexers 5 if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { 6- if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) { 7+ if (const auto error{CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db))}) { 8 return InitError(*error); 9 }
then with this pull Clang thread safety analysis is now able to detect the missing lock that on current master was previously undetected
0 CXX node/libbitcoin_node_a-blockstorage.o 1init.cpp:1544:77: error: passing variable 'm_block_tree_db' by reference requires holding mutex 'cs_main' [-Werror,-Wthread-safety-reference] 2 if (const auto error{CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db))}) { 3 ^ 41 error generated.
ajtowns commented at 1:17 pm on March 30, 2022: memberNits picked againMarcoFalke approvedMarcoFalke commented at 1:20 pm on March 30, 2022: memberCouldn’t find more nits.
ACK 2ef47ba6c57a12840499a13908ab61aefca6cb55 🚢
Signature:
0-----BEGIN PGP SIGNED MESSAGE----- 1Hash: SHA512 2 3ACK 2ef47ba6c57a12840499a13908ab61aefca6cb55 🚢 4-----BEGIN PGP SIGNATURE----- 5 6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p 7pUjUxwv7BclwGFAkVZZoIl0/IF1gA7gkGSNIRdHWw0oS+fOvd7SLO369yYsTParO 8DdQ8FLTNoptoKsSJ2C6CyNl1zZ0WV7Wvndj66uFjsHntn5N4OWwBm+731zyBMRJo 9xbOloJXrcLj5Aw1KXBCuKN4mylLN/PFythzdq2+VnAtjOTjw59JYKpqktfSQAXS3 10+51l9BCZJf/F2G4pa1y8yKqyeuAr+IGsC/4SvFybXCaFLiRAR8A+4/TFsAmTJnYn 11T3csvAXoLJDfdn0/mGV2d5pSlPwxqvIMJdhW01cm4Oj2BDgPdsSUizLiTATtTvIG 1269a2nOO9mDBNbtfj7Wy/BATVRMQDVBxZeafdbCYtUO7/BjyAzAE7hSOODAMtv98p 13XQFfDvhBZSsuYEaADQELDx1FqNn7fqz7I/NjiWZbz9+onINH8t+IDlO+qUcChQ3w 14aIX/q1FjmZVxWtqf/kiKyann0Gx3plqjnBFSv/54P0K3D5s4yS1BWNSZOGyciGb+ 15Cm6dc3hb 16=xsn6 17-----END PGP SIGNATURE-----
jonatack commented at 2:04 pm on March 30, 2022: memberTested re-ACK 2ef47ba6c57a12840499a13908ab61aefca6cb55
Nice updates in the last push.
not worth changing unless you retouch for something else
0diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp 1index b5d8411e1d..95d84593aa 100644 2--- a/src/test/util_tests.cpp 3+++ b/src/test/util_tests.cpp 4@@ -79,9 +79,8 @@ BOOST_AUTO_TEST_CASE(util_datadir) 5 6-class NoCopyOrMove 7+struct NoCopyOrMove 8 { 9-public: 10 int i; 11 explicit NoCopyOrMove(int i) : i{i} { } 12 13diff --git a/src/util/check.cpp b/src/util/check.cpp 14index 2a9f885560..56d66f78c6 100644 15--- a/src/util/check.cpp 16+++ b/src/util/check.cpp 17@@ -8,7 +8,7 @@ 18 19 void assertion_fail(const char* file, int line, const char* func, const char* assertion) 20 { 21- auto str = strprintf("%s:%s %s: Assertion `%s' failed.\n", file, line, func, assertion); 22+ const auto str = strprintf("%s:%s %s: Assertion `%s' failed.\n", file, line, func, assertion); 23 fwrite(str.data(), 1, str.size(), stderr); 24 std::abort(); 25 }
MarcoFalke merged this on Mar 31, 2022MarcoFalke closed this on Mar 31, 2022
jnewbery 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:
0./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]’: 1./validation.h:207:13: required from here 2./util/check.h:54:49: warning: parameter ‘file’ set but not used [-Wunused-but-set-parameter] 3 54 | T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) 4 | ~~~~~~~~~~~~^~~~ 5./util/check.h:54:59: warning: parameter ‘line’ set but not used [-Wunused-but-set-parameter] 6 54 | T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) 7 | ~~~~^~~~ 8./util/check.h:54:77: warning: parameter ‘func’ set but not used [-Wunused-but-set-parameter] 9 54 | T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) 10 | ~~~~~~~~~~~~^~~~ 11./util/check.h:54:95: warning: parameter ‘assertion’ set but not used [-Wunused-but-set-parameter] 12 54 | T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) 13 | ~~~~~~~~~~~~^~~~~~~~~ 14 CXX test/test_bitcoin-txrequest_tests.o
configure options:
0Options used to compile and link: 1 external signer = yes 2 multiprocess = no 3 with experimental syscall sandbox support = yes 4 with libs = yes 5 with wallet = no 6 with gui / qt = yes 7 with qr = no 8 with zmq = yes 9 with test = yes 10 with fuzz binary = yes 11 with bench = yes 12 with upnp = no 13 with natpmp = no 14 use asm = yes 15 USDT tracing = no 16 sanitizers = 17 debug enabled = no 18 gprof enabled = no 19 werror = no 20 LTO = no 21 22 target os = linux-gnu 23 build os = linux-gnu 24 25 CC = /usr/bin/ccache gcc 26 CFLAGS = -pthread -g -O2 27 CPPFLAGS = -fmacro-prefix-map=$(abs_top_srcdir)=. -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -DHAVE_BUILD_INFO -DPROVIDE_FUZZ_MAIN_FUNCTION 28 CXX = /usr/bin/ccache g++ -std=c++17 29 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 30 LDFLAGS = -lpthread -Wl,-z,relro -Wl,-z,now -Wl,-z,separate-code -pie 31 ARFLAGS = cr
0→ gcc --version 1gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 2Copyright (C) 2019 Free Software Foundation, Inc. 3This is free software; see the source for copying conditions. There is NO 4warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 5→ g++ --version 6g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 7Copyright (C) 2019 Free Software Foundation, Inc. 8This is free software; see the source for copying conditions. There is NO 9warranty; 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 constexpr
withif
- Revert #24714 (review)
- Mark them “used” (see diff below in this comment)
- (edit) Mark them
[[maybe_unused]]
(see diff below in another comment)
0diff --git a/src/util/check.h b/src/util/check.h 1index 80e973e7e..dea498293 100644 2--- a/src/util/check.h 3+++ b/src/util/check.h 4@@ -53,6 +53,7 @@ void assertion_fail(const char* file, int line, const char* func, const char* as 5 template <bool IS_ASSERT, typename T> 6 T&& inline_assertion_check(T&& val, const char* file, int line, const char* func, const char* assertion) 7 { 8+ (void)file,(void)line,(void)func,(void)assertion; 9 if constexpr (IS_ASSERT 10 #ifdef ABORT_ON_FAILED_ASSUME 11 || true
jnewbery 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 sayinline_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: 2024-12-04 06:12 UTC
This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me