diff mbox

[3/3] mangler/demangler dogfooding

Message ID 1401191856-27585-4-git-send-email-palves@redhat.com
State New
Headers show

Commit Message

Pedro Alves May 27, 2014, 11:57 a.m. UTC
This patch teaches g++ to try to demangle any symbol it
generates/mangles, when checking is enabled in the build, as soon as
the symbol is mangled.  The idea here is validate the demangling as
close as possible to the generator as possible.

This allows catching demangler bugs/crashes much earlier in the cycle,
when building libstdc++ and friends, when running g++'s testsuite, and
even potentially earlier than that, when developers work on new
C++11/14-and-beyond features, which influence mangling, validating
against some random test that's not in the testsuite yet (and
sometimes doesn't make it there either), rather than much later in
production when the user is trying to debug the code, or the program
tries to generate a backtrace.  Both libstdc++ and the testsuite
include a good set of tricky symbols to demangle, and the latter
naturally includes all sort of random, weird, code full of corner
cases.  And, I assume g++ maintainers once in a while run WIP g++
through some piles of very complicated C++ code.

It seems clear to me that ideally we should be able to do

 assert (demangle (mangle (symbol));

But, unfortunately, we can't yet.  I built g++ and ran the testsuite
with a variant of this patch that would print the mangled symbol if
the demangling fails, but would otherwise continue without aborting,
and I found out that:

- we can't demangle ~40 symbols generated while building libstdc++
  and friends.  E.g.:

  _ZN9__gnu_cxx13new_allocatorINSt13__future_base13_State_baseV2EE9constructIS2_IEEEvPT_DpOT0_
  _ZNSt15_Sp_counted_ptrIDnLN9__gnu_cxx12_Lock_policyE1EEC1ERKS3_

- we can't demangle around ~2600 (!) symbols generated while running the g++ testsuite.  E.g.,

  _Z1f1SIXadL3FooEEE
  _ZZ4mainENKUlRT_E_clI1SEEDaS0_

Of course, these all may well be mangler bugs rather than demangler
bugs.  It's possible that these are already known mangler bugs even,
that have been fixed, but require a higher -fabi-version=X.  I didn't
investigate that.

Bootstrapped and regtested on x86_64 Fedora 20.

gcc/
2014-05-27  Pedro Alves  <palves@redhat.com>

	* cp/mangle.c: Include demangle.h.
	(finish_mangling_internal) [ENABLE_CHECKING]: Demangle the just
	mangled symbol.
---
 gcc/cp/mangle.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

Comments

Mike Stump May 27, 2014, 6:16 p.m. UTC | #1
On May 27, 2014, at 4:57 AM, Pedro Alves <palves@redhat.com> wrote:
> This patch teaches g++ to try to demangle any symbol it
> generates/mangles, when checking is enabled in the build

I like this strategy.  :-)
diff mbox

Patch

diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 4205fec..c4eb5dc 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -58,6 +58,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "cgraph.h"
 #include "wide-int.h"
+#include "demangle.h"
 
 /* Debugging support.  */
 
@@ -3367,6 +3368,35 @@  finish_mangling_internal (const bool warn)
 
   /* Null-terminate the string.  */
   write_char ('\0');
+
+#if ENABLE_CHECKING
+  /* Make sure we can demangle what we just generated.  */
+  {
+    const char *str ATTRIBUTE_UNUSED;
+    const char *mangled_str;
+    int dmgl_opts;
+
+    dmgl_opts = (DMGL_VERBOSE
+		 | DMGL_ANSI
+		 | DMGL_GNU_V3
+		 | DMGL_RET_POSTFIX
+		 | DMGL_PARAMS);
+
+    mangled_str = (const char *) obstack_base (mangle_obstack);
+    str = cplus_demangle_v3 (mangled_str, dmgl_opts);
+#if 0
+    /* XXX The above catches potential demangler crashes.  And,
+       ideally, we'd also abort if demangling fails.  However, we
+       can't do that because the demangler isn't able to demangle all
+       symbols we generate by default.  Some failures might be
+       demangler bugs, others unknown mangler bugs, and others known
+       mangler bugs fixed with a higher -fabi-version, which the
+       demangler doesn't have a workaround for.  */
+    if ((str != NULL) != (mangled_str[0] == '_' && mangled_str[1] == 'Z'))
+      internal_error ("demangling failed for: %s", mangled_str);
+#endif
+  }
+#endif
 }