[libcxx-dev] How do _LIBCPP_DEBUG=1 "debug iterators" ever work, when linking against libc++.a?

Louis Dionne via libcxx-dev libcxx-dev at lists.llvm.org
Wed Jun 9 08:38:52 PDT 2021


Thanks for bumping and bringing this back to my attention, Arthur.

So the short answer for "how was this ever supposed to work" is "I'm not sure, that was before my time".
However, I think it was originally believed that by not using the extern template instantiations in the library
when the debug mode is enabled (see logic in __config), we would basically be using definitions from the
headers only, which would see the _LIBCPP_DEBUG=X passed by the user, and correctly register whatever
iterators needed to be registered.

I suspect that as time went by and nobody used the feature, support for it declined and eventually things
stopped working sanely. I believe you could probably fix the proximate.pass.cpp test by putting the right
set of functions in the headers (as inlines), and only using the version in the library when the debug mode
isn't in effect. However, that is very brittle IMO.

I also do know there's been some gripes about the debug mode ever since I started getting involved in
libc++, and I also do know that Apple has never shipped the debug mode. And when I say Apple has
never shipped the debug mode, I mean it has never shipped a library that even contained support for
the debug mode - so if you were to try enabling it while linking against the system library, you would
get linker errors like:

    Undefined symbols for architecture x86_64:
      "std::__1::__libcpp_db::__find_c_from_i(void*) const"

I can't speak for other vendors, but I would assume most have been shipping support for the debug
mode (i.e. the iterator database). However, I strongly suspect no user has ever tried using it seriously
(I would love to hear about it if I'm wrong).

So, to summarize, it looks like we've got a debug mode with a usage story that doesn't work. What do we do?
I see a couple options:

1. We make the debug mode a configure-time setting that vendors can use to control whether the debug mode
    is enabled for the flavor of libc++ that they build. Users can't control that. Then, if a vendor is interested in
    shipping it, they can start shipping a version of the library with the debug mode enabled, and add a nice
    compiler option that causes Clang to link against the debug-enabled libc++ instead of the normal libc++.
    Or something along those lines.

2. We try to tweak the debug mode with the current usage model such that it passes our test suite. As Arthur
    nicely explained though, that means we'll be walking in a minefield since any function compiled into the library
    will not be registering its iterators, so if they leak anywhere where the debug mode is enabled, BOOM. CI might
    be enough to catch this, but that sounds brittle to me.

3. Eric Fiselier (CC'd) had once told me about a debug mode design he'd thought about based on ASAN (I think) that
    did not require a separate build of the library. This might be a viable path forward too, and we could investigate it
    if we have more information.

4. We rip out support for the debug mode entirely since it has very few serious users (I know of some, but not many).

Personally, I think having a debug mode is something useful, so I would rather see us fix it than get rid of it.
Unless someone else can provide additional context around how the debug mode was originally supposed to
work, I would strongly go for (1) or (3), but not (2). Solutions (1) and (3) are the ones that will empower vendors
to do what's right for their users most easily, at least from my perspective. If we go for (2), unless I misunderstand
something fundamental, I don't think we'll ever be able to get the debug mode to a point where it is sufficiently solid
so that vendors are able to ship it.

If we go for (1), I can lay out the steps to get us there (and do some of them). I've already thought about it some.
Eric, do you have an opinion? Would you like to expand on (3)?

Louis


> On Jun 9, 2021, at 10:24, Arthur O'Dwyer <arthur.j.odwyer at gmail.com> wrote:
> 
> Bump again, since this just came up AGAIN in Louis's https://reviews.llvm.org/D103960 <https://reviews.llvm.org/D103960>
> On Sat, May 29, 2021 at 1:00 PM Mark de Wever <koraq at xs4all.nl <mailto:koraq at xs4all.nl>> wrote:
> On Sat, May 08, 2021 at 04:49:20PM -0400, Arthur O'Dwyer via libcxx-dev wrote:
> > Gentle bump.
> >
> > Quoting myself for emphasis:
> > >
> > > The problem seems to be that
> > > (1) libc++.a needs to copy strings sometimes, so it contains codegen for
> > the copy constructor
> > > (2) libc++.a is compiled with -D_LIBCPP_DEBUG=0, i.e., assertions but no
> > debug iterators
> > > (3) Therefore any strings created by the copy constructor inside
> > libc++.a, don't get registered with the debug-iterators library
> > > (4) Therefore pretty much everything is affected by unpredictable
> > assert-fails??
> > >
> > > The real question is, how was this ever *supposed* to work?
> 
> It seems the issue also happens with strings returned from
> std::to_string. This function is implemented in src/string.cpp.
> I ran into it a while ago while implementing the std::formatter stubs.
> 
> (I actually forgot about this issue, but Arthur reminded me.)
> 
> To me it seems unintentional and unwanted. But I don't have a suggestion
> how to fix it.
> 
> Cheers,
> Mark de Wever

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/libcxx-dev/attachments/20210609/ca86326f/attachment.html>


More information about the libcxx-dev mailing list