Skip to content
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

[libc++] Encode additional ODR-affecting properties in the ABI tag #69669

Merged
merged 4 commits into from Oct 26, 2023

Conversation

ldionne
Copy link
Member

@ldionne ldionne commented Oct 20, 2023

As explained in __config, we have an ABI tag that we use to ensure that we don't run into ODR issues when mixing different versions of libc++ in multiple TUs. However, the reasoning behind that extends not only to different versions of libc++, but also to different configurations of the same version of libc++. In fact, we've been aware of this for a while but never really bothered to make the change because ODR issues are often thought to be benign.

Well, it turns out that I just spent over an hour banging my head against an issue that boils down to our lack of encoding of some ODR properties in the ABI tag, so here's the patch we should have done a long time ago.

For now, the ODR properties we encode in the ABI tag are:

  • library version
  • exceptions vs no-exceptions
  • hardening mode

Those are all things that we support different values for on a per-TU basis and they definitely affect ODR in a meaningful way. We can add more properties later as we see fit.

As explained in __config, we have an ABI tag that we use to ensure that
we don't run into ODR issues when mixing different versions of libc++
in multiple TUs. However, the reasoning behind that extends not only to
different versions of libc++, but also to different configurations of
the same version of libc++. In fact, we've been aware of this for a while
but never really bothered to make the change because ODR issues are often
thought to be benign.

Well, it turns out that I just spent over an hour banging my head against
an issue that boils down to our lack of encoding some ODR properties in
the ABI tag, so here's the patch we should have done a long time ago.

For now, the ODR properties we encode in the ABI tag are:
- library version
- exceptions vs no-exceptions
- hardening mode

Those are all things that we support different values for on a per-TU
basis and they definitely affect ODR in a meaningful way. We can add
more properties later as we see fit.
@ldionne ldionne requested a review from a team as a code owner October 20, 2023 01:04
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Oct 20, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Oct 20, 2023

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

As explained in __config, we have an ABI tag that we use to ensure that we don't run into ODR issues when mixing different versions of libc++ in multiple TUs. However, the reasoning behind that extends not only to different versions of libc++, but also to different configurations of the same version of libc++. In fact, we've been aware of this for a while but never really bothered to make the change because ODR issues are often thought to be benign.

Well, it turns out that I just spent over an hour banging my head against an issue that boils down to our lack of encoding some ODR properties in the ABI tag, so here's the patch we should have done a long time ago.

For now, the ODR properties we encode in the ABI tag are:

  • library version
  • exceptions vs no-exceptions
  • hardening mode

Those are all things that we support different values for on a per-TU basis and they definitely affect ODR in a meaningful way. We can add more properties later as we see fit.


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

3 Files Affected:

  • (modified) libcxx/include/__config (+43-15)
  • (added) libcxx/test/libcxx/odr_signature.exceptions.sh.cpp (+43)
  • (added) libcxx/test/libcxx/odr_signature.hardening.sh.cpp (+63)
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 65ce6d6a27f8326..2fa548132bba569 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -56,10 +56,6 @@
 #  define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y
 #  define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y)
 
-// Valid C++ identifier that revs with every libc++ version. This can be used to
-// generate identifiers that must be unique for every released libc++ version.
-#  define _LIBCPP_VERSIONED_IDENTIFIER _LIBCPP_CONCAT(v, _LIBCPP_VERSION)
-
 #  if __STDC_HOSTED__ == 0
 #    define _LIBCPP_FREESTANDING
 #  endif
@@ -734,22 +730,54 @@ typedef __char32_t char32_t;
 #    define _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION _LIBCPP_ALWAYS_INLINE
 #  endif
 
+#  if _LIBCPP_ENABLE_HARDENED_MODE
+#    define _LIBCPP_HARDENING_SIG h
+#  elif _LIBCPP_ENABLE_SAFE_MODE
+#    define _LIBCPP_HARDENING_SIG s
+#  elif _LIBCPP_ENABLE_DEBUG_MODE
+#    define _LIBCPP_HARDENING_SIG d
+#  else
+#    define _LIBCPP_HARDENING_SIG u // for unchecked
+#  endif
+
+#  ifdef _LIBCPP_HAS_NO_EXCEPTIONS
+#    define _LIBCPP_EXCEPTIONS_SIG n
+#  else
+#    define _LIBCPP_EXCEPTIONS_SIG e
+#  endif
+
+#  define _LIBCPP_ODR_SIGNATURE                                                                                        \
+    _LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_CONCAT(v, _LIBCPP_VERSION), _LIBCPP_HARDENING_SIG), _LIBCPP_EXCEPTIONS_SIG)
+
 // This macro marks a symbol as being hidden from libc++'s ABI. This is achieved
 // on two levels:
 // 1. The symbol is given hidden visibility, which ensures that users won't start exporting
 //    symbols from their dynamic library by means of using the libc++ headers. This ensures
 //    that those symbols stay private to the dynamic library in which it is defined.
 //
-// 2. The symbol is given an ABI tag that changes with each version of libc++. This ensures
-//    that no ODR violation can arise from mixing two TUs compiled with different versions
-//    of libc++ where we would have changed the definition of a symbol. If the symbols shared
-//    the same name, the ODR would require that their definitions be token-by-token equivalent,
-//    which basically prevents us from being able to make any change to any function in our
-//    headers. Using this ABI tag ensures that the symbol name is "bumped" artificially at
-//    each release, which lets us change the definition of these symbols at our leisure.
-//    Note that historically, this has been achieved in various ways, including force-inlining
-//    all functions or giving internal linkage to all functions. Both these (previous) solutions
-//    suffer from drawbacks that lead notably to code bloat.
+// 2. The symbol is given an ABI tag that encodes the ODR-relevant properties of the library.
+//    This ensures that no ODR violation can arise from mixing two TUs compiled with different
+//    versions or configurations of libc++ (such as exceptions vs no-exceptions). Indeed, if the
+//    program contains two definitions of a function, the ODR requires them to be token-by-token
+//    equivalent, and the linker is allowed to pick either definition and discard the other one.
+//
+//    For example, if a program contains a copy of `vector::at()` compiled with exceptions enabled
+//    *and* a copy of `vector::at()` compiled with exceptions disabled (by means of having two TUs
+//    compiled with different settings), the two definitions are both visible by the linker and they
+//    have the same name, but they have a meaningfully different implementation (one throws an exception
+//    and the other aborts the program). This violates the ODR and makes the program ill-formed, and in
+//    practice what will happen is that the linker will pick one of the definitions at random and will
+//    discard the other one. This can quite clearly lead to incorrect program behavior.
+//
+//    A similar reasoning holds for many other properties that are ODR-affecting. Essentially any
+//    property that causes the code of a function to differ from the code in another configuration
+//    can be considered ODR-affecting. In practice, we don't encode all such properties in the ABI
+//    tag, but we encode the ones that we think are most important: library version, exceptions, and
+//    hardening mode.
+//
+//    Note that historically, solving this problem has been achieved in various ways, including
+//    force-inlining all functions or giving internal linkage to all functions. Both these previous
+//    solutions suffer from drawbacks that lead notably to code bloat.
 //
 // Note that we use _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION to ensure that we don't depend
 // on _LIBCPP_HIDE_FROM_ABI methods of classes explicitly instantiated in the dynamic library.
@@ -769,7 +797,7 @@ typedef __char32_t char32_t;
 #  ifndef _LIBCPP_NO_ABI_TAG
 #    define _LIBCPP_HIDE_FROM_ABI                                                                                      \
       _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION                                                       \
-          __attribute__((__abi_tag__(_LIBCPP_TOSTRING(_LIBCPP_VERSIONED_IDENTIFIER))))
+          __attribute__((__abi_tag__(_LIBCPP_TOSTRING(_LIBCPP_ODR_SIGNATURE))))
 #  else
 #    define _LIBCPP_HIDE_FROM_ABI _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION
 #  endif
diff --git a/libcxx/test/libcxx/odr_signature.exceptions.sh.cpp b/libcxx/test/libcxx/odr_signature.exceptions.sh.cpp
new file mode 100644
index 000000000000000..4796f4070f86300
--- /dev/null
+++ b/libcxx/test/libcxx/odr_signature.exceptions.sh.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Test that we encode whether exceptions are supported in an ABI tag to avoid
+// ODR violations when linking TUs that have different values for it.
+
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU1  -fno-exceptions -o %t.tu1.o
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU2  -fexceptions    -o %t.tu2.o
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DMAIN                 -o %t.main.o
+// RUN: %{cxx} %t.tu1.o %t.tu2.o %t.main.o %{flags} %{link_flags} -o %t.exe
+// RUN: %{exec} %t.exe
+
+// -fno-exceptions
+#ifdef TU1
+#  include <__config>
+_LIBCPP_HIDE_FROM_ABI inline int f() { return 1; }
+int tu1() { return f(); }
+#endif // TU1
+
+// -fexceptions
+#ifdef TU2
+#  include <__config>
+_LIBCPP_HIDE_FROM_ABI inline int f() { return 2; }
+int tu2() { return f(); }
+#endif // TU2
+
+#ifdef MAIN
+#  include <cassert>
+
+int tu1();
+int tu2();
+
+int main(int, char**) {
+  assert(tu1() == 1);
+  assert(tu2() == 2);
+  return 0;
+}
+#endif // MAIN
diff --git a/libcxx/test/libcxx/odr_signature.hardening.sh.cpp b/libcxx/test/libcxx/odr_signature.hardening.sh.cpp
new file mode 100644
index 000000000000000..b9965030966509d
--- /dev/null
+++ b/libcxx/test/libcxx/odr_signature.hardening.sh.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Test that we encode the hardening mode in an ABI tag to avoid ODR violations
+// when linking TUs that have different values for it.
+
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU1  -D_LIBCPP_ENABLE_HARDENED_MODE -o %t.tu1.o
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU2  -D_LIBCPP_ENABLE_SAFE_MODE     -o %t.tu2.o
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU3  -D_LIBCPP_ENABLE_DEBUG_MODE    -o %t.tu3.o
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU4                                 -o %t.tu4.o
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DMAIN                                -o %t.main.o
+// RUN: %{cxx} %t.tu1.o %t.tu2.o %t.tu3.o %t.tu4.o %t.main.o %{flags} %{link_flags} -o %t.exe
+// RUN: %{exec} %t.exe
+
+// hardened mode
+#ifdef TU1
+#  include <__config>
+_LIBCPP_HIDE_FROM_ABI inline int f() { return 1; }
+int tu1() { return f(); }
+#endif // TU1
+
+// safe mode
+#ifdef TU2
+#  include <__config>
+_LIBCPP_HIDE_FROM_ABI inline int f() { return 2; }
+int tu2() { return f(); }
+#endif // TU2
+
+// debug mode
+#ifdef TU3
+#  include <__config>
+_LIBCPP_HIDE_FROM_ABI inline int f() { return 3; }
+int tu3() { return f(); }
+#endif // TU3
+
+// unchecked mode
+#ifdef TU4
+#  include <__config>
+_LIBCPP_HIDE_FROM_ABI inline int f() { return 4; }
+int tu4() { return f(); }
+#endif // TU4
+
+#ifdef MAIN
+#  include <cassert>
+
+int tu1();
+int tu2();
+int tu3();
+int tu4();
+
+int main(int, char**) {
+  assert(tu1() == 1);
+  assert(tu2() == 2);
+  assert(tu3() == 3);
+  assert(tu4() == 4);
+  return 0;
+}
+#endif // MAIN

libcxx/include/__config Outdated Show resolved Hide resolved
libcxx/include/__config Show resolved Hide resolved
@EricWF
Copy link
Member

EricWF commented Oct 20, 2023

Before merging this could you do some analysis to what this does to binary size, both with and without debug info?

@ldionne
Copy link
Member Author

ldionne commented Oct 20, 2023

Before merging this could you do some analysis to what this does to binary size, both with and without debug info?

Do you mean the binary size of libc++.dylib itself or something else?

@EricWF
Copy link
Member

EricWF commented Oct 20, 2023

Before merging this could you do some analysis to what this does to binary size, both with and without debug info?

Do you mean the binary size of libc++.dylib itself or something else?

I mean something else. Choose something that instantiates a lot of templates in our test suite, and then compile that to an object. We're increasing the size of the mangled names here, and I want to know what effect that has.

libcxx/include/__config Outdated Show resolved Hide resolved
@philnik777 philnik777 added the ABI Application Binary Interface label Oct 22, 2023
@EricWF
Copy link
Member

EricWF commented Oct 23, 2023

I'm fine with this change btw. It LGTM.

@ldionne
Copy link
Member Author

ldionne commented Oct 23, 2023

I mean something else. Choose something that instantiates a lot of templates in our test suite, and then compile that to an object. We're increasing the size of the mangled names here, and I want to know what effect that has.

Ok, that makes sense. So here we go. I took libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.range.pass.cpp since that was the slowest Ranges test, and those usually instantiate a lot of stuff.

First, with -O0:

$ bloaty O0-before.o
    FILE SIZE        VM SIZE
 --------------  --------------
  44.7%  3.72Mi   0.0%       0    String Table
  30.8%  2.56Mi  83.5%  2.56Mi    ,__text
  15.0%  1.25Mi   0.0%       0    [Unmapped]
   5.4%   458Ki  14.6%   458Ki    ,__compact_unwind
   3.4%   288Ki   0.0%       0    Symbol Table
   0.5%  40.3Ki   1.3%  40.3Ki    ,__const
   0.1%  10.7Ki   0.3%  10.7Ki    ,__literal16
   0.1%  6.80Ki   0.2%  6.80Ki    ,__data
   0.0%  2.68Ki   0.1%  2.68Ki    ,__literal4
   0.0%     872   0.0%       0    [Mach-O Headers]
   0.0%     664   0.0%     664    ,__cstring
   0.0%      16   0.0%      16    ,__gcc_except_tab
   0.0%       4   0.0%       4    []
 100.0%  8.32Mi 100.0%  3.07Mi    TOTAL

$ bloaty O0-after.o
    FILE SIZE        VM SIZE
 --------------  --------------
  44.8%  3.73Mi   0.0%       0    String Table
  30.8%  2.56Mi  83.5%  2.56Mi    ,__text
  15.0%  1.25Mi   0.0%       0    [Unmapped]
   5.4%   458Ki  14.6%   458Ki    ,__compact_unwind
   3.4%   288Ki   0.0%       0    Symbol Table
   0.5%  40.3Ki   1.3%  40.3Ki    ,__const
   0.1%  10.7Ki   0.3%  10.7Ki    ,__literal16
   0.1%  6.80Ki   0.2%  6.80Ki    ,__data
   0.0%  2.68Ki   0.1%  2.68Ki    ,__literal4
   0.0%     872   0.0%       0    [Mach-O Headers]
   0.0%     664   0.0%     664    ,__cstring
   0.0%      16   0.0%      16    ,__gcc_except_tab
   0.0%       4   0.0%       4    []
 100.0%  8.33Mi 100.0%  3.07Mi    TOTAL

There is a 0.1% size increase for that test (which should be pretty intensive in terms of instantiating libc++ internal symbols with the ABI tag).

Now with -O3:

$ bloaty O3-before.o
    FILE SIZE        VM SIZE
 --------------  --------------
  35.6%   109Ki   0.0%       0    String Table
  21.9%  67.6Ki  67.1%  67.6Ki    ,__text
  20.1%  62.2Ki   0.0%       0    [Unmapped]
  10.6%  32.7Ki  32.4%  32.7Ki    ,__compact_unwind
   6.0%  18.7Ki   0.0%       0    Optimization Hints
   5.4%  16.7Ki   0.0%       0    Symbol Table
   0.2%     728   0.0%       0    [Mach-O Headers]
   0.1%     313   0.3%     313    ,__cstring
   0.0%      72   0.1%      72    ,__const
   0.0%      64   0.1%      64    ,__literal16
   0.0%      19   0.0%      19    []
   0.0%       8   0.0%       8    ,__literal8
 100.0%   309Ki 100.0%   100Ki    TOTAL

$ bloaty O3-after.o
    FILE SIZE        VM SIZE
 --------------  --------------
  35.6%   109Ki   0.0%       0    String Table
  21.9%  67.6Ki  67.1%  67.6Ki    ,__text
  20.1%  62.2Ki   0.0%       0    [Unmapped]
  10.6%  32.7Ki  32.4%  32.7Ki    ,__compact_unwind
   6.0%  18.7Ki   0.0%       0    Optimization Hints
   5.4%  16.7Ki   0.0%       0    Symbol Table
   0.2%     728   0.0%       0    [Mach-O Headers]
   0.1%     313   0.3%     313    ,__cstring
   0.0%      72   0.1%      72    ,__const
   0.0%      64   0.1%      64    ,__literal16
   0.0%      19   0.0%      19    []
   0.0%       8   0.0%       8    ,__literal8
 100.0%   309Ki 100.0%   100Ki    TOTAL

This seems to show no difference at all between before and after at -O3.

//===----------------------------------------------------------------------===//

// TODO: Investigate
// XFAIL: target={{.+}}-windows-{{.+}}
Copy link
Member Author

Choose a reason for hiding this comment

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

@mstorsjo Do you know why this might fail on Windows? ABI tags are supported an honored on Windows too, right?

Copy link
Member

Choose a reason for hiding this comment

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

It seems like these ABI tags aren't supported when using the MSVC C++ name mangling - but as you observed, it does work with MinGW which uses the regular Itanium name mangling. I don't know the details any further than that for the MSVC C++ ABI though - maybe @rnk might know?

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's correct, ABI tags are only supported for targets using the Itanium C++ ABI, so non-MSVC targets.

@EricWF
Copy link
Member

EricWF commented Oct 24, 2023

1% 10.7Ki 0.3% 10.7Ki ,__literal16
0.1% 6.80Ki 0.2% 6.80Ki ,__data

If it's not too much trouble, I'm interested in the results for debug mode. But feel free to ignore this, and don't consider it a blocker.

Again, this LGTM.

@ldionne
Copy link
Member Author

ldionne commented Oct 24, 2023

Here's the results for libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.range.pass.cpp when compiling with -O0 -g (that's what you wanted right?):

$ bloaty debug-before.o
    FILE SIZE        VM SIZE
 --------------  --------------
  30.9%  5.60Mi  44.0%  5.60Mi    ,__debug_str
  20.5%  3.72Mi   0.0%       0    String Table
  14.7%  2.67Mi  21.0%  2.67Mi    ,__debug_info
  14.1%  2.56Mi  20.1%  2.56Mi    ,__text
   7.6%  1.38Mi   0.0%       0    [Unmapped]
   4.7%   870Ki   6.7%   870Ki    ,__debug_line
   2.8%   524Ki   4.0%   524Ki    ,__apple_names
   2.5%   458Ki   3.5%   458Ki    ,__compact_unwind
   1.6%   288Ki   0.0%       0    Symbol Table
   0.2%  40.3Ki   0.3%  40.3Ki    ,__const
   0.2%  33.7Ki   0.3%  33.7Ki    ,__apple_types
   0.1%  10.7Ki   0.1%  10.7Ki    ,__literal16
   0.0%  6.80Ki   0.1%  6.80Ki    ,__data
   0.0%  2.68Ki   0.0%  2.68Ki    ,__literal4
   0.0%  1.63Ki   0.0%       0    [Mach-O Headers]
   0.0%  1.45Ki   0.0%  1.45Ki    ,__debug_abbrev
   0.0%     664   0.0%     664    ,__cstring
   0.0%     372   0.0%     372    ,__apple_namespac
   0.0%      56   0.0%      56    ,__eh_frame
   0.0%      52   0.0%      52    [2 Others]
   0.0%      48   0.0%      48    ,__debug_ranges
 100.0%  18.1Mi 100.0%  12.7Mi    TOTAL

$ bloaty debug-after.o
    FILE SIZE        VM SIZE
 --------------  --------------
  30.9%  5.61Mi  44.0%  5.61Mi    ,__debug_str
  20.6%  3.73Mi   0.0%       0    String Table
  14.7%  2.67Mi  21.0%  2.67Mi    ,__debug_info
  14.1%  2.56Mi  20.1%  2.56Mi    ,__text
   7.6%  1.38Mi   0.0%       0    [Unmapped]
   4.7%   870Ki   6.7%   870Ki    ,__debug_line
   2.8%   524Ki   4.0%   524Ki    ,__apple_names
   2.5%   458Ki   3.5%   458Ki    ,__compact_unwind
   1.6%   288Ki   0.0%       0    Symbol Table
   0.2%  40.3Ki   0.3%  40.3Ki    ,__const
   0.2%  33.7Ki   0.3%  33.7Ki    ,__apple_types
   0.1%  10.7Ki   0.1%  10.7Ki    ,__literal16
   0.0%  6.80Ki   0.1%  6.80Ki    ,__data
   0.0%  2.68Ki   0.0%  2.68Ki    ,__literal4
   0.0%  1.63Ki   0.0%       0    [Mach-O Headers]
   0.0%  1.45Ki   0.0%  1.45Ki    ,__debug_abbrev
   0.0%     664   0.0%     664    ,__cstring
   0.0%     372   0.0%     372    ,__apple_namespac
   0.0%      56   0.0%      56    ,__eh_frame
   0.0%      52   0.0%      52    [2 Others]
   0.0%      48   0.0%      48    ,__debug_ranges
 100.0%  18.1Mi 100.0%  12.7Mi    TOTAL

There doesn't seem to be a super significant change here either. Also FWIW I have no idea how symbols are stored inside debug information and whether it's possible to change that without breaking the world, but it would be quite awesome if they were stored in some sort of compressed form. For example we could store symbols in some kind of prefix tree and then this change would have basically no effect on the overall size of symbols.

@philnik777
Copy link
Contributor

https://maskray.me/blog/2022-01-23-compressed-debug-sections

@rnk
Copy link
Collaborator

rnk commented Oct 24, 2023

To make the size comparison easier, bloaty has a builtin comparison feature, see the docs here:
https://github.com/google/bloaty/blob/main/doc/using.md

Comparison commands seem to look like: bloaty binary.after -- binary.before.

@ldionne
Copy link
Member Author

ldionne commented Oct 26, 2023

To make the size comparison easier, bloaty has a builtin comparison feature, see the docs here: https://github.com/google/bloaty/blob/main/doc/using.md

Comparison commands seem to look like: bloaty binary.after -- binary.before.

Yeah I realized that after reading @MaskRay 's blog post, thanks a bunch! I'll use that going forward :)

@ldionne ldionne merged commit bc792a2 into llvm:main Oct 26, 2023
4 checks passed
@ldionne ldionne deleted the review/odr-issues-abi-namespace branch October 26, 2023 13:05
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Oct 26, 2023
…lvm#69669)

As explained in `__config`, we have an ABI tag that we use to ensure
that we don't run into ODR issues when mixing different versions of
libc++ in multiple TUs. However, the reasoning behind that extends not
only to different versions of libc++, but also to different
configurations of the same version of libc++. In fact, we've been aware
of this for a while but never really bothered to make the change because
ODR issues are often thought to be benign.

Well, it turns out that I just spent over an hour banging my head
against an issue that boils down to our lack of encoding of some ODR
properties in the ABI tag, so here's the patch we should have done a
long time ago.

For now, the ODR properties we encode in the ABI tag are:
- library version
- exceptions vs no-exceptions
- hardening mode

Those are all things that we support different values for on a per-TU
basis and they definitely affect ODR in a meaningful way. We can add
more properties later as we see fit.
tru pushed a commit that referenced this pull request Oct 30, 2023
…69669)

As explained in `__config`, we have an ABI tag that we use to ensure
that we don't run into ODR issues when mixing different versions of
libc++ in multiple TUs. However, the reasoning behind that extends not
only to different versions of libc++, but also to different
configurations of the same version of libc++. In fact, we've been aware
of this for a while but never really bothered to make the change because
ODR issues are often thought to be benign.

Well, it turns out that I just spent over an hour banging my head
against an issue that boils down to our lack of encoding of some ODR
properties in the ABI tag, so here's the patch we should have done a
long time ago.

For now, the ODR properties we encode in the ABI tag are:
- library version
- exceptions vs no-exceptions
- hardening mode

Those are all things that we support different values for on a per-TU
basis and they definitely affect ODR in a meaningful way. We can add
more properties later as we see fit.

(cherry picked from commit bc792a2)
@AntonRydahl
Copy link
Contributor

AntonRydahl commented Oct 31, 2023

Hi @ldionne

This change breaks OpenMP offloading on my machine. I traced it back to this commit with git bisect. If I compile simple tests programs with OpenMP offloading enabled, I get runtime errors like

"PluginInterface" error: Failure to load binary image 0x555555892c30 on device 0: Error in hsa_executable_get_symbol_by_name(__omp_offloading_16_cff8cf6__ZNSt3__122__omp_transform_reduceB8se180000IPdS1_ldvZ4mainE3$_0EET2_T_T0_T1_S3_NS_4plusIT3_EET4__l87.kd): HSA_STATUS_ERROR_INVALID_SYMBOL_NAME: There is no symbol with the given name.
Libomptarget error: Unable to generate entries table for device id 0.
Libomptarget error: Failed to init globals on device 0
Libomptarget error: Consult https://openmp.llvm.org/design/Runtimes.html for debugging options.
Libomptarget error: Source location information not present. Compile with -g or -gline-tables-only.
Libomptarget fatal error 1: failure of target construct while offloading is mandatory

and I did not get any from the previous commit in the log.

I am not trying to ask you to revert this commit, but could you please help me understand what side effects this commit could have?

@ldionne
Copy link
Member Author

ldionne commented Oct 31, 2023

Hi @ldionne

This change breaks OpenMP offloading on my machine. I traced it back to this commit with git bisect. If I compile simple tests programs with OpenMP offloading enabled, I get runtime errors like

"PluginInterface" error: Failure to load binary image 0x555555892c30 on device 0: Error in hsa_executable_get_symbol_by_name(__omp_offloading_16_cff8cf6__ZNSt3__122__omp_transform_reduceB8se180000IPdS1_ldvZ4mainE3$_0EET2_T_T0_T1_S3_NS_4plusIT3_EET4__l87.kd): HSA_STATUS_ERROR_INVALID_SYMBOL_NAME: There is no symbol with the given name.
[...]

and I did not get any from the previous commit in the log.

I am not trying to ask you to revert this commit, but could you please help me understand what side effects this commit could have?

If I had to guess, I would say there's some kind of mismatch between whether exceptions or hardening is enabled or not when you compile a function. I don't know how OpenMP offloading works, but if the compiler compiled the device code with e.g. exceptions disabled and then tried to find that function from a TU where exceptions are enabled, it could be that there's a mismatch between the mangled name the compiler expects to find and the actual mangled name that was generated for the device.

@AntonRydahl
Copy link
Contributor

Thanks a lot for the quick reply! I will try to see if enabling or disabling exceptions will resolve the problem. :D

@AntonRydahl
Copy link
Contributor

It worked to compile everything with exceptions disabled.

AntonRydahl added a commit to AntonRydahl/llvm-project that referenced this pull request Nov 2, 2023
AntonRydahl added a commit to AntonRydahl/llvm-project that referenced this pull request Nov 8, 2023
AntonRydahl added a commit to AntonRydahl/llvm-project that referenced this pull request Nov 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ABI Application Binary Interface libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants