Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -58,6 +58,7 @@ option(LIBCXX_ENABLE_STDIN "Build libc++ with support for stdin/std::cin." ON) option(LIBCXX_ENABLE_STDOUT "Build libc++ with support for stdout/std::cout." ON) option(LIBCXX_ENABLE_THREADS "Build libc++ with support for threads." ON) +option(LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS "Build libc++ with support for thread-unsafe C functions" ON) option(LIBCXX_BUILD_32_BITS "Build 32 bit libc++" OFF) option(LIBCXX_ENABLE_MONOTONIC_CLOCK "Build libc++ with support for a monotonic clock. @@ -283,6 +284,11 @@ " when LIBCXX_ENABLE_THREADS is also set to OFF.") endif() +# LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS configuration +if (NOT LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS) + add_definitions(-D_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS) +endif() + # Configure for sanitizers. If LIBCXX_BUILT_STANDALONE then we have to do # the flag translation ourselves. Othewise LLVM's CMakeList.txt will handle it. if (LIBCXX_BUILT_STANDALONE) Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -751,4 +751,10 @@ #define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE #endif +// Thread-unsafe functions such as strtok(), mbtowc() and localtime() +// are not available. +#ifdef __CloudABI__ +#define _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS +#endif + #endif // _LIBCPP_CONFIG Index: include/clocale =================================================================== --- include/clocale +++ include/clocale @@ -45,7 +45,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD using ::lconv; +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS using ::setlocale; +#endif using ::localeconv; _LIBCPP_END_NAMESPACE_STD Index: include/cstdlib =================================================================== --- include/cstdlib +++ include/cstdlib @@ -147,9 +147,11 @@ #undef lldiv using ::lldiv; #endif // _LIBCPP_HAS_NO_LONG_LONG +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS using ::mblen; using ::mbtowc; using ::wctomb; +#endif using ::mbstowcs; using ::wcstombs; #ifdef _LIBCPP_HAS_QUICK_EXIT Index: include/cstring =================================================================== --- include/cstring +++ include/cstring @@ -102,7 +102,9 @@ inline _LIBCPP_INLINE_VISIBILITY char* strstr( char* __s1, const char* __s2) {return ::strstr(__s1, __s2);} #endif +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS using ::strtok; +#endif using ::memset; using ::strerror; using ::strlen; Index: include/ctime =================================================================== --- include/ctime +++ include/ctime @@ -61,10 +61,12 @@ using ::difftime; using ::mktime; using ::time; +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS using ::asctime; using ::ctime; using ::gmtime; using ::localtime; +#endif using ::strftime; _LIBCPP_END_NAMESPACE_STD Index: src/locale.cpp =================================================================== --- src/locale.cpp +++ src/locale.cpp @@ -575,8 +575,10 @@ locale& g = __global(); locale r = g; g = loc; +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS if (g.name() != "*") setlocale(LC_ALL, g.name().c_str()); +#endif return r; } Index: test/CMakeLists.txt =================================================================== --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -46,6 +46,7 @@ pythonize_bool(LIBCXX_ENABLE_STDIN) pythonize_bool(LIBCXX_ENABLE_STDOUT) pythonize_bool(LIBCXX_ENABLE_THREADS) + pythonize_bool(LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS) pythonize_bool(LIBCXX_ENABLE_MONOTONIC_CLOCK) # The tests shouldn't link to any ABI library when it has been linked into # libc++ statically. Index: test/libcxx/test/config.py =================================================================== --- test/libcxx/test/config.py +++ test/libcxx/test/config.py @@ -365,6 +365,8 @@ elif not enable_monotonic_clock: self.lit_config.fatal('enable_monotonic_clock cannot be false when' ' enable_threads is true.') + self.configure_compile_flags_no_thread_unsafe_c_functions() + # Use verbose output for better errors self.cxx.flags += ['-v'] sysroot = self.get_lit_conf('sysroot') @@ -424,6 +426,15 @@ self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_THREADS'] self.config.available_features.add('libcpp-has-no-threads') + def configure_compile_flags_no_thread_unsafe_c_functions(self): + enable_thread_unsafe_c_functions = self.get_lit_bool( + 'enable_thread_unsafe_c_functions', True) + if not enable_thread_unsafe_c_functions: + self.cxx.compile_flags += [ + '-D_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS'] + self.config.available_features.add( + 'libcpp-has-no-thread-unsafe-c-functions') + def configure_compile_flags_no_monotonic_clock(self): self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_MONOTONIC_CLOCK'] self.config.available_features.add('libcpp-has-no-monotonic-clock') Index: test/lit.site.cfg.in =================================================================== --- test/lit.site.cfg.in +++ test/lit.site.cfg.in @@ -12,6 +12,7 @@ config.enable_stdin = "@LIBCXX_ENABLE_STDIN@" config.enable_stdout = "@LIBCXX_ENABLE_STDOUT@" config.enable_threads = "@LIBCXX_ENABLE_THREADS@" +config.enable_thread_unsafe_c_functions = "@LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS@" config.enable_monotonic_clock = "@LIBCXX_ENABLE_MONOTONIC_CLOCK@" config.cxx_abi = "@LIBCXX_CXX_ABI_LIBNAME@" config.use_sanitizer = "@LLVM_USE_SANITIZER@" Index: test/std/depr/depr.c.headers/stdlib_h.pass.cpp =================================================================== --- test/std/depr/depr.c.headers/stdlib_h.pass.cpp +++ test/std/depr/depr.c.headers/stdlib_h.pass.cpp @@ -71,12 +71,14 @@ static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); wchar_t* pw = 0; const wchar_t* pwc = 0; char* pc = 0; +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS + static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); +#endif static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); } Index: test/std/depr/depr.c.headers/string_h.pass.cpp =================================================================== --- test/std/depr/depr.c.headers/string_h.pass.cpp +++ test/std/depr/depr.c.headers/string_h.pass.cpp @@ -41,7 +41,9 @@ static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS static_assert((std::is_same::value), ""); +#endif static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); Index: test/std/language.support/support.runtime/cstdlib.pass.cpp =================================================================== --- test/std/language.support/support.runtime/cstdlib.pass.cpp +++ test/std/language.support/support.runtime/cstdlib.pass.cpp @@ -75,12 +75,14 @@ static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); wchar_t* pw = 0; const wchar_t* pwc = 0; char* pc = 0; +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS + static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); +#endif static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); } Index: test/std/language.support/support.runtime/ctime.pass.cpp =================================================================== --- test/std/language.support/support.runtime/ctime.pass.cpp +++ test/std/language.support/support.runtime/ctime.pass.cpp @@ -30,10 +30,12 @@ static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); +#endif char* c1 = 0; const char* c2 = 0; static_assert((std::is_same::value), ""); Index: test/std/localization/c.locales/clocale.pass.cpp =================================================================== --- test/std/localization/c.locales/clocale.pass.cpp +++ test/std/localization/c.locales/clocale.pass.cpp @@ -12,6 +12,8 @@ #include #include +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS + #ifndef LC_ALL #error LC_ALL not defined #endif @@ -36,6 +38,8 @@ #error LC_TIME not defined #endif +#endif // !_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS + #ifndef NULL #error NULL not defined #endif @@ -43,6 +47,8 @@ int main() { std::lconv lc; +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS static_assert((std::is_same::value), ""); +#endif static_assert((std::is_same::value), ""); } Index: test/std/strings/c.strings/cstring.pass.cpp =================================================================== --- test/std/strings/c.strings/cstring.pass.cpp +++ test/std/strings/c.strings/cstring.pass.cpp @@ -46,7 +46,9 @@ static_assert((std::is_same::value), ""); // static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS static_assert((std::is_same::value), ""); +#endif static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); Index: test/std/utilities/date.time/no.thread.unsafe.c.functions/asctime.fail.cpp =================================================================== --- test/std/utilities/date.time/no.thread.unsafe.c.functions/asctime.fail.cpp +++ test/std/utilities/date.time/no.thread.unsafe.c.functions/asctime.fail.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +int main() { + // asctime is not thread-safe. + std::time_t t = 0; + std::asctime(&t); +} Index: test/std/utilities/date.time/no.thread.unsafe.c.functions/ctime.fail.cpp =================================================================== --- test/std/utilities/date.time/no.thread.unsafe.c.functions/ctime.fail.cpp +++ test/std/utilities/date.time/no.thread.unsafe.c.functions/ctime.fail.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +int main() { + // ctime is not thread-safe. + std::time_t t = 0; + std::ctime(&t); +} Index: test/std/utilities/date.time/no.thread.unsafe.c.functions/gmtime.fail.cpp =================================================================== --- test/std/utilities/date.time/no.thread.unsafe.c.functions/gmtime.fail.cpp +++ test/std/utilities/date.time/no.thread.unsafe.c.functions/gmtime.fail.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +int main() { + // gmtime is not thread-safe. + std::time_t t = 0; + std::gmtime(&t); +} Index: test/std/utilities/date.time/no.thread.unsafe.c.functions/lit.local.cfg =================================================================== --- test/std/utilities/date.time/no.thread.unsafe.c.functions/lit.local.cfg +++ test/std/utilities/date.time/no.thread.unsafe.c.functions/lit.local.cfg @@ -0,0 +1,2 @@ +if 'libcpp-has-no-thread-unsafe-c-functions' not in config.available_features: + config.unsupported = True Index: test/std/utilities/date.time/no.thread.unsafe.c.functions/localtime.fail.cpp =================================================================== --- test/std/utilities/date.time/no.thread.unsafe.c.functions/localtime.fail.cpp +++ test/std/utilities/date.time/no.thread.unsafe.c.functions/localtime.fail.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +int main() { + // localtime is not thread-safe. + std::time_t t = 0; + std::localtime(&t); +} Index: test/std/utilities/date.time/tested_elsewhere.pass.cpp =================================================================== --- test/std/utilities/date.time/tested_elsewhere.pass.cpp +++ test/std/utilities/date.time/tested_elsewhere.pass.cpp @@ -30,9 +30,11 @@ static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); +#ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); +#endif static_assert((std::is_same::value), ""); }