Repository: bitcoin/bitcoin (language: cpp)

Issue:
fuzz: wallet_bdb_parser: implicit-signed-integer-truncation wallet/migrate.cpp:554:35 
Full error:

```
wallet/migrate.cpp:554:35: runtime error: implicit conversion from type 'int64_t' (aka 'long') of value -1 (64-bit, signed) to type 'uint32_t' (aka 'unsigned int') changed the value to 4294967295 (32-bit, unsigned)
```

The code:

```cpp
uint32_t expected_last_page = (size / page_size) - 1;
```

This may lead to a fuzz runtime error when `(size / page_size)` is `0`. I don't think this can lead to issues for real users, because it can only happen with corrupt files and the next line should throw `"Last page number could not fit in file"`, or in the case where `outer_meta.last_page` is corrupt as well, and equal to `4294967295`, the following read should fail and throw.


Discussion / hints:
Found by @murchandamus in https://github.com/bitcoin-core/qa-assets/pull/186#issuecomment-2154348655

```
Run wallet_bdb_parser with args ['/ci_container_base/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/src/test/fuzz/fuzz', '-runs=1', PosixPath('/ci_container_base/ci/scratch/qa-assets/fuzz_seed_corpus/wallet_bdb_parser')]INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 1090373666
INFO: Loaded 1 modules   (584206 inline 8-bit counters): 584206 [0x55fc8b5c2ec8, 0x55fc8b6518d6), 
INFO: Loaded 1 PC tables (584206 PCs): 584206 [0x55fc8b6518d8,0x55fc8bf3b9b8), 
INFO:       43 files found in /ci_container_base/ci/scratch/qa-assets/fuzz_seed_corpus/wallet_bdb_parser
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: seed corpus: files: 43 min: 1b max: 1237b total: 31691b rss: 160Mb
wallet/migrate.cpp:554:35: runtime error: implicit conversion from type 'int64_t' (aka 'long') of value -1 (64-bit, signed) to type 'uint32_t' (aka 'unsigned int') changed the value to 4294967295 (32-bit, unsigned)
    #0 0x55fc897e51c3 in wallet::BerkeleyRODatabase::Open() src/wallet/migrate.cpp:554:35
    #1 0x55fc897f58de in wallet::BerkeleyRODatabase::BerkeleyRODatabase(fs::path const&, bool) src/./wallet/migrate.h:29:19
    #2 0x55fc897eb8fc in std::__detail::_MakeUniq<wallet::BerkeleyRODatabase>::__single_object std::make_unique<wallet::BerkeleyRODatabase, fs::path&>(fs::path&) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/unique_ptr.h:1070:34
    #3 0x55fc897eb8fc in wallet::MakeBerkeleyRODatabase(fs::path const&, wallet::DatabaseOptions const&, wallet::DatabaseStatus&, bilingual_str&) src/wallet/migrate.cpp:775:50
    #4 0x55fc88560dab in wallet_bdb_parser_fuzz_target(Span<unsigned char const>) src/wallet/test/fuzz/wallet_bdb_parser.cpp:57:13
    #5 0x55fc88adfc3d in std::function<void (Span<unsigned char const>)>::operator()(Span<unsigned char const>) const /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/std_function.h:591:9
    #6 0x55fc88adfc3d in LLVMFuzzerTestOneInput src/test/fuzz/fuzz.cpp:201:5
    #7 0x55fc88402484 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/ci_container_base/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/src/test/fuzz/fuzz+0x1ab6484) (BuildId: e6ce4f280e684054dbb9f999521c5970ef6be186)
    #8 0x55fc88401b79 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (/ci_container_base/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/src/test/fuzz/fuzz+0x1ab5b79) (BuildId: e6ce4f280e684054dbb9f999521c5970ef6be186)
    #9 0x55fc88403796 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (/ci_container_base/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/src/test/fuzz/fuzz+0x1ab7796) (BuildId: e6ce4f280e684054dbb9f999521c5970ef6be186)
    #10 0x55fc88403ca7 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (/ci_container_base/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/src/test/fuzz/fuzz+0x1ab7ca7) (BuildId: e6ce4f280e684054dbb9f999521c5970ef6be186)
    #11 0x55fc883f119f in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/ci_container_base/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/src/test/fuzz/fuzz+0x1aa519f) (BuildId: e6ce4f280e684054dbb9f999521c5970ef6be186)
    #12 0x55fc8841b826 in main (/ci_container_base/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/src/test/fuzz/fuzz+0x1acf826) (BuildId: e6ce4f280e684054dbb9f999521c5970ef6be186)
    #13 0x7f7a35bbf1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 08134323d00289185684a4cd177d202f39c2a5f3)
    #14 0x7f7a35bbf28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 08134323d00289185684a4cd177d202f39c2a5f3)
    #15 0x55fc883e6184 in _start (/ci_container_base/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/src/test/fuzz/fuzz+0x1a9a184) (BuildId: e6ce4f280e684054dbb9f999521c5970ef6be186)

SUMMARY: UndefinedBehaviorSanitizer: implicit-signed-integer-truncation wallet/migrate.cpp:554:35 
MS: 0 ; base unit: 0000000000000000000000000000000000000000
artifact_prefix='./'; Test unit written to ./crash-1376869be72eebcc87fe737020add634b1a29533
```

File: https://github.com/bitcoin-core/qa-assets/blob/24c507b3ea6263e6b121fb8dced01123065c44c2/fuzz_seed_corpus/wallet_bdb_parser/1376869be72eebcc87fe737020add634b1a29533

Fix patch:
diff --git a/src/wallet/migrate.cpp b/src/wallet/migrate.cpp
index 09254a76ad89a..d7d8577374346 100644
--- a/src/wallet/migrate.cpp
+++ b/src/wallet/migrate.cpp
@@ -551,7 +551,7 @@ void BerkeleyRODatabase::Open()
     // }
 
     // Check the last page number
-    uint32_t expected_last_page = (size / page_size) - 1;
+    uint32_t expected_last_page{uint32_t((size / page_size) - 1)};
     if (outer_meta.last_page != expected_last_page) {
         throw std::runtime_error("Last page number could not fit in file");
     }


Test patch: