The ccoincontrol fuzzer misses tests for a number of CCoinControl operations. Add them.
While at it, improve the oracle for the existing tests.
CCoinControl methods
#34026
The ccoincontrol fuzzer misses tests for a number of CCoinControl operations. Add them.
While at it, improve the oracle for the existing tests.
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/34026.
See the guideline for information on the review process.
If your review is incorrectly listed, please copy-paste <!–meta-tag:bot-skip–> into the comment that the bot should ignore.
76@@ -77,6 +77,12 @@ FUZZ_TARGET(coincontrol, .init = initialize_coincontrol)
77 },
78 [&] {
79 (void)coin_control.GetInputWeight(out_point);
80+ },
81+ [&] {
82+ (void)coin_control.GetSequence(out_point);
83+ },
84+ [&] {
85+ (void)coin_control.GetScripts(out_point);
These were indeed missing from https://maflcko.github.io/b-c-cov/fuzz.coverage/src/wallet/coincontrol.cpp.gcov.html - there are quite a few more, consider adding those as well
Do you think it would be better to add the other ones in a separate PR or is it better to add them all in this one?
code review ACK 31904f1ba1de49890f605f1d7c907790780831ec
It’s fine as is, but I think we could improve this harness a little bit by adding some assertions. Some quite simple examples:
0@@ -87,9 +87,7 @@ FUZZ_TARGET(coincontrol, .init = initialize_coincontrol)
1 [&] {
2 uint32_t sequence{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
3 (void)coin_control.Select(out_point).SetSequence(sequence);
4- },
5- [&] {
6- (void)coin_control.Select(out_point).GetSequence();
7+ assert(coin_control.Select(out_point).GetSequence() == sequence);
8 },
0@@ -108,10 +106,8 @@ FUZZ_TARGET(coincontrol, .init = initialize_coincontrol)
1 [&] {
2 unsigned int pos{fuzzed_data_provider.ConsumeIntegral<unsigned int>()};
3 (void)coin_control.Select(out_point).SetPosition(pos);
4- },
5- [&] {
6- (void)coin_control.Select(out_point).GetPosition();
7- });
8+ assert(coin_control.Select(out_point).GetPosition() == pos);
9+ });
106+ const auto& scripts = coin_control.Select(out_point).GetScripts();
107+ assert(scripts.first && *scripts.first == script);
108+ },
109+ [&] {
110+ const CScriptWitness script_wit{ConsumeScriptWitness(fuzzed_data_provider)};
111+ (void)coin_control.Select(out_point).SetScriptWitness(script_wit);
SetScriptWitness is already void:
0 coin_control.Select(out_point).SetScriptWitness(script_wit);
77+ assert(!coin_control.HasSelected());
78 },
79 [&] {
80- (void)coin_control.ListSelected();
81+ const std::vector<COutPoint> selected = coin_control.ListSelected();
82+ assert(selected.empty() == !coin_control.HasSelected());
78 },
79 [&] {
80- (void)coin_control.ListSelected();
81+ const std::vector<COutPoint> selected = coin_control.ListSelected();
82+ assert(selected.empty() == !coin_control.HasSelected());
83+ for (const auto& out : selected)
84+ assert(coin_control.IsSelected(out));
85 },
86 [&] {
87 int64_t weight{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
88 (void)coin_control.SetInputWeight(out_point, weight);
89+ assert(coin_control.GetInputWeight(out_point) == weight);
GetInputWeight return nullptr? can we exercise that path as well?
GetInputWeight() returns a std::optional<int64_t>, so I don’t think it can return a nullptr. It does return a std::nullopt when the coin is not selected, but I think adding a check for that would be too close to duplicating the implementation.
nullopt of course. We should at least exercise that code path.
102+ [&] {
103+ const CScript script{ConsumeScript(fuzzed_data_provider)};
104+ (void)coin_control.Select(out_point).SetScriptSig(script);
105+ assert(coin_control.Select(out_point).HasScripts());
106+ const auto& scripts = coin_control.Select(out_point).GetScripts();
107+ assert(scripts.first && *scripts.first == script);
Given the std::optional’s operator== overload, wouldn’t this suffice
0 assert(scripts.first == script);
?
100+ assert(coin_control.Select(out_point).GetSequence() == sequence);
101+ },
102+ [&] {
103+ const CScript script{ConsumeScript(fuzzed_data_provider)};
104+ (void)coin_control.Select(out_point).SetScriptSig(script);
105+ assert(coin_control.Select(out_point).HasScripts());
Select mutates m_selection_pos - we could do selection separately
HasSelectedOrder() and GetSelectionPos() from header are still untested
42@@ -43,40 +43,70 @@ FUZZ_TARGET(coincontrol, .init = initialize_coincontrol)
43 }
44 out_point = *optional_out_point;
45 },
46- [&] {
47- (void)coin_control.HasSelected();
115 },
116 [&] {
117- (void)coin_control.GetInputWeight(out_point);
118+ auto& input = coin_control.Select(out_point);
119+ unsigned int pos{fuzzed_data_provider.ConsumeIntegral<unsigned int>()};
120+ input.SetPosition(pos);
coin_control.Select?
Yes, that is correct and intentional.
Select() assigns a default sequential position, but the goal of this test is to exercise the SetPosition() setter directly. We want to verify that the PreselectedInput object handles arbitrary position values correctly, even if they differ from the default sequence assigned by Select().
The improved harness from this PR increased the mutation score of the coin_control target compared to the master branch. See:
The only uncaught mutant is:
0diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp
1index 873c5ab383..e83f8d451a 100644
2--- a/src/wallet/coincontrol.cpp
3+++ b/src/wallet/coincontrol.cpp
4@@ -25,7 +25,7 @@ bool CCoinControl::IsSelected(const COutPoint& outpoint) const
5 bool CCoinControl::IsExternalSelected(const COutPoint& outpoint) const
6 {
7 const auto it = m_selected.find(outpoint);
8- return it != m_selected.end() && it->second.HasTxOut();
9+ return it != m_selected.end() || it->second.HasTxOut();
10 }
which can be killed with the following diff - it checks that when there is no tx out for a given input, it’s not external selected:
0 auto& input = coin_control.Select(out_point);
1- input.SetTxOut(tx_out);
2- assert(input.HasTxOut());
3- assert(input.GetTxOut() == tx_out);
4- assert(coin_control.IsExternalSelected(out_point));
5+ const auto set_tx_out{fuzzed_data_provider.ConsumeBool()};
6+ if (set_tx_out) {
7+ input.SetTxOut(tx_out);
8+ }
9+ auto has_tx_out{input.HasTxOut()};
10+ auto is_external_selected{coin_control.IsExternalSelected(out_point)};
11+ if (set_tx_out) {
12+ assert(has_tx_out);
13+ assert(input.GetTxOut() == tx_out);
14+ assert(is_external_selected);
15+ } else if (!has_tx_out) {
16+ assert(!is_external_selected);
17+ }
18 },
103+ assert(!weight.has_value());
104+ }
105+ (void)coin_control.GetSequence(out_point);
106+ },
107+ [&] {
108+ (void)coin_control.GetScripts(out_point);
They are pretty simple wrappers:
0std::pair<std::optional<CScript>, std::optional<CScriptWitness>> CCoinControl::GetScripts(const COutPoint& outpoint) const
1{
2 const auto it = m_selected.find(outpoint);
3 return it != m_selected.end() ? m_selected.at(outpoint).GetScripts() : std::make_pair(std::nullopt, std::nullopt);
4}
The only way I can think of adding assertions would lead to duplicating logic, which has already been deemed unnecessary.
I only reviewed it lightly, but it seems to me we’re not actually checking the cross-method invariants, just running them and hoping they don’t throw - which isn’t a very high bar, though we do that sometimes in other places, so I won’t block, but consider the following adjustments (untested):
0diff --git a/src/wallet/test/fuzz/coincontrol.cpp b/src/wallet/test/fuzz/coincontrol.cpp
1--- a/src/wallet/test/fuzz/coincontrol.cpp (revision 722e460d4d6248b427d3a92b357d1b5ff9fc0a4f)
2+++ b/src/wallet/test/fuzz/coincontrol.cpp (date 1773671084564)
3@@ -77,11 +77,11 @@
4 }
5 },
6 [&] {
7- (void)coin_control.UnSelect(out_point);
8+ coin_control.UnSelect(out_point);
9 assert(!coin_control.IsSelected(out_point));
10 },
11 [&] {
12- (void)coin_control.UnSelectAll();
13+ coin_control.UnSelectAll();
14 assert(!coin_control.HasSelected());
15 },
16 [&] {
17@@ -92,30 +92,30 @@
18 },
19 [&] {
20 int64_t weight{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
21- (void)coin_control.SetInputWeight(out_point, weight);
22+ coin_control.SetInputWeight(out_point, weight);
23 assert(coin_control.GetInputWeight(out_point) == weight);
24 },
25 [&] {
26- auto weight = coin_control.GetInputWeight(out_point);
27- if (!coin_control.IsSelected(out_point)) {
28- assert(!weight.has_value());
29- }
30- (void)coin_control.GetSequence(out_point);
31+ const bool is_selected = coin_control.IsSelected(out_point);
32+ assert(coin_control.GetInputWeight(out_point) || !is_selected);
33+ assert(coin_control.GetSequence(out_point) || !is_selected);
34 },
35 [&] {
36- (void)coin_control.GetScripts(out_point);
37+ const auto scripts = coin_control.GetScripts(out_point);
38+ assert(coin_control.IsSelected(out_point) || (!scripts.first && !scripts.second));
39 },
40 [&] {
41- (void)coin_control.HasSelectedOrder();
42+ assert(coin_control.HasSelectedOrder() || !coin_control.GetSelectionPos(out_point));
43 },
44 [&] {
45- (void)coin_control.GetSelectionPos(out_point);
46+ assert(!coin_control.GetSelectionPos(out_point) || coin_control.IsSelected(out_point));
47 },
48 [&] {
49 auto& input = coin_control.Select(out_point);
50 uint32_t sequence{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
51 input.SetSequence(sequence);
52 assert(input.GetSequence() == sequence);
53+ assert(coin_control.GetSequence(out_point) == sequence);
54 },
55 [&] {
56 auto& input = coin_control.Select(out_point);
57@@ -123,6 +123,7 @@
58 input.SetScriptSig(script);
59 assert(input.HasScripts());
60 assert(input.GetScripts().first == script);
61+ assert(coin_control.GetScripts(out_point).first == script);
62 },
63 [&] {
64 auto& input = coin_control.Select(out_point);
65@@ -130,12 +131,14 @@
66 input.SetScriptWitness(script_wit);
67 assert(input.HasScripts());
68 assert(input.GetScripts().second->stack == script_wit.stack);
69+ assert(coin_control.GetScripts(out_point).second->stack == script_wit.stack);
70 },
71 [&] {
72 auto& input = coin_control.Select(out_point);
73 unsigned int pos{fuzzed_data_provider.ConsumeIntegral<unsigned int>()};
74 input.SetPosition(pos);
75 assert(input.GetPosition() == pos);
76+ assert(coin_control.GetSelectionPos(out_point) == pos);
77 });
78 }
79 }
The `ccoincontrol` fuzzer misses tests for a number of CCoinControl
operations. Add them.
I only reviewed it lightly, but it seems to me we’re not actually checking the cross-method invariants, just running them and hoping they don’t throw - which isn’t a very high bar, though we do that sometimes in other places, so I won’t block, but consider the following adjustments (untested):
0diff --git a/src/wallet/test/fuzz/coincontrol.cpp b/src/wallet/test/fuzz/coincontrol.cpp 1--- a/src/wallet/test/fuzz/coincontrol.cpp (revision 722e460d4d6248b427d3a92b357d1b5ff9fc0a4f) 2+++ b/src/wallet/test/fuzz/coincontrol.cpp (date 1773671084564) 3@@ -77,11 +77,11 @@ 4 } 5 }, 6 [&] { 7- (void)coin_control.UnSelect(out_point); 8+ coin_control.UnSelect(out_point); 9 assert(!coin_control.IsSelected(out_point)); 10 }, 11 [&] { 12- (void)coin_control.UnSelectAll(); 13+ coin_control.UnSelectAll(); 14 assert(!coin_control.HasSelected()); 15 }, 16 [&] { 17@@ -92,30 +92,30 @@ 18 }, 19 [&] { 20 int64_t weight{fuzzed_data_provider.ConsumeIntegral<int64_t>()}; 21- (void)coin_control.SetInputWeight(out_point, weight); 22+ coin_control.SetInputWeight(out_point, weight); 23 assert(coin_control.GetInputWeight(out_point) == weight); 24 }, 25 [&] { 26- auto weight = coin_control.GetInputWeight(out_point); 27- if (!coin_control.IsSelected(out_point)) { 28- assert(!weight.has_value()); 29- } 30- (void)coin_control.GetSequence(out_point); 31+ const bool is_selected = coin_control.IsSelected(out_point); 32+ assert(coin_control.GetInputWeight(out_point) || !is_selected); 33+ assert(coin_control.GetSequence(out_point) || !is_selected);
This change leads to a crash:
0fuzz: wallet/test/fuzz/coincontrol.cpp:100: auto wallet::(anonymous namespace)::coincontrol_fuzz_target(FuzzBufferType)::(anonymous class)::operator()() const: Assertion `coin_control.GetInputWeight(out_point) || !is_selected' failed.
1==14181== ERROR: libFuzzer: deadly signal
2 [#0](/bitcoin-bitcoin/0/) 0x5a0af5d4fe85 in __sanitizer_print_stack_trace (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1ca2e85) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
3 [#1](/bitcoin-bitcoin/1/) 0x5a0af5ca999c in fuzzer::PrintStackTrace() (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1bfc99c) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
4 [#2](/bitcoin-bitcoin/2/) 0x5a0af5c8fa27 in fuzzer::Fuzzer::CrashCallback() (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1be2a27) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
5 [#3](/bitcoin-bitcoin/3/) 0x7e3978a4532f (/usr/lib/x86_64-linux-gnu/libc.so.6+0x4532f) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
6 [#4](/bitcoin-bitcoin/4/) 0x7e3978a9eb2b in __pthread_kill_implementation nptl/pthread_kill.c:43:17
7 [#5](/bitcoin-bitcoin/5/) 0x7e3978a9eb2b in __pthread_kill_internal nptl/pthread_kill.c:78:10
8 [#6](/bitcoin-bitcoin/6/) 0x7e3978a9eb2b in pthread_kill nptl/pthread_kill.c:89:10
9 [#7](/bitcoin-bitcoin/7/) 0x7e3978a4527d in raise signal/../sysdeps/posix/raise.c:26:13
10 [#8](/bitcoin-bitcoin/8/) 0x7e3978a288fe in abort stdlib/abort.c:79:7
11 [#9](/bitcoin-bitcoin/9/) 0x7e3978a2881a in __assert_fail_base assert/assert.c:96:3
12 [#10](/bitcoin-bitcoin/10/) 0x7e3978a3b516 in __assert_fail assert/assert.c:105:3
13 [#11](/bitcoin-bitcoin/11/) 0x5a0af66a51a7 in wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_11::operator()() const /home/chandra/bitcoin/src/wallet/test/fuzz/coincontrol.cpp:100:17
14 [#12](/bitcoin-bitcoin/12/) 0x5a0af66a51a7 in unsigned long CallOneOf<wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_0, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_2, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_3, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_4, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_5, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_6, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_7, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_8, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_9, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_10, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_11, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_12, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_13, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_14, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_15, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_16, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_17, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_18>(FuzzedDataProvider&, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_0, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_2, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_3, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_4, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_5, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_6, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_7, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_8, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_9, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_10, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_11, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_12, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_13, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_14, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_15, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_16, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_17, wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_18) /home/chandra/bitcoin/src/test/fuzz/util.h:42:27
15 [#13](/bitcoin-bitcoin/13/) 0x5a0af66a51a7 in wallet::(anonymous namespace)::coincontrol_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>) /home/chandra/bitcoin/src/wallet/test/fuzz/coincontrol.cpp:37:9
16 [#14](/bitcoin-bitcoin/14/) 0x5a0af6741bb5 in std::function<void (std::span<unsigned char const, 18446744073709551615ul>)>::operator()(std::span<unsigned char const, 18446744073709551615ul>) const /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/std_function.h:591:9
17 [#15](/bitcoin-bitcoin/15/) 0x5a0af6741bb5 in test_one_input(std::span<unsigned char const, 18446744073709551615ul>) /home/chandra/bitcoin/src/test/fuzz/fuzz.cpp:88:5
18 [#16](/bitcoin-bitcoin/16/) 0x5a0af6741bb5 in LLVMFuzzerTestOneInput /home/chandra/bitcoin/src/test/fuzz/fuzz.cpp:216:5
19 [#17](/bitcoin-bitcoin/17/) 0x5a0af5c90ff4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1be3ff4) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
20 [#18](/bitcoin-bitcoin/18/) 0x5a0af5c906e9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1be36e9) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
21 [#19](/bitcoin-bitcoin/19/) 0x5a0af5c91ed5 in fuzzer::Fuzzer::MutateAndTestOne() (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1be4ed5) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
22 [#20](/bitcoin-bitcoin/20/) 0x5a0af5c92a35 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1be5a35) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
23 [#21](/bitcoin-bitcoin/21/) 0x5a0af5c7fd0f in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1bd2d0f) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
24 [#22](/bitcoin-bitcoin/22/) 0x5a0af5caa396 in main (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1bfd396) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
25 [#23](/bitcoin-bitcoin/23/) 0x7e3978a2a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
26 [#24](/bitcoin-bitcoin/24/) 0x7e3978a2a28a in __libc_start_main csu/../csu/libc-start.c:360:3
27 [#25](/bitcoin-bitcoin/25/) 0x5a0af5c74cf4 in _start (/home/chandra/bitcoin/build_fuzz/bin/fuzz+0x1bc7cf4) (BuildId: 49a35e3f207fc4eb2d208d6286597a919c2718da)
The correct logic should be:
0assert(!coin_control.GetInputWeight(out_point) || is_selected);
1assert(!coin_control.GetSequence(out_point) || is_selected);
because $\neg S \implies \neg W$ is boolean equivalent to $S \lor \neg W$.
Other than this, incorporated rest of the suggestions as is and rebased the branch on top of the latest master.