The MinGW-w64 toolchain links executables to the old msvcrt C Runtime Library that does not support the x modifier for the _wfopen() function.
Fixes #29014.
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--006a51241073e994b41acfe9ec718e94-->
For detailed information about the code coverage, see the test coverage report.
<!--021abf342d371248e50ceaed478a90ca-->
See the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.
However, the latter is available on Windows 10 only, which breaks our release compatibility with the older Windows versions.
No? According to the link you provided:
The Universal CRT is a component of the Windows operating system. It is included as a part of Windows 10, starting with the January Technical Preview, and it is available for older versions of the operating system via Windows Update.
Nevertheless, the second commit introduces an assertion in the AutoFile constructor.
Can you explain why this change makes sense? AutoFile already checks for nullptr.
Nevertheless, the second commit introduces an assertion in the AutoFile constructor.
Can you explain why this change makes sense?
AutoFilealready checks for nullptr.
The added assertion makes the issue with the unsupported x modifier explicit:
The
streams_tests/xor_filetest will fail without the first commit.
It is already explicit and will fail on master without the first commit:
unknown location(0): fatal error: in "streams_tests/xor_file": std::ios_base::failure[abi:cxx11]: AutoFile::write: file handle is nullptr: iostream error
<!--85328a0da195eb286784d51f73fa0af9-->
🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the documentation.
Possibly this is 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.
Leave a comment here, if you need help tracking down a confusing failure.
<sub>Debug: https://github.com/bitcoin/bitcoin/runs/21071017851</sub>
Concept NACK. I don't think we should remove test coverage from all other platforms, just to accomodate Windows. In the worse case this should just have a Windows paths with the modified modifiers, with documentation explaining why?
Concept NACK. I don't think we should remove test coverage from all other platforms, just to accomodate Windows.
It is not about Windows as a platform. It is about Windows users who download the Bitcoin Core release binaries. We should not treat them in a discriminatory way.
UPD. There are no cases where the "wbx" mode is used in the non-testing code, right?
It is already explicit and will fail on master without the first commit:
unknown location(0): fatal error: in "streams_tests/xor_file": std::ios_base::failure[abi:cxx11]: AutoFile::write: file handle is nullptr: iostream error
On the master branch the test passes on my system (Ubuntu 22.04):
$ ./src/test/test_bitcoin.exe -t streams_tests/xor_file
Running 1 test case...
00f0:err:msvcrt:msvcrt_get_flags incorrect mode flag: x
*** No errors detected
It is already explicit and will fail on master without the first commit:
unknown location(0): fatal error: in "streams_tests/xor_file": std::ios_base::failure[abi:cxx11]: AutoFile::write: file handle is nullptr: iostream errorOn the master branch the test passes on my system (Ubuntu 22.04):
$ ./src/test/test_bitcoin.exe -t streams_tests/xor_file Running 1 test case... 00f0:err:msvcrt:msvcrt_get_flags incorrect mode flag: x *** No errors detected
Can you add exact steps to reproduce? How is it possible that the file is a nullptr and the std::fwrite succeeds?
We should not treat them in a discriminatory way.
I don't see how fixing the tests in the way I've suggested would be discriminatory. It would make them work on Windows while retaining the current test for all other platforms.
Can you add exact steps to reproduce?
$ cat /etc/os-release | head -1
PRETTY_NAME="Ubuntu 22.04.3 LTS"
$ x86_64-w64-mingw32-g++-posix --version
x86_64-w64-mingw32-g++-posix (GCC) 10-posix 20220113
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ make -C depends -j $(nproc) HOST=x86_64-w64-mingw32 NO_QT=1
$ ./autogen.sh && ./configure CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site
$ make -j $(nproc) -C src test/test_bitcoin.exe
$ ./src/test/test_bitcoin.exe -t streams_tests/xor_file
Running 1 test case...
00f0:err:msvcrt:msvcrt_get_flags incorrect mode flag: x
*** No errors detected
We should not treat them in a discriminatory way.
I don't see how fixing the tests in the way I've suggested would be discriminatory. It would make them work on Windows while retaining the current test for all other platforms.
Thank you! Your suggestion has been implemented.
Can you add exact steps to reproduce?
$ cat /etc/os-release | head -1 PRETTY_NAME="Ubuntu 22.04.3 LTS" $ x86_64-w64-mingw32-g++-posix --version x86_64-w64-mingw32-g++-posix (GCC) 10-posix 20220113 Copyright (C) 2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ make -C depends -j $(nproc) HOST=x86_64-w64-mingw32 NO_QT=1 $ ./autogen.sh && ./configure CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site $ make -j $(nproc) -C src test/test_bitcoin.exe $ ./src/test/test_bitcoin.exe -t streams_tests/xor_file Running 1 test case... 00f0:err:msvcrt:msvcrt_get_flags incorrect mode flag: x *** No errors detected
It prints "No errors detected", which means that the test passed.
I also tried this locally, and the file is not a nullptr.
I also tried this locally, and the file is not a nullptr.
I agree. That is how it works on Linux in the Wine environment.
On Windows, being linked to msvcrt.dll, it fails.
I also tried this locally, and the file is not a nullptr.
I agree. That is how it works on Linux in the Wine environment.
On Windows, being linked to
msvcrt.dll, it fails.
Yes, either the file is a nullptr, in which case the test already fails, or it is not, in which case the test passes. In any case, the added assert in the dropped commit isn't needed here or elsewhere, and doesn't change the outcome here.
I also tried this locally, and the file is not a nullptr.
I agree. That is how it works on Linux in the Wine environment. On Windows, being linked to
msvcrt.dll, it fails.Yes, either the file is a nullptr, in which case the test already fails, or it is not, in which case the test passes. In any case, the added assert in the dropped commit isn't needed here or elsewhere, and doesn't change the outcome here.
You are right. That commit was my mistake.
FWIW, the _wfopen_s function reports an error for the x modifier even in Wine.
34 | + // The MinGW-w64 toolchain links executables to the old msvcrt C Runtime 35 | + // Library that does not support the `x` modifier for the _wfopen() 36 | + // function. It is possible to link to the new UCRT library instead. 37 | + // However, the most easiest way to do it is to use a new GCC with 38 | + // the -mcrtdll=ucrt option, which has been available since the commit 39 | + // https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=453cb585f0f8673a5d69d1b420ffd4b3f53aca00
I think this comment could just be something like Our usage of mingw-w64 and the msvcrt runtime does not support the x modifier for the _wfopen(). The other info seems a bit overkiil, I'm also not sure if it's correct. From a quick look, if you choose the runtime you want, when you compile mingw-w64, there's no need for any GCC flag.
The other info seems a bit overkiil, I'm also not sure if it's correct. From a quick look, if you choose the runtime you want, when you compile mingw-w64, there's no need for any GCC flag.
If the new runtime can be linked in guix builds, I'd say it would be better to use it, instead of patching the code. Or is there some downside I am missing?
If the new runtime is available in guix, I'd say it would be better to just use it, instead of patching the code. Or is there some downside I am missing?
I agree that we should move to the new runtime. I assume the downside is possibly dropping support for Windows 7, but I don't see why that would be a problem.
According to the docs, if it is missing, it can be installed via "Windows Update": https://devblogs.microsoft.com/cppblog/introducing-the-universal-crt/ . IIUC it is shipped by default on Windows 10.
if you choose the runtime you want, when you compile mingw-w64
Yes, there is --with-default-msvcrt=ucrt configuration option.
Yea. So I don't see why anything GCC related is required, or needs to be mentioned here.
The following patch
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -108,6 +108,16 @@ desirable for building Bitcoin Core release binaries."
base-libc
base-gcc))
+
+(define-public mingw-w64-x86_64-winpthreads-ucrt
+ (package
+ (inherit mingw-w64-x86_64-winpthreads)
+ (arguments
+ (substitute-keyword-arguments (package-arguments mingw-w64-x86_64-winpthreads)
+ ((#:configure-flags flags)
+ `(append ,flags
+ '("--with-default-msvcrt=ucrt")))))))
+
(define (gcc-mingw-patches gcc)
(package-with-extra-patches gcc
(search-our-patches "gcc-remap-guix-store.patch"
@@ -116,7 +126,7 @@ desirable for building Bitcoin Core release binaries."
(define (make-mingw-pthreads-cross-toolchain target)
"Create a cross-compilation toolchain package for TARGET"
(let* ((xbinutils (cross-binutils target))
- (pthreads-xlibc mingw-w64-x86_64-winpthreads)
+ (pthreads-xlibc mingw-w64-x86_64-winpthreads-ucrt)
(pthreads-xgcc (cross-gcc target
#:xgcc (gcc-mingw-patches mingw-w64-base-gcc)
#:xbinutils xbinutils
results in an error:
x86_64-w64-mingw32-ld: src/.libs/libwinpthread_la-thread.o: in function `pthread_create_wrapper':
/tmp/guix-build-mingw-w64-x86_64-winpthreads-11.0.1.drv-0/mingw-w64-v11.0.1/mingw-w64-libraries/winpthreads/src/thread.c:1518: undefined reference to `__intrinsic_setjmpex'
collect2: error: ld returned 1 exit status
Any ideas how to resolve it?
FWIW, the _wfopen_s function reports an error for the x modifier even in Wine.
So it reports an error but the unit tests don't fail? Is this another (different bug)?
We use the _wfopen. Microsoft docs suggest:
More-secure versions of these functions that perform more parameter validation and return error codes are available; see fopen_s, _wfopen_s.
So, the _wfopen_s is an alternative, which is not used now.
UPD. I've made a notice about a potential code change.
<!--9cd9c72976c961c55c7acef8f6ba82cd-->
I haven't reviewed this in detail, but it seems good enough for a temporary workaround.
lgtm ACK d4690e449ae470b8274176396564237ee6ec0f35
I think the documentation should still be adjusted (https://github.com/bitcoin/bitcoin/pull/29357#discussion_r1475960179). No point merging what I still think are incorrect docs, especially if the change is going to be backported. In any case, our unit test code also seems like the wrong place to put overly verbose documentaiton about GCC configuration options and the various windows runtimes.
The MinGW-w64 toolchain links executables to the old msvcrt C Runtime
Library that does not support the `x` modifier for the _wfopen()
function.
I think the documentation should still be adjusted (#29357 (comment)).
Sorry, it skipped my attention. Fixed now.
ACK d2fe90571e98e02617682561ea82acb1e2647827
ACK d2fe90571e98e02617682561ea82acb1e2647827 - the plan here should still be to migrate to the newer windows runtime.
post-merge ACK d2fe90571e98e02617682561ea82acb1e2647827
I've tested this fix earlier on the related issue but missed the PR.