[cfe-dev] [libc++] debug mode

Howard Hinnant hhinnant at apple.com
Wed Sep 14 11:35:32 PDT 2011


A few years back, prior to the open sourcing of libc++, I attempted to create a debug mode.  That first effort had a little bit of good work in it, but was basically still-born.  It is defined under _LIBCPP_DEBUG and doesn't even compile today.

Lately I've been working on a new debug mode.  It is currently defined under _LIBCPP_DEBUG2.  The plan is that if this experiment is successful, then _LIBCPP_DEBUG2 will be renamed to _LIBCPP_DEBUG, and the original _LIBCPP_DEBUG will either be integrated, or it will disappear.

The initial check-in for _LIBCPP_DEBUG2 was committed revision 139711.

There isn't a lot there yet.  I've tried to get vector working (just the primary, not vector<bool> so far), and I believe I have done so.  Though I don't have tests for it yet (I've just been spot checking).  At this point I'm simply exploring whether the basic design is viable or not.

A major goal of the design of this debug mode is to keep the ABI stable as debug mode is turned on/off.  This would enable clients to turn debug mode on/off on a translation unit basis, and not have to worry whether data structures such as vector which are visible across translation units are the debug version or not.  To achieve this, all debug data which typically relates iterators to their containers (and vice-versa) is stored in an external, global database.  This database is initially empty and compiled into libc++.dylib unconditionally.  But it is only referenced when _LIBCPP_DEBUG2 is defined by the client.

The database is currently protected by a mutex.  However it is currently set up such that it would be easy to switch to a shared_mutex should testing reveal that this would offer a performance benefit.

Every time a container is constructed (just vector so far), then the address of the container is added to the database.  When the container is destructed it is removed from the database.  And every time an iterator is constructed within a container, then the address of the iterator is added to the database.  Additionally the information of which container the iterator references is also stored in the database.  The database can be searched either by iterator address, or by container address.  And given a container entry, all iterators which reference the container can be enumerated.  And given an iterator entry, which container it references (if any) can be queried.

The database is a custom hash table.

So far everything is quite immature.  I've only added API to the database as has become necessary to add debug mode to vector.  I don't expect this API to remain stable during the development of debug mode.  I do expect the API to remain as small as possible, and to only address the needs of libc++.  I don't expect clients to be able to plug their own containers into the libc++ debug mode database (at least I don't view that as a primary goal).

In addition to the database, there is an assert-like macro:

    _LIBCPP_ASSERT(true/false, "message");

I decided not to use assert itself as preliminary clients advised me that they would like to turn libc++ debug mode on/off independently of NDEBUG.

Suggestions concerning debug mode and/or contributions are welcome.

Howard




More information about the cfe-dev mailing list