util: Abort on failing CHECK_NONFATAL in debug builds
This requires adjusting some tests to force exceptions over aborts, or accept either exceptions or aborts. Also, remove a fuzz test in integer.cpp that is mostly redundant with the unit test added in the prior commit.
This commit is contained in:
5 files changed
+47
-26
No files matched your search
@@ -255,9 +255,4 @@ FUZZ_TARGET(integer, .init = initialize_integer)
|
|||||||
} catch (const std::ios_base::failure&) {
|
} catch (const std::ios_base::failure&) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
CHECK_NONFATAL(b);
|
|
||||||
} catch (const NonFatalCheckError&) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -381,6 +381,12 @@ FUZZ_TARGET(rpc, .init = initialize_rpc)
|
|||||||
arguments.push_back(ConsumeRPCArgument(fuzzed_data_provider, good_data));
|
arguments.push_back(ConsumeRPCArgument(fuzzed_data_provider, good_data));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
std::optional<test_only_CheckFailuresAreExceptionsNotAborts> maybe_mock{};
|
||||||
|
if (rpc_command == "echo") {
|
||||||
|
// Avoid aborting fuzzing for this specific test-only RPC with an
|
||||||
|
// intentional trigger_internal_bug
|
||||||
|
maybe_mock.emplace();
|
||||||
|
}
|
||||||
rpc_testing_setup->CallRPC(rpc_command, arguments);
|
rpc_testing_setup->CallRPC(rpc_command, arguments);
|
||||||
} catch (const UniValue& json_rpc_error) {
|
} catch (const UniValue& json_rpc_error) {
|
||||||
const std::string error_msg{json_rpc_error.find_value("message").get_str()};
|
const std::string error_msg{json_rpc_error.find_value("message").get_str()};
|
||||||
|
|||||||
+16
-13
@@ -534,20 +534,23 @@ BOOST_AUTO_TEST_CASE(check_dup_param_names)
|
|||||||
make_rpc({{"p1", NAMED_ONLY}, {"p2", NAMED}});
|
make_rpc({{"p1", NAMED_ONLY}, {"p2", NAMED}});
|
||||||
make_rpc({{"p1", NAMED_ONLY}, {"p2", NAMED_ONLY}});
|
make_rpc({{"p1", NAMED_ONLY}, {"p2", NAMED_ONLY}});
|
||||||
|
|
||||||
// Error if parameters names are duplicates, unless one parameter is
|
{
|
||||||
// positional and the other is named and .also_positional is true.
|
test_only_CheckFailuresAreExceptionsNotAborts mock_checks{};
|
||||||
BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p1", POSITIONAL}}), NonFatalCheckError);
|
// Error if parameter names are duplicates, unless one parameter is
|
||||||
make_rpc({{"p1", POSITIONAL}, {"p1", NAMED}});
|
// positional and the other is named and .also_positional is true.
|
||||||
BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
|
BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p1", POSITIONAL}}), NonFatalCheckError);
|
||||||
make_rpc({{"p1", NAMED}, {"p1", POSITIONAL}});
|
make_rpc({{"p1", POSITIONAL}, {"p1", NAMED}});
|
||||||
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED}, {"p1", NAMED}}), NonFatalCheckError);
|
BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
|
||||||
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
|
make_rpc({{"p1", NAMED}, {"p1", POSITIONAL}});
|
||||||
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", POSITIONAL}}), NonFatalCheckError);
|
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED}, {"p1", NAMED}}), NonFatalCheckError);
|
||||||
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", NAMED}}), NonFatalCheckError);
|
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
|
||||||
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
|
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", POSITIONAL}}), NonFatalCheckError);
|
||||||
|
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", NAMED}}), NonFatalCheckError);
|
||||||
|
BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
|
||||||
|
|
||||||
// Make sure duplicate aliases are detected too.
|
// Make sure duplicate aliases are detected too.
|
||||||
BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p2|p1", NAMED_ONLY}}), NonFatalCheckError);
|
BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p2|p1", NAMED_ONLY}}), NonFatalCheckError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(help_example)
|
BOOST_AUTO_TEST_CASE(help_example)
|
||||||
|
|||||||
+6
-3
@@ -60,11 +60,17 @@ public:
|
|||||||
NonFatalCheckError(std::string_view msg, std::string_view file, int line, std::string_view func);
|
NonFatalCheckError(std::string_view msg, std::string_view file, int line, std::string_view func);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Internal helper */
|
||||||
|
void assertion_fail(std::string_view file, int line, std::string_view func, std::string_view assertion);
|
||||||
|
|
||||||
/** Helper for CHECK_NONFATAL() */
|
/** Helper for CHECK_NONFATAL() */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T&& inline_check_non_fatal(LIFETIMEBOUND T&& val, const char* file, int line, const char* func, const char* assertion)
|
T&& inline_check_non_fatal(LIFETIMEBOUND T&& val, const char* file, int line, const char* func, const char* assertion)
|
||||||
{
|
{
|
||||||
if (!val) {
|
if (!val) {
|
||||||
|
if constexpr (G_ABORT_ON_FAILED_ASSUME) {
|
||||||
|
assertion_fail(file, line, func, assertion);
|
||||||
|
}
|
||||||
throw NonFatalCheckError{assertion, file, line, func};
|
throw NonFatalCheckError{assertion, file, line, func};
|
||||||
}
|
}
|
||||||
return std::forward<T>(val);
|
return std::forward<T>(val);
|
||||||
@@ -74,9 +80,6 @@ T&& inline_check_non_fatal(LIFETIMEBOUND T&& val, const char* file, int line, co
|
|||||||
#error "Cannot compile without assertions!"
|
#error "Cannot compile without assertions!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Helper for Assert() */
|
|
||||||
void assertion_fail(std::string_view file, int line, std::string_view func, std::string_view assertion);
|
|
||||||
|
|
||||||
/** Helper for Assert()/Assume() */
|
/** Helper for Assert()/Assume() */
|
||||||
template <bool IS_ASSERT, typename T>
|
template <bool IS_ASSERT, typename T>
|
||||||
constexpr T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion)
|
constexpr T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion)
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ from test_framework.util import (
|
|||||||
|
|
||||||
from test_framework.authproxy import JSONRPCException
|
from test_framework.authproxy import JSONRPCException
|
||||||
|
|
||||||
|
import http
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
class RpcMiscTest(BitcoinTestFramework):
|
class RpcMiscTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
@@ -24,11 +27,22 @@ class RpcMiscTest(BitcoinTestFramework):
|
|||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
|
|
||||||
self.log.info("test CHECK_NONFATAL")
|
self.log.info("test CHECK_NONFATAL")
|
||||||
assert_raises_rpc_error(
|
msg_internal_bug = 'request.params[9].get_str() != "trigger_internal_bug"'
|
||||||
-1,
|
self.restart_node(0) # Required to flush the chainstate
|
||||||
'Internal bug detected: request.params[9].get_str() != "trigger_internal_bug"',
|
try:
|
||||||
lambda: node.echo(arg9='trigger_internal_bug'),
|
node.echo(arg9="trigger_internal_bug")
|
||||||
)
|
assert False # Must hit one of the exceptions below
|
||||||
|
except (
|
||||||
|
subprocess.CalledProcessError,
|
||||||
|
http.client.CannotSendRequest,
|
||||||
|
http.client.RemoteDisconnected,
|
||||||
|
):
|
||||||
|
self.log.info("Restart node after crash")
|
||||||
|
assert_equal(-6, node.process.wait(timeout=10))
|
||||||
|
self.start_node(0)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
assert_equal(e.error["code"], -1)
|
||||||
|
assert f"Internal bug detected: {msg_internal_bug}" in e.error["message"]
|
||||||
|
|
||||||
self.log.info("test getmemoryinfo")
|
self.log.info("test getmemoryinfo")
|
||||||
memory = node.getmemoryinfo()['locked']
|
memory = node.getmemoryinfo()['locked']
|
||||||
|
|||||||
Reference in new issue
Block a user