This PR continues the ongoing effort to enforce IWYU warnings.
See Developer Notes.
src/util and treat them as errors
#34448
This PR continues the ongoing effort to enforce IWYU warnings.
See Developer Notes.
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
See the guideline for information on the review process. A summary of reviews will appear here.
Reviewers, this pull request conflicts with the following ones:
-dbcache default from total system RAM by l0rinc)pragma: export and other improvements by hebasto)HexStr payload by l0rinc)_MiB/_GiB consistently for byte conversions by l0rinc)If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
0In file included from /home/admin/actions-runner/_work/_temp/src/hash.h:16:
1/home/admin/actions-runner/_work/_temp/src/uint256.h:150:17: error: no member named 'HexDigit' in the global namespace
2 150 | *p1 = ::HexDigit(str[--digits]);
3 | ^~~~~~~~
4/home/admin/actions-runner/_work/_temp/src/uint256.h:152:38: error: no member named 'HexDigit' in the global namespace
5 152 | *p1 |= ((unsigned char)::HexDigit(str[--digits]) << 4);
6 | ^~~~~~~~
72 errors generated.
🚧 At least one of the CI tasks failed.
Task Valgrind, fuzz: https://github.com/bitcoin/bitcoin/actions/runs/21484505843/job/61889746047
LLM reason (✨ experimental): Compilation failed due to missing #include causing std::vector to be undefined in string.h and related code.
Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:
Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.
A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.
An intermittent issue.
Leave a comment here, if you need help tracking down a confusing failure.
7@@ -8,13 +8,16 @@
8 # libc symbols.
9 { "symbol": ["AT_HWCAP", "private", "<sys/auxv.h>", "public"] },
10 { "symbol": ["AT_HWCAP2", "private", "<sys/auxv.h>", "public"] },
11+ { "symbol": ["sched_param", "private", "<sched.h>", "public"] },
sched_param mentioned in https://github.com/include-what-you-use/include-what-you-use/issues/1809. Are you opening separate issues for different symbols, or just adding new missing symbols to https://github.com/include-what-you-use/include-what-you-use/issues/1809? Any reason to not add the missing mappings upstream; otherwise it seems like we are just accumulating workarounds for things that are not being fixed.
I don’t see
sched_parammentioned in include-what-you-use/include-what-you-use#1809.
An upstream fix has been proposed in https://github.com/include-what-you-use/include-what-you-use/pull/1918.
Any reason to not add the missing mappings upstream; otherwise it seems like we are just accumulating workarounds for things that are not being fixed.
Fixed upstream in https://github.com/include-what-you-use/include-what-you-use/pull/1923.
7@@ -8,13 +8,16 @@
8 # libc symbols.
9 { "symbol": ["AT_HWCAP", "private", "<sys/auxv.h>", "public"] },
10 { "symbol": ["AT_HWCAP2", "private", "<sys/auxv.h>", "public"] },
11+ { "symbol": ["sched_param", "private", "<sched.h>", "public"] },
12
13 # Fixed in https://github.com/include-what-you-use/include-what-you-use/pull/1706.
Fixed in https://github.com/include-what-you-use/include-what-you-use/pull/1706.
This was fixed in IWYU 0.25, which we are using, so this whole block should be able to be dropped?
8 #include <util/syserror.h>
9
10+#include <string>
11+
12 #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
13-#include <pthread.h>
5@@ -6,8 +6,11 @@
6 #ifndef BITCOIN_UTIL_TIME_H
7 #define BITCOIN_UTIL_TIME_H
8
9+#include <compat/compat.h>
compat.h being added here (with sys/time.h being added to it), rather than just including sys/time.h here? It seems like compat.h is starting to become a catch-all for includes, which is going in the opposite of the direction we want (and defeats the point of IWYU).
Why is
compat.hbeing added here (withsys/time.hbeing added to it), rather than just includingsys/time.hhere?
Without #include <compat/compat.h>, the code has to be:
0#ifdef WIN32
1#include <winsock2.h>
2#else
3#include <sys/time.h>
4#endif
This was actually my first iteration while working on this PR.
It seems like
compat.his starting to become a catch-all for includes, which is going in the opposite of the direction we want (and defeats the point of IWYU).
I agree. It would be great to have clearly documented use cases for compat.h.
Without #include <compat/compat.h>, the code has to be:
What is wrong with that code?
winsock2.h change seems unrelated, given IWYU is not run for Windows.
Also, the
winsock2.hchange seems unrelated, given IWYU is not run for Windows.
We still cross-compile for it and support native Windows builds. The winsock2.h header defines the timeval structure used here: https://github.com/bitcoin/bitcoin/blob/9f8764c814ead48d45b3822dfcc4cc2b3bda80d6/src/util/time.h#L151-L159
The code currently compiles without it only because of transitive includes, which is going in the opposite of the direction we want.
Without #include <compat/compat.h>, the code has to be:
What is wrong with that code?
I think it is missing the IWYU export. Generally, those should be avoided, but when it comes to compat headers, I think there is a benefit to just have them imported once to get one symbol cross-platform and then IWYU export them.
Otherwise, all call-sites will have to add:
0#ifdef WIN32
1#include <winsock2.h>
2#else
3#include <sys/time.h>
4#endif
,which is verbose, and hard to review, and easy to get wrong: As you say iwyu is not run on Windows and the transitive include can hide a missing winsock2 include.
So I think the options are either:
Otherwise, all call-sites will have to add:
Isn’t this the only callsite though? I don’t really see why we’d add #include <sys/time.h> to compat.h, just to have it included hundreds of places it isn’t needed, for the sake of saving 1 #ifdef.
I think before we make any more changes, we need to decide if we are actually doing IWYU, or only when it’s convenient/not inconvenient for Windows, and otherwise bundling things in 1 header to include everywhere else.
Isn’t this the only callsite though?
0$ git grep -l timeval -- src ":(exclude)src/leveldb" ":(exclude)src/secp256k1"
1src/crypto/ctaes/bench.c
2src/httpserver.cpp
3src/httpserver.h
4src/randomenv.cpp
5src/torcontrol.cpp
6src/util/sock.cpp
7src/util/time.cpp
8src/util/time.h
compat.h already includes sys/select.h, which also defines timeval. So why does sys/time.h need to be added to compat.h?
Alternatively, we can introduce a new compat_time.h header, which exports both winsock2.h and sys/time.h, and specify a new mapping in iwyu/bitcoin.core.imp:
0{ "symbol": ["timeval", "private", "<compat_time.h>", "public"] },
Isn’t this the only callsite though?
0$ git grep -l timeval -- src ":(exclude)src/leveldb" ":(exclude)src/secp256k1" 1src/crypto/ctaes/bench.c 2src/httpserver.cpp 3src/httpserver.h 4src/randomenv.cpp 5src/torcontrol.cpp 6src/util/sock.cpp 7src/util/time.cpp 8src/util/time.h
Right, my understanding is that all those would have to add the same
0#ifdef WIN32
1#include <winsock2.h>
2#else
3#include <sys/time.h>
4#endif
Alternatively, we can introduce a new
compat_time.hheader, which exports bothwinsock2.handsys/time.h, and specify a new mapping iniwyu/bitcoin.core.imp:0{ "symbol": ["timeval", "private", "<compat_time.h>", "public"] },
Yeah, that is a bit cleaner than the “iwyu export” hack. Maybe it can be named ./src/compat/time.h though?
compat.h?
compat.h, into many more of these mini-compat headers, and have many new includes (which themselves are some #ifdef logic + includes) in every file that previously only included compat.h? I do wonder if that will make it more or less likely to run into issues like #34454, or if that is really worth it to save some (hopefully comparatively ) small amount of code duplication/preprocessor time.
I’d say it would just be two:
But no strong opinion. Leaving this pull as-is is also fine.
compat.h, because timeval is already defined by sys/select.h.
along with reporting upstream
https://github.com/include-what-you-use/include-what-you-use/pull/1927.
Not sure how heavy the full compat net stack headers are to parse every time util/time.h is included. It may be faster to just include what is needed via compat/time.h instead of compat/compat.h, but I haven’t benchmarked this.
A third alternative could be to just move MillisToTimeval into compat.h
compat.h (or any other facade header) does not guarantee adherence to the ‘include what you use’ paradigm, as the timeval symbol can be defined in any of four different headers. Therefore, the decision of which header to include should be based on the headers already present in the given file.
unrelated, but the clang-format in the ci container seems broken? It removes the newlines. E.g. https://github.com/bitcoin/bitcoin/actions/runs/21830259022/job/62995439943#step:11:1639
0diff --git a/src/index/base.cpp b/src/index/base.cpp
1index 39d4dc7..0547fd1 100644
2--- a/src/index/base.cpp
3+++ b/src/index/base.cpp
4@@ -10,6 +10,7 @@
5 #include <interfaces/chain.h>
6 #include <interfaces/types.h>
7 #include <kernel/types.h>
8+#include <logging.h>
9 #include <node/abort.h>
10 #include <node/blockstorage.h>
11 #include <node/context.h>
12@@ -21,7 +22,6 @@
13 #include <uint256.h>
14 #include <undo.h>
15 #include <util/fs.h>
16-#include <util/log.h>
17 #include <util/string.h>
18 #include <util/thread.h>
19 #include <util/threadinterrupt.h>
20diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
21index cf31c9a..a805719 100644
22--- a/src/node/blockstorage.cpp
23+++ b/src/node/blockstorage.cpp
24@@ -3,7 +3,6 @@
25 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
26
27 #include <node/blockstorage.h>
28-
29 #include <arith_uint256.h>
30 #include <chain.h>
31 #include <consensus/params.h>
32@@ -30,7 +29,6 @@
33 #include <util/check.h>
34 #include <util/expected.h>
35 #include <util/fs.h>
36-#include <util/log.h>
37 #include <util/obfuscation.h>
38 #include <util/overflow.h>
39 #include <util/result.h>
40@@ -40,7 +38,6 @@
41 #include <util/time.h>
42 #include <util/translation.h>
43 #include <validation.h>
44-
45 #include <cerrno>
46 #include <compare>
47 #include <cstddef>
unrelated, but the clang-format in the ci container seems broken? It removes the newlines. E.g. https://github.com/bitcoin/bitcoin/actions/runs/21830259022/job/62995439943#step:11:1639
Looks like fix_includes.py strips empty lines and clang-format-diff.py fails to restore them.
unrelated, but the clang-format in the ci container seems broken? It removes the newlines. E.g. https://github.com/bitcoin/bitcoin/actions/runs/21830259022/job/62995439943#step:11:1639
Looks like
fix_includes.pystrips empty lines andclang-format-diff.pyfails to restore them.
Fixed in #34551.
The only conflicting PR has been merged, so now seems like a good time to get this reviewed.
Friendly ping @sedited @maflcko @willcl-ark :)
19 #include <string>
20 #include <string_view>
21 #include <thread>
22
23+#ifdef WIN32
24+#include <winsock2.h>
util/time.h)?
timeval type.
5@@ -6,7 +6,6 @@
6 #define BITCOIN_UTIL_THREADINTERRUPT_H
7
8 #include <sync.h>
9-#include <threadsafety.h>
pragma: export from sync.h, and retain this header, given it is used?
🚧 At least one of the CI tasks failed.
Task Windows-cross to x86_64, ucrt: https://github.com/bitcoin/bitcoin/actions/runs/21989888993/job/63533810608
LLM reason (✨ experimental): Test failure: std::future::wait_for is called with a plain long int instead of a std::chrono::duration, causing a type-mismatch in threadpool_tests.cpp.
Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:
Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.
A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.
An intermittent issue.
Leave a comment here, if you need help tracking down a confusing failure.
On Windows, the `winerror.h` header defines `WAIT_TIMEOUT` as a macro.
This introduces a fragile dependency on header inclusion order: if
Windows headers happen to be included before using `WAIT_TIMEOUT`, the
preprocessor expands it into a numeric literal, causing syntax errors.
Rename the variable to `TEST_WAIT_TIMEOUT` to remove this fragility and
avoid the collision entirely.
4@@ -5,17 +5,15 @@
5 #ifndef BITCOIN_UTIL_FS_H
6 #define BITCOIN_UTIL_FS_H
7
8-#include <tinyformat.h>
9+#include <tinyformat.h> // IWYU pragma: keep
// IWYU pragma: keep here?
7@@ -8,6 +8,7 @@
8
9 #include <crypto/siphash.h>
10 #include <logging/categories.h> // IWYU pragma: export
I agree that all pragmas should eventually be documented. However, addressing the existing ones here would significantly expand the scope of this PR and likely introduce more merge conflicts.
Since these older pragmas might need to be removed entirely rather than just documented, it would be best to loop in the original authors or reviewers to make that call. I think it makes the most sense to tackle this cleanup in follow-up PRs.
However, addressing the existing ones here would significantly expand the scope of this PR
Looking at the current state of this PR, there are 4 instances of // IWYU pragma: export in src/util/. Documenting or removing them, seems in scope for a PR that is fixing all issues in src/util/. If not done now, we’ll just have to come back again later and fix them anyways (and still have merge conflicts anyways, if there are any).
Since these older pragmas might need to be removed entirely rather than just documented, it would be best to loop in the original authors or reviewers to make that call.
Isn’t the best case if you can just delete the pragma, and fix the includes? Otherwise I’m not sure what call they would need to make. Either the pragma is removed, and includes fixed, there is a IWYU bug (which can be documented), or a rationale is written for keeping the pragma (even if it isn’t needed)?