139faf428SLouis Dionne //===----------------------------------------------------------------------===//
239faf428SLouis Dionne //
339faf428SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
439faf428SLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
539faf428SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
639faf428SLouis Dionne //
739faf428SLouis Dionne //===----------------------------------------------------------------------===//
839faf428SLouis Dionne
939faf428SLouis Dionne // Make sure that the iostreams are initialized before everything else.
1039faf428SLouis Dionne // This has been an issue when statically linking libc++ in some contexts.
1139faf428SLouis Dionne // See https://llvm.org/PR28954 for details.
1239faf428SLouis Dionne //
1339faf428SLouis Dionne // This test works by checking that std::{cin,cout,cerr} is the same in a
1439faf428SLouis Dionne // static object constructor and in the main function. It dumps the memory of
1539faf428SLouis Dionne // each stream in the static object constructor and compares it with the memory
1639faf428SLouis Dionne // in the main function.
1739faf428SLouis Dionne //
1839faf428SLouis Dionne // The assumption is that if there are no uses of the stream object (such as
1939faf428SLouis Dionne // construction), then its memory must be the same. In the case where the test
2039faf428SLouis Dionne // "fails" and we are actually accessing an uninitialized object when we perform
2139faf428SLouis Dionne // the memcpy, the behavior is technically undefined (so the test could still
2239faf428SLouis Dionne // pass).
2339faf428SLouis Dionne
2439faf428SLouis Dionne #include <cassert>
2539faf428SLouis Dionne #include <cstring>
2639faf428SLouis Dionne #include <iostream>
2739faf428SLouis Dionne
28*f4c1258dSLouis Dionne #include "test_macros.h"
29*f4c1258dSLouis Dionne
3039faf428SLouis Dionne struct Checker {
3139faf428SLouis Dionne char *cerr_mem_dump;
3239faf428SLouis Dionne char *cin_mem_dump;
3339faf428SLouis Dionne char *cout_mem_dump;
3439faf428SLouis Dionne char *clog_mem_dump;
3539faf428SLouis Dionne
CheckerChecker3639faf428SLouis Dionne Checker()
3739faf428SLouis Dionne : cerr_mem_dump(new char[sizeof(std::cerr)])
3839faf428SLouis Dionne , cin_mem_dump(new char[sizeof(std::cin)])
3939faf428SLouis Dionne , cout_mem_dump(new char[sizeof(std::cout)])
4039faf428SLouis Dionne , clog_mem_dump(new char[sizeof(std::clog)])
4139faf428SLouis Dionne {
4239faf428SLouis Dionne std::memcpy(cerr_mem_dump, (char*)&std::cerr, sizeof(std::cerr));
4339faf428SLouis Dionne std::memcpy(cin_mem_dump, (char*)&std::cin, sizeof(std::cin));
4439faf428SLouis Dionne std::memcpy(cout_mem_dump, (char*)&std::cout, sizeof(std::cout));
4539faf428SLouis Dionne std::memcpy(clog_mem_dump, (char*)&std::clog, sizeof(std::clog));
4639faf428SLouis Dionne }
4739faf428SLouis Dionne
~CheckerChecker4839faf428SLouis Dionne ~Checker() {
4939faf428SLouis Dionne delete[] cerr_mem_dump;
5039faf428SLouis Dionne delete[] cin_mem_dump;
5139faf428SLouis Dionne delete[] cout_mem_dump;
5239faf428SLouis Dionne delete[] clog_mem_dump;
53*f4c1258dSLouis Dionne }
54*f4c1258dSLouis Dionne };
55*f4c1258dSLouis Dionne static Checker check;
5639faf428SLouis Dionne
57*f4c1258dSLouis Dionne #ifndef TEST_HAS_NO_WIDE_CHARACTERS
58*f4c1258dSLouis Dionne struct WideChecker {
59*f4c1258dSLouis Dionne char *wcerr_mem_dump;
60*f4c1258dSLouis Dionne char *wcin_mem_dump;
61*f4c1258dSLouis Dionne char *wcout_mem_dump;
62*f4c1258dSLouis Dionne char *wclog_mem_dump;
63*f4c1258dSLouis Dionne
WideCheckerWideChecker64*f4c1258dSLouis Dionne WideChecker()
65*f4c1258dSLouis Dionne : wcerr_mem_dump(new char[sizeof(std::wcerr)])
66*f4c1258dSLouis Dionne , wcin_mem_dump(new char[sizeof(std::wcin)])
67*f4c1258dSLouis Dionne , wcout_mem_dump(new char[sizeof(std::wcout)])
68*f4c1258dSLouis Dionne , wclog_mem_dump(new char[sizeof(std::wclog)])
69*f4c1258dSLouis Dionne {
70*f4c1258dSLouis Dionne std::memcpy(wcerr_mem_dump, (char*)&std::wcerr, sizeof(std::wcerr));
71*f4c1258dSLouis Dionne std::memcpy(wcin_mem_dump, (char*)&std::wcin, sizeof(std::wcin));
72*f4c1258dSLouis Dionne std::memcpy(wcout_mem_dump, (char*)&std::wcout, sizeof(std::wcout));
73*f4c1258dSLouis Dionne std::memcpy(wclog_mem_dump, (char*)&std::wclog, sizeof(std::wclog));
74*f4c1258dSLouis Dionne }
75*f4c1258dSLouis Dionne
~WideCheckerWideChecker76*f4c1258dSLouis Dionne ~WideChecker() {
7739faf428SLouis Dionne delete[] wcerr_mem_dump;
7839faf428SLouis Dionne delete[] wcin_mem_dump;
7939faf428SLouis Dionne delete[] wcout_mem_dump;
8039faf428SLouis Dionne delete[] wclog_mem_dump;
8139faf428SLouis Dionne }
8239faf428SLouis Dionne };
8339faf428SLouis Dionne
84*f4c1258dSLouis Dionne static WideChecker wide_check;
85*f4c1258dSLouis Dionne #endif
8639faf428SLouis Dionne
main(int,char **)87504bc07dSLouis Dionne int main(int, char**) {
8839faf428SLouis Dionne assert(std::memcmp(check.cerr_mem_dump, (char const*)&std::cerr, sizeof(std::cerr)) == 0);
8939faf428SLouis Dionne assert(std::memcmp(check.cin_mem_dump, (char const*)&std::cin, sizeof(std::cin)) == 0);
9039faf428SLouis Dionne assert(std::memcmp(check.cout_mem_dump, (char const*)&std::cout, sizeof(std::cout)) == 0);
9139faf428SLouis Dionne assert(std::memcmp(check.clog_mem_dump, (char const*)&std::clog, sizeof(std::clog)) == 0);
9239faf428SLouis Dionne
93*f4c1258dSLouis Dionne #ifndef TEST_HAS_NO_WIDE_CHARACTERS
94*f4c1258dSLouis Dionne assert(std::memcmp(wide_check.wcerr_mem_dump, (char const*)&std::wcerr, sizeof(std::wcerr)) == 0);
95*f4c1258dSLouis Dionne assert(std::memcmp(wide_check.wcin_mem_dump, (char const*)&std::wcin, sizeof(std::wcin)) == 0);
96*f4c1258dSLouis Dionne assert(std::memcmp(wide_check.wcout_mem_dump, (char const*)&std::wcout, sizeof(std::wcout)) == 0);
97*f4c1258dSLouis Dionne assert(std::memcmp(wide_check.wclog_mem_dump, (char const*)&std::wclog, sizeof(std::wclog)) == 0);
98*f4c1258dSLouis Dionne #endif
99504bc07dSLouis Dionne return 0;
10039faf428SLouis Dionne }
101