upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-07-30 10:38:12 -0300
committerGitHub <noreply@github.com>2026-07-30 10:38:12 -0300
commit2ed9aed2ea9e302b3b36b37806ec03f2cccaaed1 (patch)
treeab30eade9435c074ee08c70303b8a15c08770b4f /src/main.cpp
parentf30f45849ecd45be6a073b6b1d308e1c12b8b52b (diff)
build: check format strings, which nothing ever did (#44)
The segfault in issue #5 was a format string: `%I64d` is MSVC-only, glibc parses it as the GNU `I` flag with a width of 64 and an `int` conversion, the vararg run desynchronises, and the following `%s` dereferences an integer. It killed the node mid-sync at the first block carrying a real transaction, deterministically. GCC can catch this. It never got the chance, for two reasons that had to be fixed together: - `-w` sat in both makefiles and suppressed every diagnostic. It cannot be narrowed; it wins over any -W or -Werror= that follows, so it had to go. The four -Wno- entries replacing it are the categories this 2009-era tree actually produces (measured: 248 deprecated-declarations, 157 write-strings, 18 narrowing, 1 unused-result), silenced by name instead of wholesale. - Even with -Wformat on, nothing was checked. GCC only inspects format strings for functions it knows are printf-like, and every format string here goes through strprintf, error, my_snprintf, or OutputDebugStringF -- `printf` itself is #defined to the last of those. None carried a format attribute, so the entire tree was invisible to the check. They are annotated now. Annotating surfaced 77 warnings across 17 distinct sites, all fixed here. Most were size_t or int64 passed to %d, harmless on x86-64 but wrong. Two were not cosmetic: - CBlockIndex::ToString printed pprev/pnext with %08x, truncating both pointers to 32 bits, so the two fields that line exists to show were unreliable on every 64-bit build. - CInv::GetCommand threw "type=% unknown type", where the % ate the space as a flag and the u as its conversion. The message read "type= 3nknown type". PRId64 is now one spelling for every target. Its MSVCRT branch was what produced "I64d" in the first place, it is pointless against UCRT which takes the C99 forms, the rest of the tree already prints int64 with %lld on Windows, and its only user (i64tostr) is dead code. Collapsing it lets both builds share the gnu_printf archetype -- ms_printf would reject %zu, which this tree uses and UCRT supports, while waving through the %I64d that crashes. Verified on both platforms: clean build, and reintroducing the issue #5 specifier now fails compilation rather than shipping. main.h:410:50: error: unknown conversion type character 'I' in format main.h:410:70: error: format '%s' expects argument of type 'char*', but argument 3 has type 'long long int' That second line is the crash itself, caught at build time. Runtime checked on both: node syncs past the block from issue #5, and the repaired log lines read correctly -- before: CTxOut(nValue= 50.%08I64d, scriptPubKey=(null)) after: CTxOut(nValue=50.00000000, scriptPubKey=0xE1C7EF3E706002) Four '_WIN32_WINNT redefined' warnings remain on Windows. Silencing them means letting a system header pick the Windows API level instead of this tree, which is a separate decision from format checking.
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp16
1 files changed, 8 insertions, 8 deletions
diff --git a/src/main.cpp b/src/main.cpp
index bb317d2..c882b0b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -898,7 +898,7 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPoo
898 } 898 }
899 899
900 if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) 900 if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
901 return error("ConnectInputs() : %s prevout.n out of range %d %d %d", GetHash().ToString().substr(0,6).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size()); 901 return error("ConnectInputs() : %s prevout.n out of range %d %d %d", GetHash().ToString().substr(0,6).c_str(), prevout.n, (int)txPrev.vout.size(), (int)txindex.vSpent.size());
902 902
903 // If prev is coinbase, check that it's matured 903 // If prev is coinbase, check that it's matured
904 if (txPrev.IsCoinBase()) 904 if (txPrev.IsCoinBase())
@@ -1690,14 +1690,14 @@ void PrintBlockTree()
1690 pindex->nBlockPos, 1690 pindex->nBlockPos,
1691 block.GetHash().ToString().substr(0,14).c_str(), 1691 block.GetHash().ToString().substr(0,14).c_str(),
1692 DateTimeStr(block.nTime).c_str(), 1692 DateTimeStr(block.nTime).c_str(),
1693 block.vtx.size()); 1693 (int)block.vtx.size());
1694 1694
1695 CRITICAL_BLOCK(cs_mapWallet) 1695 CRITICAL_BLOCK(cs_mapWallet)
1696 { 1696 {
1697 if (mapWallet.count(block.vtx[0].GetHash())) 1697 if (mapWallet.count(block.vtx[0].GetHash()))
1698 { 1698 {
1699 CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; 1699 CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
1700 printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); 1700 printf(" mine: %d %d %lld", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
1701 } 1701 }
1702 } 1702 }
1703 printf("\n"); 1703 printf("\n");
@@ -1759,7 +1759,7 @@ bool ProcessMessages(CNode* pfrom)
1759 CDataStream& vRecv = pfrom->vRecv; 1759 CDataStream& vRecv = pfrom->vRecv;
1760 if (vRecv.empty()) 1760 if (vRecv.empty())
1761 return true; 1761 return true;
1762 LogPrint("net", "ProcessMessages(%d bytes)\n", vRecv.size()); 1762 LogPrint("net", "ProcessMessages(%d bytes)\n", (int)vRecv.size());
1763 1763
1764 // 1764 //
1765 // Message format 1765 // Message format
@@ -1783,7 +1783,7 @@ bool ProcessMessages(CNode* pfrom)
1783 break; 1783 break;
1784 } 1784 }
1785 if (pstart - vRecv.begin() > 0) 1785 if (pstart - vRecv.begin() > 0)
1786 if (LogAcceptsCategory("net")) printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin()); 1786 if (LogAcceptsCategory("net")) printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", (int)(pstart - vRecv.begin()));
1787 vRecv.erase(vRecv.begin(), pstart); 1787 vRecv.erase(vRecv.begin(), pstart);
1788 1788
1789 // Read header 1789 // Read header
@@ -1836,7 +1836,7 @@ bool ProcessMessages(CNode* pfrom)
1836bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) 1836bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
1837{ 1837{
1838 static map<unsigned int, vector<unsigned char> > mapReuseKey; 1838 static map<unsigned int, vector<unsigned char> > mapReuseKey;
1839 if (LogAcceptsCategory("net")) { printf("received: %-12s (%d bytes) ", strCommand.c_str(), vRecv.size()); for (int i = 0; i < min(vRecv.size(), (unsigned int)25); i++) printf("%02x ", vRecv[i] & 0xff); printf("\n"); } 1839 if (LogAcceptsCategory("net")) { printf("received: %-12s (%d bytes) ", strCommand.c_str(), (int)vRecv.size()); for (int i = 0; i < min(vRecv.size(), (unsigned int)25); i++) printf("%02x ", vRecv[i] & 0xff); printf("\n"); }
1840 if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) 1840 if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0)
1841 { 1841 {
1842 if (LogAcceptsCategory("net")) printf("dropmessages DROPPING RECV MESSAGE\n"); 1842 if (LogAcceptsCategory("net")) printf("dropmessages DROPPING RECV MESSAGE\n");
@@ -2171,7 +2171,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
2171 2171
2172 2172
2173 if (!vRecv.empty()) 2173 if (!vRecv.empty())
2174 if (LogAcceptsCategory("net")) printf("ProcessMessage(%s) : %d extra bytes\n", strCommand.c_str(), vRecv.size()); 2174 if (LogAcceptsCategory("net")) printf("ProcessMessage(%s) : %d extra bytes\n", strCommand.c_str(), (int)vRecv.size());
2175 2175
2176 return true; 2176 return true;
2177} 2177}
@@ -2885,7 +2885,7 @@ bool BitcoinMiner()
2885 } 2885 }
2886 pblock->nBits = nBits; 2886 pblock->nBits = nBits;
2887 pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nBestHeight + 1, nFees); 2887 pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nBestHeight + 1, nFees);
2888 if (LogAcceptsCategory("net")) printf("\n\nRunning BitcoinMiner with %d transactions in block\n", pblock->vtx.size()); 2888 if (LogAcceptsCategory("net")) printf("\n\nRunning BitcoinMiner with %d transactions in block\n", (int)pblock->vtx.size());
2889 2889
2890 2890
2891 // 2891 //