Skip to content

[libc++] Implements Runtime format strings II. #72543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 24, 2023

Conversation

mordante
Copy link
Member

Implements

  • P2918R2 Runtime format strings II

@mordante mordante requested a review from a team as a code owner November 16, 2023 17:58
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 16, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 16, 2023

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

Changes

Implements

  • P2918R2 Runtime format strings II

Full diff: https://github.com/llvm/llvm-project/pull/72543.diff

10 Files Affected:

  • (modified) libcxx/docs/ReleaseNotes/18.rst (+1)
  • (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1)
  • (modified) libcxx/docs/Status/FormatIssues.csv (+1-1)
  • (modified) libcxx/include/__format/format_functions.h (+25)
  • (modified) libcxx/include/format (+19)
  • (modified) libcxx/modules/std/format.inc (+3)
  • (added) libcxx/test/std/utilities/format/format.functions/format.locale.runtime_format.pass.cpp (+72)
  • (added) libcxx/test/std/utilities/format/format.functions/format.runtime_format.pass.cpp (+70)
  • (added) libcxx/test/std/utilities/format/format.syn/runtime_format_string.pass.cpp (+61)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (+1-1)
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index d5df7fde5be91af..7cc8481317bf62f 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -48,6 +48,7 @@ Implemented Papers
 - P2538R1 - ADL-proof ``std::projected``
 - P2614R2 - Deprecate ``numeric_limits::has_denorm``
 - P0053R7 - C++ Synchronized Buffered Ostream (in the experimental library)
+- P2918R2 - Runtime format strings II
 
 
 Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index eb5398f66d0e0c1..e7ddc906b622bd9 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -31,7 +31,7 @@
 "`P2407R5 <https://wg21.link/P2407R5>`__","LWG","Freestanding Library: Partial Classes","Kona November 2023","","",""
 "`P2546R5 <https://wg21.link/P2546R5>`__","LWG","Debugging Support","Kona November 2023","","",""
 "`P2905R2 <https://wg21.link/P2905R2>`__","LWG","Runtime format strings","Kona November 2023","","","|format| |DR|"
-"`P2918R2 <https://wg21.link/P2918R2>`__","LWG","Runtime format strings II","Kona November 2023","","","|format|"
+"`P2918R2 <https://wg21.link/P2918R2>`__","LWG","Runtime format strings II","Kona November 2023","|Complete|","18.0","|format|"
 "`P2909R4 <https://wg21.link/P2909R4>`__","LWG","Fix formatting of code units as integers (Dude, where’s my ``char``?)","Kona November 2023","","","|format| |DR|"
 "`P0952R2 <https://wg21.link/P0952R2>`__","LWG","A new specification for ``std::generate_canonical``","Kona November 2023","","",""
 "`P2447R6 <https://wg21.link/P2447R6>`__","LWG","``std::span`` over an initializer list","Kona November 2023","","",""
diff --git a/libcxx/docs/Status/FormatIssues.csv b/libcxx/docs/Status/FormatIssues.csv
index 5c6463fa97ed2ba..14ea7c4360a373f 100644
--- a/libcxx/docs/Status/FormatIssues.csv
+++ b/libcxx/docs/Status/FormatIssues.csv
@@ -18,7 +18,7 @@ Number,Name,Standard,Assignee,Status,First released version
 "`P2757R3 <https://wg21.link/P2757R3>`__","Type-checking format args","C++26","","",
 "`P2637R3 <https://wg21.link/P2637R3>`__","Member ``visit``","C++26","","",
 "`P2905R2 <https://wg21.link/P2905R2>`__","Runtime format strings","C++26 DR","Mark de Wever","|In Progress|"
-"`P2918R2 <https://wg21.link/P2918R2>`__","Runtime format strings II","C++26","Mark de Wever","|In Progress|"
+"`P2918R2 <https://wg21.link/P2918R2>`__","Runtime format strings II","C++26","Mark de Wever","|Complete|",18.0
 "`P2909R4 <https://wg21.link/P2909R4>`__","Fix formatting of code units as integers (Dude, where’s my ``char``?)","C++26 DR","Mark de Wever","|In Progress|"
 `P1361 <https://wg21.link/P1361>`_,"Integration of chrono with text formatting","C++20",Mark de Wever,|In Progress|,
 `P2372 <https://wg21.link/P2372>`__,"Fixing locale handling in chrono formatters","C++20",Mark de Wever,|In Progress|,
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index bb62c1ce10c15cb..a0ece7b2bc5db70 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -338,6 +338,28 @@ __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
 
 } // namespace __format
 
+#  if _LIBCPP_STD_VER >= 26
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __runtime_format_string {
+private:
+  basic_string_view<_CharT> __str_;
+
+  template <class _Cp, class... _Args>
+  friend struct _LIBCPP_TEMPLATE_VIS basic_format_string;
+
+public:
+  _LIBCPP_HIDE_FROM_ABI __runtime_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {}
+
+  __runtime_format_string(const __runtime_format_string&)            = delete;
+  __runtime_format_string& operator=(const __runtime_format_string&) = delete;
+};
+
+_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<char> runtime_format(string_view __fmt) noexcept { return __fmt; }
+_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<wchar_t> runtime_format(wstring_view __fmt) noexcept {
+  return __fmt;
+}
+#  endif //_LIBCPP_STD_VER >= 26
+
 template <class _CharT, class... _Args>
 struct _LIBCPP_TEMPLATE_VIS basic_format_string {
   template <class _Tp>
@@ -350,6 +372,9 @@ struct _LIBCPP_TEMPLATE_VIS basic_format_string {
   _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT> get() const noexcept {
     return __str_;
   }
+#  if _LIBCPP_STD_VER >= 26
+  _LIBCPP_HIDE_FROM_ABI basic_format_string(__runtime_format_string<_CharT> __s) noexcept : __str_(__s.__str_) {}
+#  endif //_LIBCPP_STD_VER >= 26
 
 private:
   basic_string_view<_CharT> __str_;
diff --git a/libcxx/include/format b/libcxx/include/format
index c48bcf6e8403930..8a4837a868a9845 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -31,6 +31,7 @@ namespace std {
 
     public:
       template<class T> consteval basic_format_string(const T& s);
+	  basic_format_string(runtime-format-string<charT> s) noexcept : str(s.str) {}   // since C++26
 
       constexpr basic_string_view<charT> get() const noexcept { return str; }
     };
@@ -41,6 +42,24 @@ namespace std {
     using wformat_string =                                      // since C++23, exposition only before C++23
       basic_format_string<wchar_t, type_identity_t<Args>...>;
 
+  template<class charT> struct runtime-format-string {          // since C++26, exposition-only
+  private:
+    basic_string_view<charT> str;                               // exposition-only
+
+  public:
+    runtime-format-string(basic_string_view<charT> s) noexcept : str(s) {}
+
+    runtime-format-string(const runtime-format-string&) = delete;
+    runtime-format-string& operator=(const runtime-format-string&) = delete;
+  };
+
+  runtime-format-string<char> runtime_format(string_view fmt) noexcept {
+    return fmt;
+  }
+  runtime-format-string<wchar_t> runtime_format(wstring_view fmt) noexcept {
+    return fmt;
+  }
+
   // [format.functions], formatting functions
   template<class... Args>
     string format(format-string<Args...> fmt, Args&&... args);
diff --git a/libcxx/modules/std/format.inc b/libcxx/modules/std/format.inc
index c1bc91f8317dd0a..743a43811005a4b 100644
--- a/libcxx/modules/std/format.inc
+++ b/libcxx/modules/std/format.inc
@@ -28,6 +28,9 @@ export namespace std {
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
   using std::wformat_string;
 #endif
+#if _LIBCPP_STD_VER >= 26
+  using std::runtime_format;
+#endif //_LIBCPP_STD_VER >= 26
 
   // [format.functions], formatting functions
   using std::format;
diff --git a/libcxx/test/std/utilities/format/format.functions/format.locale.runtime_format.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.locale.runtime_format.pass.cpp
new file mode 100644
index 000000000000000..e2e10a3dd97d29e
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format.locale.runtime_format.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// UNSUPPORTED: no-localization
+// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+
+// XFAIL: availability-fp_to_chars-missing
+
+// <format>
+
+// template<class charT, class... Args>
+//   struct basic_format_string {
+//   ...
+//   basic_format_string(runtime-format-string<charT> s) noexcept : str(s.str) {}
+//   ...
+// }
+
+// template<class... Args>
+//   string format(const locale& loc, format_string<Args...> fmt, const Args&... args);
+// template<class... Args>
+//   wstring format(const locale& loc, wformat_string<Args...> fmt, const Args&... args);
+
+#include <format>
+#include <cassert>
+#include <locale>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+#include "string_literal.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+
+auto test = []<class CharT, class... Args>(
+                std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) constexpr {
+  std::basic_string<CharT> out = std::format(std::locale(), std::runtime_format(fmt), std::forward<Args>(args)...);
+  TEST_REQUIRE(out == expected,
+               TEST_WRITE_CONCATENATED(
+                   "\nFormat string   ", fmt, "\nExpected output ", expected, "\nActual output   ", out, '\n'));
+};
+
+auto test_exception =
+    []<class CharT, class... Args>(
+        [[maybe_unused]] std::string_view what,
+        [[maybe_unused]] std::basic_string_view<CharT> fmt,
+        [[maybe_unused]] Args&&... args) {
+      TEST_VALIDATE_EXCEPTION(
+          std::format_error,
+          [&]([[maybe_unused]] const std::format_error& e) {
+            TEST_LIBCPP_REQUIRE(
+                e.what() == what,
+                TEST_WRITE_CONCATENATED(
+                    "\nFormat string   ", fmt, "\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
+          },
+          TEST_IGNORE_NODISCARD std::format(std::locale(), std::runtime_format(fmt), std::forward<Args>(args)...));
+    };
+
+int main(int, char**) {
+  format_tests<char, execution_modus::partial>(test, test_exception);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  format_tests_char_to_wchar_t(test);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/format/format.functions/format.runtime_format.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.runtime_format.pass.cpp
new file mode 100644
index 000000000000000..8a8e8527e0cba49
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format.runtime_format.pass.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+
+// XFAIL: availability-fp_to_chars-missing
+
+// <format>
+
+// template<class charT, class... Args>
+//   struct basic_format_string {
+//   ...
+//   basic_format_string(runtime-format-string<charT> s) noexcept : str(s.str) {}
+//   ...
+// }
+
+// template<class... Args>
+//   string format(format_string<Args...> fmt, const Args&... args);
+// template<class... Args>
+//   wstring format(wformat_string<Args...> fmt, const Args&... args);
+
+#include <format>
+#include <cassert>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+#include "string_literal.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+
+auto test = []<class CharT, class... Args>(
+                std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) constexpr {
+  std::basic_string<CharT> out = std::format(std::runtime_format(fmt), std::forward<Args>(args)...);
+  TEST_REQUIRE(out == expected,
+               TEST_WRITE_CONCATENATED(
+                   "\nFormat string   ", fmt, "\nExpected output ", expected, "\nActual output   ", out, '\n'));
+};
+
+auto test_exception =
+    []<class CharT, class... Args>(
+        [[maybe_unused]] std::string_view what,
+        [[maybe_unused]] std::basic_string_view<CharT> fmt,
+        [[maybe_unused]] Args&&... args) {
+      TEST_VALIDATE_EXCEPTION(
+          std::format_error,
+          [&]([[maybe_unused]] const std::format_error& e) {
+            TEST_LIBCPP_REQUIRE(
+                e.what() == what,
+                TEST_WRITE_CONCATENATED(
+                    "\nFormat string   ", fmt, "\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
+          },
+          TEST_IGNORE_NODISCARD std::format(std::runtime_format(fmt), std::forward<Args>(args)...));
+    };
+
+int main(int, char**) {
+  format_tests<char, execution_modus::partial>(test, test_exception);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  format_tests_char_to_wchar_t(test);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/format/format.syn/runtime_format_string.pass.cpp b/libcxx/test/std/utilities/format/format.syn/runtime_format_string.pass.cpp
new file mode 100644
index 000000000000000..660fe79835ac090
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.syn/runtime_format_string.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <format>
+
+// template<class charT> struct runtime-format-string {  // exposition-only
+// private:
+//   basic_string_view<charT> str;  // exposition-only
+//
+// public:
+//   runtime-format-string(basic_string_view<charT> s) noexcept : str(s) {}
+//
+//   runtime-format-string(const runtime-format-string&) = delete;
+//   runtime-format-string& operator=(const runtime-format-string&) = delete;
+// };
+// runtime-format-string<char> runtime_format(string_view fmt) noexcept;
+// runtime-format-string<wchar_t> runtime_format(wstring_view fmt) noexcept;
+
+#include <format>
+
+#include <cassert>
+#include <concepts>
+#include <string_view>
+#include <type_traits>
+
+#include "test_macros.h"
+
+template <class T, class CharT>
+static void test_properties() {
+  static_assert(std::is_nothrow_convertible_v<std::basic_string_view<CharT>, T>);
+  static_assert(std::is_nothrow_constructible_v<T, std::basic_string_view<CharT>>);
+
+  static_assert(!std::copy_constructible<T>);
+  static_assert(!std::is_copy_assignable_v<T>);
+
+  static_assert(!std::move_constructible<T>);
+  static_assert(!std::is_move_assignable_v<T>);
+}
+
+int main(int, char**) {
+  static_assert(noexcept(std::runtime_format(std::string_view{})));
+  auto format_string = std::runtime_format(std::string_view{});
+  LIBCPP_ASSERT((std::same_as<decltype(format_string), std::__runtime_format_string<char>>));
+  test_properties<decltype(format_string), char>();
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  static_assert(noexcept(std::runtime_format(std::wstring_view{})));
+  auto wformat_string = std::runtime_format(std::wstring_view{});
+  LIBCPP_ASSERT((std::same_as<decltype(wformat_string), std::__runtime_format_string<wchar_t>>));
+  test_properties<decltype(wformat_string), wchar_t>();
+#endif // TEST_HAS_NO_WIDE_CHARACTERS
+
+  return 0;
+}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 0c07ac432d7c7e4..0d4f1708e85a333 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -467,7 +467,7 @@ def add_version_header(tc):
                 # "c++20": 202110 Not implemented P2372R3 Fixing locale handling in chrono formatters
                 "c++20": 202106,
                 # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
-                # "c++26": 202311, Not implemented P2918R2 Runtime format strings II
+                # "c++26": 202311, P2918R2 Runtime format strings II (implemented)
             },
             # Note these three papers are adopted at the June 2023 meeting and have sequential numbering
             # 202304 P2510R3 Formatting pointers (Implemented)

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically LGTM with comments.

@mordante mordante force-pushed the GH-runtime_format_strings_II branch from 1f397fd to cf2c112 Compare November 22, 2023 17:01
@mordante mordante force-pushed the GH-runtime_format_strings_II branch from cf2c112 to f73eeac Compare November 23, 2023 19:45
Implements
- P2918R2 Runtime format strings II
@mordante mordante force-pushed the GH-runtime_format_strings_II branch from f73eeac to bd45154 Compare November 24, 2023 16:30
@mordante mordante merged commit 92d9f23 into llvm:main Nov 24, 2023
@mordante mordante deleted the GH-runtime_format_strings_II branch November 24, 2023 16:30
@vitalybuka
Copy link
Collaborator

vitalybuka commented Nov 26, 2023

@mordante
Copy link
Member Author

These bots are still broken:

https://lab.llvm.org/buildbot/#/builders/236 https://lab.llvm.org/buildbot/#/builders/237 https://lab.llvm.org/buildbot/#/builders/239

Thanks for the heads up, it seems I overlooked the buildbot e-mail.
This is quite curious since there are several similar tests in libc++ that do not trigger this issue.
Is it possible to get a stacktrace where the exception is thrown?

@vitalybuka
Copy link
Collaborator

This is quite curious since there are several similar tests in libc++ that do not trigger this issue.

Is this one of these disabled tests?
https://github.com/llvm/llvm-zorg/blob/8842c8c262cce13e48cd8e382fc42693f142512d/zorg/buildbot/builders/sanitizers/buildbot_functions.sh#L357C8-L372C78

@vitalybuka
Copy link
Collaborator

vitalybuka commented Nov 28, 2023

All these fail msan bot

Failed Tests (6):
  llvm-libc++-shared.cfg.in :: std/utilities/format/format.functions/format.locale.runtime_format.pass.cpp
  llvm-libc++-shared.cfg.in :: std/utilities/format/format.functions/format.runtime_format.pass.cpp
  llvm-libc++-shared.cfg.in :: std/utilities/format/format.functions/vformat.locale.pass.cpp
  llvm-libc++-shared.cfg.in :: std/utilities/format/format.functions/vformat.pass.cpp
  llvm-libc++-shared.cfg.in :: std/utilities/format/format.functions/vformat_to.locale.pass.cpp
  llvm-libc++-shared.cfg.in :: std/utilities/format/format.functions/vformat_to.pass.cpp

@vitalybuka
Copy link
Collaborator

put/vformat.locale.pass.cpp.dir/t.tmp.exe
libc++abi: terminating due to uncaught exception of type std::__1::format_error: The argument index value is too large for the number of arguments supplied
MemorySanitizer:DEADLYSIGNAL
==127537==ERROR: MemorySanitizer: ABRT on unknown address 0x03e70001f231 (pc 0xffff9f4a03f0 bp 0xffffc4ff8a90 sp 0xffffc4ff8a90 T127537)
    #0 0xffff9f4a03f0 in __pthread_kill_implementation nptl/pthread_kill.c:44:76
    #1 0xffff9f45a1e8 in raise signal/../sysdeps/posix/raise.c:26:13
    #2 0xffff9f446af8 in abort stdlib/abort.c:79:7
    #3 0xffff9f76dd54 in abort_message abort_message.cpp
    #4 0xffff9f71f588 in demangling_terminate_handler() cxa_default_handlers.cpp
    #5 0xffff9f76c558 in std::__terminate(void (*)()) cxa_handlers.cpp
    #6 0xffff9f7737e0 in __cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception*) cxa_exception.cpp
    #7 0xffff9f77370c in __cxa_throw (/b/my/build/libcxx_build_msan/lib/libc++abi.so.1+0x8370c)
    #8 0xaaaacaaae1d8 in std::__1::__throw_format_error[abi:ne180000](char const*) /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_error.h:43:3
    #9 0xaaaacaab1148 in auto char const* std::__1::__format::__handle_replacement_field[abi:ne180000]<char const*, std::__1::basic_format_parse_context<char>, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(char const*, char const*, std::__1::basic_format_parse_context<char>&, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>&)::'lambda'(char const*)::operator()<std::__1::monostate>(char const*) const /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_functions.h:277:13
    #10 0xaaaacaab10d8 in decltype(std::declval<char const*>()(std::declval<std::__1::monostate&>())) std::__1::__invoke[abi:ne180000]<char const* std::__1::__format::__handle_replacement_field[abi:ne180000]<char const*, std::__1::basic_format_parse_context<char>, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(char const*, char const*, std::__1::basic_format_parse_context<char>&, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>&)::'lambda'(char const*), std::__1::monostate&>(char const*&&, std::__1::monostate&) /b/my/build/libcxx_build_msan/include/c++/v1/__type_traits/invoke.h:344:25

MemorySanitizer can not provide additional info.
SUMMARY: MemorySanitizer: ABRT nptl/pthread_kill.c:44:76 in __pthread_kill_implementation
==127537==ABORTING

vitalybuka added a commit to llvm/llvm-zorg that referenced this pull request Nov 28, 2023
@vitalybuka
Copy link
Collaborator

Not sure what that stack means, so I just disabled these tests on our bots as a few similar were already disabled.

@mordante
Copy link
Member Author

Not sure what that stack means, so I just disabled these tests on our bots as a few similar were already disabled.

I see you disabled them in zorg and not in the test itself, the same for the previous errors. That means we don't see them exclusion in the libc++ tests themselves; hence my conclusion that the other tests worked.

I wanted to see which format-string causes the issue, there are hundreds of them tested. Unfortunately it seems the stack is not complete so it's hard to tell.
Is there a way to get a more detailed stack up to main()?

@vitalybuka
Copy link
Collaborator

On e1f911e

MSAN_OPTIONS=fast_unwind_on_fatal=1:handle_abort=1:external_symbolizer_path=llvm_build0/bin/llvm-symbolizer  /b/my/build/libcxx_build_msan/test/std/utilities/format/format.functions/Output/vformat.locale.pass.cpp.dir/t.tmp.exe
libc++abi: terminating due to uncaught exception of type std::__1::format_error: The argument index value is too large for the number of arguments supplied
MemorySanitizer:DEADLYSIGNAL
==1128068==ERROR: MemorySanitizer: ABRT on unknown address 0x03e700113684 (pc 0xffffbedf03f0 bp 0xffffce972130 sp 0xffffce972130 T1128068)
    #0 0xffffbedf03f0 in __pthread_kill_implementation nptl/pthread_kill.c:44:76
    #1 0xffffbedaa1e8 in raise signal/../sysdeps/posix/raise.c:26:13
    #2 0xffffbed96af8 in abort stdlib/abort.c:79:7
    #3 0xffffbf0bdd54 in abort_message abort_message.cpp
    #4 0xffffbf06f588 in demangling_terminate_handler() cxa_default_handlers.cpp
    #5 0xffffbf0bc558 in std::__terminate(void (*)()) cxa_handlers.cpp
    #6 0xffffbf0c37e0 in __cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception*) cxa_exception.cpp
    #7 0xffffbf0c370c in __cxa_throw (/b/my/build/libcxx_build_msan/lib/libc++abi.so.1+0x8370c)
    #8 0xaaaacf59e1d8 in std::__1::__throw_format_error[abi:ne180000](char const*) /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_error.h:43:3
    #9 0xaaaacf5a1148 in auto char const* std::__1::__format::__handle_replacement_field[abi:ne180000]<char const*, std::__1::basic_format_parse_context<char>, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(char const*, char const*, std::__1::basic_format_parse_context<char>&, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>&)::'lambda'(char const*)::operator()<std::__1::monostate>(char const*) const /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_functions.h:277:13
    #10 0xaaaacf5a10d8 in decltype(std::declval<char const*>()(std::declval<std::__1::monostate&>())) std::__1::__invoke[abi:ne180000]<char const* std::__1::__format::__handle_replacement_field[abi:ne180000]<char const*, std::__1::basic_format_parse_context<char>, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(char const*, char const*, std::__1::basic_format_parse_context<char>&, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>&)::'lambda'(char const*), std::__1::monostate&>(char const*&&, std::__1::monostate&) /b/my/build/libcxx_build_msan/include/c++/v1/__type_traits/invoke.h:344:25
    #11 0xaaaacf5a0528 in std::__1::invoke_result<char const*, std::__1::monostate&>::type std::__1::invoke[abi:ne180000]<char const* std::__1::__format::__handle_replacement_field[abi:ne180000]<char const*, std::__1::basic_format_parse_context<char>, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(char const*, char const*, std::__1::basic_format_parse_context<char>&, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>&)::'lambda'(char const*), std::__1::monostate&>(char const*&&, std::__1::monostate&) /b/my/build/libcxx_build_msan/include/c++/v1/__functional/invoke.h:30:12
    #12 0xaaaacf59f1d0 in decltype(auto) std::__1::__visit_format_arg[abi:ne180000]<char const* std::__1::__format::__handle_replacement_field[abi:ne180000]<char const*, std::__1::basic_format_parse_context<char>, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(char const*, char const*, std::__1::basic_format_parse_context<char>&, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>&)::'lambda'(char const*), std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(char const*&&, std::__1::basic_format_arg<std::__1::basic_format_parse_context<char>>) /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_arg.h:103:12
    #13 0xaaaacf59e6a0 in char const* std::__1::__format::__handle_replacement_field[abi:ne180000]<char const*, std::__1::basic_format_parse_context<char>, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(char const*, char const*, std::__1::basic_format_parse_context<char>&, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>&) /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_functions.h:274:5
    #14 0xaaaacf597f78 in std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>::iterator std::__1::__format::__vformat_to[abi:ne180000]<std::__1::basic_format_parse_context<char>, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>(std::__1::basic_format_parse_context<char>&&, std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>&&) /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_functions.h:315:13
    #15 0xaaaacf5978d4 in T std::__1::__vformat_to[abi:ne180000]<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>, char, std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>>(T, std::__1::locale, std::__1::basic_string_view<T0, std::__1::char_traits<T0>>, std::__1::basic_format_args<std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, T0>>) /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_functions.h:552:5
    #16 0xaaaacee00624 in std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> std::__1::vformat_to[abi:ne180000]<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>>(std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>, std::__1::locale, std::__1::basic_string_view<char, std::__1::char_traits<char>>, std::__1::basic_format_args<std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>) /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_functions.h:562:10
    #17 0xaaaacee00624 in std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> std::__1::vformat[abi:ne180000]<void>(std::__1::locale, std::__1::basic_string_view<char, std::__1::char_traits<char>>, std::__1::basic_format_args<std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char>>, char>>) /b/my/build/libcxx_build_msan/include/c++/v1/__format/format_functions.h:597:3
    #18 0xaaaacee00624 in auto $_1::operator()<char>(std::__1::basic_string_view<char, std::__1::char_traits<char>>, std::__1::basic_string_view<char, std::__1::char_traits<char>>) const /b/my/build/llvm-project/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp:42:7
    #19 0xaaaacedea6b0 in void format_tests<char, (execution_modus)1, $_0, $_1>($_0, $_1) /b/my/build/llvm-project/libcxx/test/std/utilities/format/format.functions/format_tests.h:3148:3
    #20 0xaaaacede80d0 in main /b/my/build/llvm-project/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp:54:3
    #21 0xffffbed96dbc in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #22 0xffffbed96e94 in __libc_start_main csu/../csu/libc-start.c:360:3
    #23 0xaaaaced5a02c in _start (/b/my/build/libcxx_build_msan/test/std/utilities/format/format.functions/Output/vformat.locale.pass.cpp.dir/t.tmp.exe+0x10a02c)

MemorySanitizer can not provide additional info.
SUMMARY: MemorySanitizer: ABRT nptl/pthread_kill.c:44:76 in __pthread_kill_implementation
==1128068==ABORTING

@vitalybuka
Copy link
Collaborator

It looks like libunwind in this setup fails, but I am not sure how to debug that.

@mordante
Copy link
Member Author

Thanks for the complete stack-trace. This seems to fail in a test that validates the expected exception is thrown. The test line contains check_exception("The argument index value is too large for the number of arguments supplied", SV("{:")); The call to failed_throw seems to indicate there's no catch handler found.

So I also start to suspect an issue in the unwinder. I'm also not sure how to debug that. Since the tests passes on other platforms including platforms using sanitizer I'm happy to keep the suppression on Zorg.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants