eastig updated this revision to Diff 34973.
eastig added a comment.

Added tests


http://reviews.llvm.org/D12689

Files:
  include/ios
  src/iostream.cpp
  
test/std/input.output/iostream.objects/narrow.stream.objects/cerr_init.pass.cpp
  test/std/input.output/iostream.objects/narrow.stream.objects/cin_init.pass.cpp
  
test/std/input.output/iostream.objects/narrow.stream.objects/clog_init.pass.cpp
  
test/std/input.output/iostream.objects/narrow.stream.objects/cout_init.pass.cpp
  test/std/input.output/iostream.objects/wide.stream.objects/wcerr_init.pass.cpp
  test/std/input.output/iostream.objects/wide.stream.objects/wcin_init.pass.cpp
  test/std/input.output/iostream.objects/wide.stream.objects/wclog_init.pass.cpp
  test/std/input.output/iostream.objects/wide.stream.objects/wcout_init.pass.cpp

Index: test/std/input.output/iostream.objects/wide.stream.objects/wcout_init.pass.cpp
===================================================================
--- test/std/input.output/iostream.objects/wide.stream.objects/wcout_init.pass.cpp
+++ test/std/input.output/iostream.objects/wide.stream.objects/wcout_init.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+// The test checks that 'std::wcout' is the same in a static object constructor
+// and in the main function.
+// It dumps std::wcout memory in the static object constructor and compares it
+// with the memory in the main function.
+// Assumption: if there are no uses of std::wcout it must be the same.
+
+struct A {
+  char *wcout_mem_dump;
+
+  A(): wcout_mem_dump(new char[sizeof(std::wcout)]) {
+    std::memcpy(wcout_mem_dump, (char *)&std::wcout, sizeof(std::wcout));
+  }
+  ~A() {
+    delete [] wcout_mem_dump;
+  }
+};
+
+static A a;
+
+int main()
+{
+  assert(memcmp(a.wcout_mem_dump, (char *)&std::wcout, sizeof(std::wcout)) == 0);
+}
+
Index: test/std/input.output/iostream.objects/wide.stream.objects/wclog_init.pass.cpp
===================================================================
--- test/std/input.output/iostream.objects/wide.stream.objects/wclog_init.pass.cpp
+++ test/std/input.output/iostream.objects/wide.stream.objects/wclog_init.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+// The test checks that 'std::wclog' is the same in a static object constructor
+// and in the main function.
+// It dumps std::wclog memory in the static object constructor and compares it
+// with the memory in the main function.
+// Assumption: if there are no uses of std::wclog it must be the same.
+
+struct A {
+  char *wclog_mem_dump;
+
+  A(): wclog_mem_dump(new char[sizeof(std::wclog)]) {
+    std::memcpy(wclog_mem_dump, (char *)&std::wclog, sizeof(std::wclog));
+  }
+  ~A() {
+    delete [] wclog_mem_dump;
+  }
+};
+
+static A a;
+
+int main()
+{
+  assert(memcmp(a.wclog_mem_dump, (char *)&std::wclog, sizeof(std::wclog)) == 0);
+}
+
Index: test/std/input.output/iostream.objects/wide.stream.objects/wcin_init.pass.cpp
===================================================================
--- test/std/input.output/iostream.objects/wide.stream.objects/wcin_init.pass.cpp
+++ test/std/input.output/iostream.objects/wide.stream.objects/wcin_init.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+// The test checks that 'std::wcin' is the same in a static object constructor
+// and in the main function.
+// It dumps std::wcin memory in the static object constructor and compares it
+// with the memory in the main function.
+// Assumption: if there are no uses of std::wcin it must be the same.
+
+struct A {
+  char *wcin_mem_dump;
+
+  A(): wcin_mem_dump(new char[sizeof(std::wcin)]) {
+    std::memcpy(wcin_mem_dump, (char *)&std::wcin, sizeof(std::wcin));
+  }
+  ~A() {
+    delete [] wcin_mem_dump;
+  }
+};
+
+static A a;
+
+int main()
+{
+  assert(memcmp(a.wcin_mem_dump, (char *)&std::wcin, sizeof(std::wcin)) == 0);
+}
+
Index: test/std/input.output/iostream.objects/wide.stream.objects/wcerr_init.pass.cpp
===================================================================
--- test/std/input.output/iostream.objects/wide.stream.objects/wcerr_init.pass.cpp
+++ test/std/input.output/iostream.objects/wide.stream.objects/wcerr_init.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+// The test checks that 'std::wcerr' is the same in a static object constructor
+// and in the main function.
+// It dumps std::wcerr memory in the static object constructor and compares it
+// with the memory in the main function.
+// Assumption: if there are no uses of std::wcerr it must be the same.
+
+struct A {
+  char *wcerr_mem_dump;
+
+  A(): wcerr_mem_dump(new char[sizeof(std::wcerr)]) {
+    std::memcpy(wcerr_mem_dump, (char *)&std::wcerr, sizeof(std::wcerr));
+  }
+  ~A() {
+    delete [] wcerr_mem_dump;
+  }
+};
+
+static A a;
+
+int main()
+{
+  assert(memcmp(a.wcerr_mem_dump, (const char *)&std::wcerr, sizeof(std::wcerr)) == 0);
+}
+
Index: test/std/input.output/iostream.objects/narrow.stream.objects/cout_init.pass.cpp
===================================================================
--- test/std/input.output/iostream.objects/narrow.stream.objects/cout_init.pass.cpp
+++ test/std/input.output/iostream.objects/narrow.stream.objects/cout_init.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+// The test checks that 'std::cout' is the same in a static object constructor
+// and in the main function.
+// It dumps std::cout memory in the static object constructor and compares it
+// with the memory in the main function.
+// Assumption: if there are no uses of std::cout it must be the same.
+
+struct A {
+  char *cout_mem_dump;
+
+  A(): cout_mem_dump(new char[sizeof(std::cout)]) {
+    std::memcpy(cout_mem_dump, (char *)&std::cout, sizeof(std::cout));
+  }
+  ~A() {
+    delete [] cout_mem_dump;
+  }
+};
+
+static A a;
+
+int main()
+{
+  assert(memcmp(a.cout_mem_dump, (char *)&std::cout, sizeof(std::cout)) == 0);
+}
+
Index: test/std/input.output/iostream.objects/narrow.stream.objects/clog_init.pass.cpp
===================================================================
--- test/std/input.output/iostream.objects/narrow.stream.objects/clog_init.pass.cpp
+++ test/std/input.output/iostream.objects/narrow.stream.objects/clog_init.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+// The test checks that 'std::clog' is the same in a static object constructor
+// and in the main function.
+// It dumps std::clog memory in the static object constructor and compares it
+// with the memory in the main function.
+// Assumption: if there are no uses of std::clog it must be the same.
+
+struct A {
+  char *clog_mem_dump;
+
+  A(): clog_mem_dump(new char[sizeof(std::clog)]) {
+    std::memcpy(clog_mem_dump, (char *)&std::clog, sizeof(std::clog));
+  }
+  ~A() {
+    delete [] clog_mem_dump;
+  }
+};
+
+static A a;
+
+int main()
+{
+  assert(memcmp(a.clog_mem_dump, (char *)&std::clog, sizeof(std::clog)) == 0);
+}
+
Index: test/std/input.output/iostream.objects/narrow.stream.objects/cin_init.pass.cpp
===================================================================
--- test/std/input.output/iostream.objects/narrow.stream.objects/cin_init.pass.cpp
+++ test/std/input.output/iostream.objects/narrow.stream.objects/cin_init.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+// The test checks that 'std::cin' is the same in a static object constructor
+// and in the main function.
+// It dumps std::cin memory in the static object constructor and compares it
+// with the memory in the main function.
+// Assumption: if there are no uses of std::cin it must be the same.
+
+struct A {
+  char *cin_mem_dump;
+
+  A(): cin_mem_dump(new char[sizeof(std::cin)]) {
+    std::memcpy(cin_mem_dump, (char *)&std::cin, sizeof(std::cin));
+  }
+  ~A() {
+    delete [] cin_mem_dump;
+  }
+};
+
+static A a;
+
+int main()
+{
+  assert(memcmp(a.cin_mem_dump, (char *)&std::cin, sizeof(std::cin)) == 0);
+}
+
Index: test/std/input.output/iostream.objects/narrow.stream.objects/cerr_init.pass.cpp
===================================================================
--- test/std/input.output/iostream.objects/narrow.stream.objects/cerr_init.pass.cpp
+++ test/std/input.output/iostream.objects/narrow.stream.objects/cerr_init.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+// The test checks that 'std::cerr' is the same in a static object constructor
+// and in the main function.
+// It dumps std::cerr memory in the static object constructor and compares it
+// with the memory in the main function.
+// Assumption: if there are no uses of std::cerr it must be the same.
+
+struct A {
+  char *cerr_mem_dump;
+
+  A(): cerr_mem_dump(new char[sizeof(std::cerr)]) {
+    std::memcpy(cerr_mem_dump, (char *)&std::cerr, sizeof(std::cerr));
+  }
+  ~A() {
+    delete [] cerr_mem_dump;
+  }
+};
+
+static A a;
+
+int main()
+{
+  assert(memcmp(a.cerr_mem_dump, (const char *)&std::cerr, sizeof(std::cerr)) == 0);
+}
+
Index: src/iostream.cpp
===================================================================
--- src/iostream.cpp
+++ src/iostream.cpp
@@ -10,6 +10,8 @@
 #include "__std_stream"
 #include "string"
 #include "new"
+#include "cassert"
+#include "memory"
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
@@ -41,9 +43,7 @@
 _ALIGNAS_TYPE (ostream)  _LIBCPP_FUNC_VIS char clog[sizeof(ostream)];
 _ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wclog[sizeof(wostream)];
 
-ios_base::Init __start_std_streams;
-
-ios_base::Init::Init()
+static void init_std_streams()
 {
 #ifndef _LIBCPP_HAS_NO_STDIN
     istream* cin_ptr  = ::new(cin)  istream(::new(__cin)  __stdinbuf <char>(stdin, &mb_cin));
@@ -70,7 +70,7 @@
 #endif
 }
 
-ios_base::Init::~Init()
+static void fini_std_streams()
 {
 #ifndef _LIBCPP_HAS_NO_STDOUT
     ostream* cout_ptr = reinterpret_cast<ostream*>(cout);
@@ -85,4 +85,51 @@
     wclog_ptr->flush();
 }
 
+/// __Init is a utility class that counts the number of ios_base::Init
+/// objects. It automatically deinitializes the std streams when the
+/// last ios_base::Init object is destroyed.
+class __Init: public __shared_count {
+private:
+  void __on_zero_shared() _NOEXCEPT {
+    fini_std_streams();
+  }
+public:
+  __Init(long count = 0): __shared_count(count) {
+    init_std_streams();
+  }
+};
+
+_ALIGNAS_TYPE (__Init) _LIBCPP_FUNC_VIS static char __init_storage[sizeof(__Init)];
+
+__shared_count *ios_base::Init::UseCount = nullptr;
+
+ios_base::Init::Init()
+{
+  //local static object is initialized only once
+  struct __S {
+    __S() {
+      Init::UseCount = ::new(__init_storage) __Init(-1);
+    }
+  };
+  static __S __s;
+  UseCount->__add_shared();
+}
+
+ios_base::Init::~Init()
+{
+  assert(UseCount);
+  UseCount->__release_shared();
+}
+
+#ifdef __APPLE__
+// Apple linker has a guarantee for an initialization order:
+// if A links against B, B's initializer will be run before A's.
+// I.e. if you link to libc++.dylib, then cout et al. are guaranteed
+// to be constructed before your initializers run. This way, initialization
+// of __start_std_streams might remain here in module initializer
+// Without Apple linker, the following definition must be in header <ios>,
+// so its initialization will be explicitly executed before any stream usage.
+ios_base::Init __start_std_streams;
+#endif
+
 _LIBCPP_END_NAMESPACE_STD
Index: include/ios
===================================================================
--- include/ios
+++ include/ios
@@ -423,13 +423,30 @@
     virtual ~failure() throw();
 };
 
+class __shared_count;
+
 class _LIBCPP_TYPE_VIS ios_base::Init
 {
+private:
+    static __shared_count *UseCount;
 public:
     Init();
     ~Init();
 };
 
+#ifndef __APPLE__
+// Apple linker has a guarantee for an initialization order:
+// if A links against B, B's initializer will be run before A's.
+// I.e. if you link to libc++.dylib, then cout et al. are guaranteed
+// to be constructed before your initializers run. This way, definition
+// of __start_std_streams might remain in src/iostream.cpp, and linker arranges
+// its initialization before any stream usage.
+// Without Apple linker, that definition must be here,
+// so its initialization will be explicitly executed before any stream usage.
+// For construction of cout, cin, cerr etc.
+static ios_base::Init __start_std_streams;
+#endif
+
 // fmtflags
 
 inline _LIBCPP_INLINE_VISIBILITY
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to