<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/79027>79027</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [libc++] After 3583bf3ad8c5, building Firefox results in hidden symbol errors
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            libc++,
            quality-of-implementation
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          DimitryAndric
      </td>
    </tr>
</table>

<pre>
    I'm investigating a build breakage of Firefox with very recent libc++ (as of `llvmorg-18-init-16864-g`3b3ee1f53424), on FreeBSD 15-CURRENT. What happens is that most of the build goes well, until it tries to link its main shared library, `libxul.so`:

```text
toolkit/library/build/libxul.so
rm -f libxul.so
clang++ -std=gnu++17 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fstack-clash-protection -DLIBICONV_PLUG -isystem /usr/local/include -fno-sized-deallocation -fno-aligned-new -O2 -pipe -O3 -DLIBICONV_PLUG -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -DLIBICONV_PLUG -isystem /usr/local/include -fno-exceptions -fPIC -fno-rtti -ffunction-sections -fdata-sections -fno-exceptions -fno-math-errno -pipe -O2 -O3 -fno-omit-frame-pointer -funwind-tables -shared -Wl,-z,defs -Wl,--warn-unresolved-symbols -Wl,--gc-sections -Wl,-h,libxul.so -o libxul.so /wrkdirs/usr/ports/www/firefox/work/.build/toolkit/library/build/libxul_so.list -pthread -Wl,--as-needed -fstack-protector-strong -fuse-ld=lld -Wl,-z,noexecstack -Wl,-z,text -Wl,-z,relro -Wl,-z,nocopyreloc -Wl,-Bsymbolic-functions -Wl,--build-id=sha1 -fstack-protector-strong -fstack-clash-protection -Wl,-rpath-link,/wrkdirs/usr/ports/www/firefox/work/.build/dist/bin -Wl,-rpath-link,/usr/local/lib  ../../../js/src/build/libjs_static.a ../../../build/pure_virtual/libpure_virtual.a /wrkdirs/usr/ports/www/firefox/work/.build/x86_64-unknown-freebsd/release/libgkrust.a ../../../config/external/gkcodecs/libgkcodecs.so ../../../config/external/lgpllibs/liblgpllibs.so ../../../config/external/sqlite/libmozsqlite3.so ../../../widget/gtk/mozgtk/libmozgtk.so ../../../widget/gtk/mozwayland/libmozwayland.so -Wl,--version-script,libxul.so.symbols  -L/usr/local/lib -licui18n -L/usr/local/lib -licuuc -licudata -laom -ldav1d -lX11 -lXcomposite -lXdamage -lXext -lXfixes -lXrandr -lXrender -lpthread -lffi -lplds4 -lplc4 -lnspr4 -pthread -ldl -L/lib -lz -lm -lnss3 -lsmime3 -lssl3 -lnssutil3 -lfreetype -lfontconfig -lgdk-3 -lharfbuzz -lpangocairo-1.0 -lpango-1.0 -lgtk-3 -latk-1.0 -lcairo -lcairo-gobject -lgdk_pixbuf-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lgio-2.0 -lutil -lpng16 -lwebp -lwebpdemux -lgraphite2 -levent -lvpx -lpixman-1 -ldbus-1 -lxcb-shm -lX11-xcb -lxcb -lXcursor -lXi
ld.lld: error: undefined hidden symbol: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::operator=(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&)
>>> referenced by Unified_cpp_xpcom_build0.cpp
>>> /wrkdirs/usr/ports/www/firefox/work/.build/toolkit/library/build/../../../xpcom/build/Unified_cpp_xpcom_build0.o:(NS_InitXPCOM)
>>> referenced by Unified_cpp_xpcom_build0.cpp
>>> /wrkdirs/usr/ports/www/firefox/work/.build/toolkit/library/build/../../../xpcom/build/Unified_cpp_xpcom_build0.o:(NS_InitXPCOM)
>>> referenced by DataChannel.cpp
>>> /wrkdirs/usr/ports/www/firefox/work/.build/toolkit/library/build/../../../netwerk/sctp/datachannel/DataChannel.o:(mozilla::DataChannelConnection::SetSignals(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&))
>>> referenced 275 more times

ld.lld: error: undefined hidden symbol: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::append(char const*, unsigned long)
>>> referenced by Unified_cpp_protocol_http4.cpp
>>> /wrkdirs/usr/ports/www/firefox/work/.build/toolkit/library/build/../../../netwerk/protocol/http/Unified_cpp_protocol_http4.o:(mozilla::net::nsHttpConnectionInfo::BuildHashKey())
>>> referenced by Unified_cpp_ipc_chromium0.cpp
>>> /wrkdirs/usr/ports/www/firefox/work/.build/toolkit/library/build/../../../ipc/chromium/Unified_cpp_ipc_chromium0.o:(FilePath::Append(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&) const)
>>> referenced by Unified_cpp_ipc_chromium0.cpp
>>> /wrkdirs/usr/ports/www/firefox/work/.build/toolkit/library/build/../../../ipc/chromium/Unified_cpp_ipc_chromium0.o:(base::BuildEnvironmentArray(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>>> const&))
>>> referenced 353 more times
... many more of these ...
```

After much digging, the reason for these symbols being hidden turns out to be a little trick Mozilla uses to limit the amount of visible symbols in `libxul.so`: the file https://github.com/mozilla/gecko-dev/blob/master/config/gcc_hidden.h which gets included in front of every `.cpp` file, using `-include /wrkdirs/usr/ports/www/firefox/work/firefox-122.0/config/gcc_hidden.h`.

The file contains nothing but a `#pragma GCC visibility push(hidden)` line, so that _everything_ following is hidden, including libc++ headers such as `<string>`, `<vector>`, etc.

Before commit 3b3ee1f53424, this made no difference since most of the templates used in libc++ headers are prefixed with `_LIBCPP_TEMPLATE_VIS`, and this expanded to either `__attribute__((__type_visibility__("default")))` (for clang) or `__attribute__((__visibility__("default")))` (for gcc), which would override the `#pragma GCC visibility push(hidden)` state.

After commit 3b3ee1f53424 however, this no longer happens: `_LIBCPP_TEMPLATE_VIS` is defined empty if clang is used, and whatever visibility is "active" due to such a pragma is used for most templates in the libc++ headers.

So this example shared library:

```c++
#pragma GCC visibility push(hidden)

#include <string>

std::string foo(char const* s, size_t len)
{
  std::string t("bar");
  return t.append(s, len);
}
```

Will not compile and link anymore with libc++ 18:

```sh
$ clang++ -fPIC hidden-string.cpp -o hidden-string.so -shared
ld: error: undefined hidden symbol: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::append(char const*, unsigned long)
>>> referenced by hidden-string.cpp
>>> /tmp/hidden-string-983b67.o:(foo(char const*, unsigned long))
>>> did you mean: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::append(char const*)
>>> defined in: /lib/libc++.so.1

ld: error: undefined hidden symbol: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::basic_string(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&)
>>> referenced by hidden-string.cpp
>>> /tmp/hidden-string-983b67.o:(foo(char const*, unsigned long))
>>> did you mean: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::basic_string(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&)
>>> defined in: /lib/libc++.so.1

ld: error: undefined hidden symbol: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::~basic_string()
>>> referenced by hidden-string.cpp
>>>               /tmp/hidden-string-983b67.o:(foo(char const*, unsigned long))
>>> referenced by hidden-string.cpp
>>> /tmp/hidden-string-983b67.o:(foo(char const*, unsigned long))

ld: error: undefined hidden symbol: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::__init(char const*, unsigned long)
>>> referenced by hidden-string.cpp
>>> /tmp/hidden-string-983b67.o:(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::basic_string[abi:se180000]<0>(char const*))
c++: error: linker command failed with exit code 1 (use -v to see invocation)
```

Now I am aware that Firefox could use `-fvisibility=hidden` and maybe also `-fvisibility-inlines-hidden` to achieve the same effect, and that does indeed seem to work, at least for the above simple test case.

But before I go to Mozilla and report this as a bug in their tracker, I would like to have an official word from the libc++ maintainers about whether this whole use case is supposed to work at all.

That is: can you do `#pragma GCC visibility push(hidden)` (or its clang equivalent, if it exists), and then expect to include any libc++ headers without problems? If so, commit 3583bf3ad8c5 would have to be adjusted to make it possible, since it no longer works now.

Or: is this kind of messing with visibility around libc++ headers officially unsupported, and would applications attempting to use such methods have to be adjusted?

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWltz2ziy_jX0SxdUEnWx8uAHW452XSczSU2SnZwnFkg0SUQgwAFAXfJwfvupBkjrYns22andZHY3lbJIXBqN7g-N_gBy52SlEW-S-V0yv7_ina-NvbmXjfT2cKuFlcVVbsTh5iFJrxuQeovOy4p7qSvgkHdSCcgt8g2vEEwJa2mxNHvYSV_DFu0BLBaoPSiZF0l6l6R3kKRL7qhxshgrtW2MrdhkyaSWnk0Wy8WMVcliPM2niJNyPp2lsyR9laQrMBrWFvHu_T1M5mz18ZdfXv_8YQS_1txDzdsWtQPpwNN7Y5ynMXyNvZqVQQc7VIpEddpLBdKDtxIdeANK6g1I76DhUoOruUVBWltuD9SDlJX5vlMjZ5LFOJneJuP7ZDz8XYzjf497H4u8MWojfZKuH6WsgyaxpJcUmtoGWAkXhYXiuupNxpwXyfS-0l0smFwD-5it3_7y4WH9v9n7tx9_Wb0Gdn9RkkzvU2Cl87zYsNYaj4U3ljlvja4eKwrFXT1US6OB3b95uHtYvf35b9m7Nx__Aky6g_PYQJKuO2dJfVNwlaRrqQvVCQRWasOc_IKCCeSKqqMkKueKMCaYxh2wtymwVrYI7O306UAvqvqVGngrC08DckcA_QcngvsCW9LfASvfPaxiqfVeAivLTgcrMRetRW0E9_z0_VKGNqzhvmZorTaP80-jDajWNNKz0vIGWWuk9miBlZ3eSS2Y57lCB6xHJPuV8Mu-JOlKYOmGd7bjVrNOW3RGbVEwd2hyo471VXGiYSyrk3T1iDlg5ghAMtDOboS07tFUrbGe3na7XZKuy7jO6d3YTZKuRwO0_z7sM2dGSjoPrPW1Rf44KcYd04iCpvkyajuHTNFqUOrMHNrgHovQ7bSYFuTpu0VlzXm_wrQHi8oUQ_FdtJ4s2ODuoyHDXJgkBVzNJ__I-oqSbEuYoLCTpKs_YHAhHVk7ly9KPse6kjnAaEQiHv98poGcLc599dllznMvixG_7DC0ajuL2VZa3w2yT0tG_I8gab9cZIsZ6_RGm51mpUXMHVVYVMgdxvGqje2cf6phYXQpqyRd496j1UG9alMYgYUbesY3AvxXdFZVq5TM-87D21d2dr8p6XuNG_Mlvk6f6byTokLyZ-XJGI35Eh9iv8pvvqrPjh8U1-KxX_8e1nmP4y1aF-JYYWXrT0PBaIgdwN48ix6mZNHJyVL_boOuiL8UHYEpbhpgSvDtRABTnyYT-luYpjVOeqQXwRvKIpj6FJas-lTKPUU-9clyLWx4QC0oOKrHyKHKUtK7Em4Wfgv60a61s5P4ooSKukbtvgBTTWjmpsCUa2SD4cGpaSzuvAyPBDp_oHitSqN9dC0wVYkNo_qa2zLvvpDAluvKFFxawyaj8VDQP1c-tud-05eElsMvq0z-GQsfJWet3OddydLYVcm8f5TaKyqJjYd6afonUprG1dVkAUztMG_7H4FNt6e2lre19JgCU7ilvIypbUs1rdw3XDPyisg7Fx72Rc5c3UR3sX2Rx7LguM46E1wiY7aixEhRVL4FtNZYeui0wFJqFFBLIVBDxBVVhXTmNpneZtkkPuTcySKjHVxXyXRV1NxS1vW0IdVk3nLp3dBu-vr5pn0mQto8NqT_VGdatLHqPkmX31MfKIymCL6gLDcmk72er8FiiRZ1gQLyA3zUspQosqJts31bmCYLoXI8Ktr2suc_aQe_iDxBi5PqFzU0ZIF0-fP77EFL_-nd6u1P_53u-XTvueermmuN6vvNUKPfYejtCt9SdsE9L6JWSbo-1bGfY2O-SKV4RPhJ_cpoHROeWPUe_XtZaa7cj7Teftcp6fUcGmMRvGzQndK9P1u0C-RYJOmSKgYD3EYiHI4ABChDbPMbliRltKYwKqu9b2c_AmQHjZJ0TTpdLNALfZ-Dr0bfP7i_et8eIfygSxNr7kiJv3JX_w8eknT5dzF0YTTZFllRW9PIrvmOgUy2lOoPilwY6lzH3k5rqfAd93W0wu2Apx9lIQ_P_wmuyIn7HMH4Wm-lNbpB7W-t5YdnvdLwNpmuvmsgerbt9x5foXPf2zBf0_xpbcvl8xX_-gX4nR37uGC_emOfzqdPNvbRaAQN14dYEU-OHcJoNLo44T3NA25LjxaarqhByKqiuaarcOZskTujoTS2FzSQ6hylroYcwXdWOzCdB28gR-CgpPcKwVtZbOCnuDlB54Yz6kb6IJ43ptPhgHsrnczVUb7UzxxVhz6lVAi0-bkQR9ZJuq6kr7t8FLPaYStM1xUWG8MEbilsKZNTJXce7enpRlUUWZzGqIZdLYsaKvSkQDhLFaRJaU3UEsNdQLKIgXYxDsqE_COc1CaLMRvOYL897PYFbJKmo_FLKtLYp677MFikMNpzqR1o42tSJu88cFIpSaet5VXD4S-rVTS0VNIfoO1cnaTLKJqgthiDkjpMyJl4AZGFKQeJGZRGKbMj4dLB0G3Vm4qKT65HauQCrQNHqOIuKELrPK6k10GvVV-6DSeOx1L0xdkk77AkNBemIeCcX6kQTqWDhgsEbUDIsl8f4CT9Pb1B8di0int0BMXg2WcU5hahtVjKPYp4AZQsxtmbh7vVu3fZh9c_vXtz--F19reH972yXIuoAu5brgkx3gBKX6MNPTPuvZV55zHLQqq1zDJ_aDE7eqKvSAWWvFM-SdN-7UefJOmSFmB_k_IKzMuCv1VmVRT9rVSE_s50SoDZorVSYDDatyLIee5x9DS8POM9qM2O8PXoRW1CAo92uAijRf-y-QmGA13BpvUHkGU0E9WQjwcH7WruaaRT5aWDJE154eUWkzQF0SG5LgIW-gn3ckIEDFA6YkjqYJ-nEDqb_HszoIM3LQW48yu5F-7feol96Veb_1RUOn0MRafr7qTJ49YUa6E05pJbgQvBQH7BzIM6HeS6Vw7gUoyPwMtpqwygmz42tUhbBfjRI5ML8nvBQ7vk-v53NqtfpVIU5AhQLUU-8m-49uT6EHa9sGhP3DJZvmRmVw_GmsHZRWW4MIt2ZXFaFPGBmYtCZ4YrrYFR_-ex6SdmeoaB-IZ47FlL9mo5zRfXAx14BnzPqvJUGyEFHEwHDXL9Y1v2qeo9OmRQPPKs-LfH7siZ0eT8yObPA7Cz8X4ckv1fNP9buvHfey3934UX_jiOz__9k1H9Q6yxP53Ts0xq6X-UHfr72-NsvPkdzyVlnThZjsfjcTK_T6arcRD8dOMdTDQk1qcYoOSxJyiUS5ZcqoH64V5SoikQJkSZOofAtoElIILU2_4TsaMHnstYfzY7eADeAN8RuQy8evjCsAiEi-QmizErj8l9Mr3v8_rFOKS4DT_kCFw5c9mUSU203bFjB2-AF7XEbeRwjjcIWJZY-CNl5R6ECTxGIAqaUUP94mnECjgl_Nz54fAHeG62xKoDjfHoPBTcnTO9u85DHsn6A1SGxA2HPzSmxdZYH_kQd-HLy6qnUdKCt7zYRDL40BNRJTeBk9V8S3k-mLKUheSKlBRQWtNcUrCGy3AOEph8bjoPuxoDFw-j7mqjMJibdCd257q2NS6ydpo6zZsrdXHIwj3IQEYLrsP2LMw3E-MkXRobvs2MFBV_6-SWK9TBJ7IE6Qlvzruekkc3oQbct1iEw7WB0nF9eO7sgjBLc26tyRU2Lpmu4aEEZ0jcQMDny2leTrlYFvPezMG8_dGd-Nw5H83R8A2SUq1x4XAuUkFdhMIjVSerEXXfndnsbVha4TtW6WAjtQBTQoMunJTFD2uP9uLWdIHGPZnS4HJ1oKBHzrL-hNcH_XnbKhlXogPuiaKHT3u9Ca4OjL5BXxvhnptrMl1Hna_EzVS8mr7iV3gzuR7PX82ul-PFVX0zuV6UYiyul8XsuizmfJZPJpP5HGezBabXk-WVvEnH6Ww8SdPJMp2m09GrFOcln6bjaXmdz6aTZDbGhks1UmrbjIytrqRzHd5cvxqn11eK56hc-H45TY9GCPx5laTpbx0PC92ULCy_BrXvA0-azO-v7A2JZXlXuWQ2VoSh40BeehW-jT4RPL-HeCpzigYyarjeIdsNAcqi61Q4Dz3fIWP4dFedVTe_cxpLWvQ_rLXmc4hA6zB3l6TrMP3_DwAA__-zBn6v">