Skip to content

Conversation

ajtowns
Copy link
Contributor

@ajtowns ajtowns commented Mar 30, 2022

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

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, some nits.

// Check that Assert doesn't require copy/move
NoCopyOrMove x{9};
Assert(x).i += 3;
Assert(x).test();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe check the return value, if that was the point?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Point was mostly to call test()

This puts it in a function body, so that __func__ is available
for reporting any assertion failure.
@ajtowns
Copy link
Contributor Author

ajtowns commented Mar 30, 2022

Nits picked

@maflcko
Copy link
Member

maflcko commented Mar 30, 2022

Tested 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)

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some more nits (can be ignored).

ACK 3bcffa1 🐤

Show signature

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-----

@jonatack
Copy link
Member

Concept ACK, testing

@maflcko
Copy link
Member

maflcko commented Mar 30, 2022

Looks 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.

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 3bcffa1

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
Copy link
Contributor Author

ajtowns commented Mar 30, 2022

Nits picked again

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't find more nits.

ACK 2ef47ba 🚢

Show signature

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-----

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested re-ACK 2ef47ba

Nice updates in the last push.

couple of nits

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();
 }

@maflcko maflcko merged commit 87dc1dc into bitcoin:master Mar 31, 2022
@jnewbery
Copy link
Contributor

This 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.o

configure 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.

@maflcko
Copy link
Member

maflcko commented Mar 31, 2022

Other workarounds for gcc-9:

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
                   || true

@jnewbery
Copy link
Contributor

I'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
Copy link
Contributor Author

ajtowns commented Mar 31, 2022

This 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
Copy link
Contributor Author

ajtowns commented Mar 31, 2022

Looks 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_unused

sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Apr 3, 2022
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 bitcoin#21596
  Fixes bitcoin#24654

ACKs for top commit:
  MarcoFalke:
    ACK 2ef47ba 🚢
  jonatack:
    Tested re-ACK 2ef47ba

Tree-SHA512: 4bdbf3215f3d14472df0552362c5eebe8b7eea2d0928a8a41109edd4e0c5f95de6f8220eb2fee8506874e352c003907faf5ef344174795939306a618157b1bae
@bitcoin bitcoin locked and limited conversation to collaborators Mar 31, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

util/check.h Assert/Assume: namespacing issues How to tell compilers to not drop the lock stack when using Assume/Assert?
4 participants