1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: libcpp-has-no-stdin, libcpp-has-no-stdout 10 11 // Make sure that the iostreams are initialized before everything else. 12 // This has been an issue when statically linking libc++ in some contexts. 13 // See https://llvm.org/PR28954 for details. 14 // 15 // This test works by checking that std::{cin,cout,cerr} is the same in a 16 // static object constructor and in the main function. It dumps the memory of 17 // each stream in the static object constructor and compares it with the memory 18 // in the main function. 19 // 20 // The assumption is that if there are no uses of the stream object (such as 21 // construction), then its memory must be the same. In the case where the test 22 // "fails" and we are actually accessing an uninitialized object when we perform 23 // the memcpy, the behavior is technically undefined (so the test could still 24 // pass). 25 26 #include <cassert> 27 #include <cstring> 28 #include <iostream> 29 30 struct Checker { 31 char *cerr_mem_dump; 32 char *cin_mem_dump; 33 char *cout_mem_dump; 34 char *clog_mem_dump; 35 36 char *wcerr_mem_dump; 37 char *wcin_mem_dump; 38 char *wcout_mem_dump; 39 char *wclog_mem_dump; 40 41 Checker() 42 : cerr_mem_dump(new char[sizeof(std::cerr)]) 43 , cin_mem_dump(new char[sizeof(std::cin)]) 44 , cout_mem_dump(new char[sizeof(std::cout)]) 45 , clog_mem_dump(new char[sizeof(std::clog)]) 46 47 , wcerr_mem_dump(new char[sizeof(std::wcerr)]) 48 , wcin_mem_dump(new char[sizeof(std::wcin)]) 49 , wcout_mem_dump(new char[sizeof(std::wcout)]) 50 , wclog_mem_dump(new char[sizeof(std::wclog)]) 51 { 52 std::memcpy(cerr_mem_dump, (char*)&std::cerr, sizeof(std::cerr)); 53 std::memcpy(cin_mem_dump, (char*)&std::cin, sizeof(std::cin)); 54 std::memcpy(cout_mem_dump, (char*)&std::cout, sizeof(std::cout)); 55 std::memcpy(clog_mem_dump, (char*)&std::clog, sizeof(std::clog)); 56 57 std::memcpy(wcerr_mem_dump, (char*)&std::wcerr, sizeof(std::wcerr)); 58 std::memcpy(wcin_mem_dump, (char*)&std::wcin, sizeof(std::wcin)); 59 std::memcpy(wcout_mem_dump, (char*)&std::wcout, sizeof(std::wcout)); 60 std::memcpy(wclog_mem_dump, (char*)&std::wclog, sizeof(std::wclog)); 61 } 62 63 ~Checker() { 64 delete[] cerr_mem_dump; 65 delete[] cin_mem_dump; 66 delete[] cout_mem_dump; 67 delete[] clog_mem_dump; 68 69 delete[] wcerr_mem_dump; 70 delete[] wcin_mem_dump; 71 delete[] wcout_mem_dump; 72 delete[] wclog_mem_dump; 73 } 74 }; 75 76 static Checker check; 77 78 int main(int, char**) { 79 assert(std::memcmp(check.cerr_mem_dump, (char const*)&std::cerr, sizeof(std::cerr)) == 0); 80 assert(std::memcmp(check.cin_mem_dump, (char const*)&std::cin, sizeof(std::cin)) == 0); 81 assert(std::memcmp(check.cout_mem_dump, (char const*)&std::cout, sizeof(std::cout)) == 0); 82 assert(std::memcmp(check.clog_mem_dump, (char const*)&std::clog, sizeof(std::clog)) == 0); 83 84 assert(std::memcmp(check.wcerr_mem_dump, (char const*)&std::wcerr, sizeof(std::wcerr)) == 0); 85 assert(std::memcmp(check.wcin_mem_dump, (char const*)&std::wcin, sizeof(std::wcin)) == 0); 86 assert(std::memcmp(check.wcout_mem_dump, (char const*)&std::wcout, sizeof(std::wcout)) == 0); 87 assert(std::memcmp(check.wclog_mem_dump, (char const*)&std::wclog, sizeof(std::wclog)) == 0); 88 return 0; 89 } 90