[gold patch] RFC: Add extra note when 'vtable for C' is undefined

Cary Coutant ccoutant@google.com
Tue May 21 18:57:00 GMT 2013


We keep getting complaints when a class is missing its key function,
and all the linker can do is complain about an "undefined reference to
'vtable for C'" (see, e.g., GCC PR 42540). This simple patch just
prints another line after the undefined reference error, explaining
"the vtable symbol may be undefined because the class is missing its
key function".

I'd like to extend this patch eventually to look for the DWARF info
for the class and use that to identify the key function. If the GCC
change that Mark Mitchell suggests in PR 42540 is ever implemented, we
may be able to do something simpler than that.

Ian, I'm doing a simple check for "_ZTV" here -- for a bit of extra
portability, I could also demangle the symbol name into components and
look for DEMANGLE_COMPONENT_VTABLE, but it just didn't seem worth it.
Also, I could have put the check in gold_undefined_symbol_at_location,
or in Errors::undefined_symbol. Do you have any preference?

-cary


2013-05-21  Cary Coutant  <ccoutant@google.com>

gold/
        * symtab.h (Symbol::is_cxx_vtable): New function.
        * target-reloc.h (relocate_section): Check for vtable symbol.
        * testsuite/Makefile.am (missing_key_func.sh): New test case.
        * testsuite/Makefile.in: Regenerate.
        * testsuite/missing_key_func.cc: New test source.
        * testsuite/missing_key_func.sh: New test script.
-------------- next part --------------
2013-05-21  Cary Coutant  <ccoutant@google.com>

gold/
	* symtab.h (Symbol::is_cxx_vtable): New function.
	* target-reloc.h (relocate_section): Check for vtable symbol.
	* testsuite/Makefile.am (missing_key_func.sh): New test case.
	* testsuite/Makefile.in: Regenerate.
	* testsuite/missing_key_func.cc: New test source.
	* testsuite/missing_key_func.sh: New test script.

diff --git a/gold/symtab.h b/gold/symtab.h
index 689d99f..9299ea8 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -817,6 +817,11 @@ class Symbol
   is_predefined() const
   { return this->is_predefined_; }
 
+  // Return true if this is a C++ vtable symbol.
+  bool
+  is_cxx_vtable() const
+  { return is_prefix_of("_ZTV", this->name_); }
+
  protected:
   // Instances of this class should always be created at a specific
   // size.
diff --git a/gold/target-reloc.h b/gold/target-reloc.h
index cf5e389..b544c78 100644
--- a/gold/target-reloc.h
+++ b/gold/target-reloc.h
@@ -411,7 +411,13 @@ relocate_section(
 	}
 
       if (issue_undefined_symbol_error(sym))
-	gold_undefined_symbol_at_location(sym, relinfo, i, offset);
+	{
+	  gold_undefined_symbol_at_location(sym, relinfo, i, offset);
+	  if (sym->is_cxx_vtable())
+	    gold_info(_("%s: the vtable symbol may be undefined because "
+			"the class is missing its key function"),
+		      program_name);
+	}
       else if (sym != NULL
 	       && sym->visibility() != elfcpp::STV_DEFAULT
 	       && (sym->is_undefined() || sym->is_from_dynobj()))
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 785adab..4936e14 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -974,6 +974,20 @@ debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o gcctestdir/ld
 	  exit 1; \
 	fi
 
+# Test error message when a vtable is undefined.
+check_SCRIPTS += missing_key_func.sh
+check_DATA += missing_key_func.err
+MOSTLYCLEANFILES += missing_key_func.err
+missing_key_func.o: missing_key_func.cc
+	$(CXXCOMPILE) -O0 -g -c -o $@ $(srcdir)/missing_key_func.cc
+missing_key_func.err: missing_key_func.o gcctestdir/ld
+	@echo $(CXXLINK) -Bgcctestdir/ -o missing_key_func missing_key_func.o "2>$@"
+	@if $(CXXLINK) -Bgcctestdir/ -o missing_key_func missing_key_func.o 2>$@; \
+	then \
+	  echo 1>&2 "Link of missing_key_func should have failed"; \
+	  rm -f $@; \
+	  exit 1; \
+	fi
 
 if HAVE_ZLIB
 
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index 1e00b15..495b7d0 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -69,6 +69,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 
 # Test --detect-odr-violations
 
+# Test error message when a vtable is undefined.
+
 # Similar to --detect-odr-violations: check for undefined symbols in .so's
 
 # Test --dynamic-list, --dynamic-list-data, --dynamic-list-cpp-new,
@@ -87,11 +89,11 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	icf_sht_rel_addend_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	merge_string_literals.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	two_file_shared.sh weak_plt.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	debug_msg.sh undef_symbol.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_1.sh ver_test_2.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_4.sh ver_test_5.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_7.sh ver_test_10.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	relro_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	debug_msg.sh missing_key_func.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	undef_symbol.sh ver_test_1.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_2.sh ver_test_4.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_5.sh ver_test_7.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_10.sh relro_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_matching_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_3.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_4.sh \
@@ -122,7 +124,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	icf_sht_rel_addend_test.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	merge_string_literals.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	two_file_shared.dbg \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	weak_plt_shared.so debug_msg.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	weak_plt_shared.so debug_msg.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	missing_key_func.err
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = incremental_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	incremental_test.cmdline \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	gc_comdat_test gc_tls_test \
@@ -225,7 +228,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	many_sections_check.h
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_26 = many_sections_define.h \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	many_sections_check.h \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	debug_msg.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	debug_msg.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	missing_key_func.err
 @GCC_FALSE@initpri1_DEPENDENCIES =
 @NATIVE_LINKER_FALSE@initpri1_DEPENDENCIES =
 @GCC_FALSE@initpri2_DEPENDENCIES =
@@ -3767,6 +3771,8 @@ weak_plt.sh.log: weak_plt.sh
 	@p='weak_plt.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 debug_msg.sh.log: debug_msg.sh
 	@p='debug_msg.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+missing_key_func.sh.log: missing_key_func.sh
+	@p='missing_key_func.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 undef_symbol.sh.log: undef_symbol.sh
 	@p='undef_symbol.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 ver_test_1.sh.log: ver_test_1.sh
@@ -4663,6 +4669,16 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	  rm -f $@; \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	  exit 1; \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	fi
+@GCC_TRUE@@NATIVE_LINKER_TRUE@missing_key_func.o: missing_key_func.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXCOMPILE) -O0 -g -c -o $@ $(srcdir)/missing_key_func.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@missing_key_func.err: missing_key_func.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	@echo $(CXXLINK) -Bgcctestdir/ -o missing_key_func missing_key_func.o "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	@if $(CXXLINK) -Bgcctestdir/ -o missing_key_func missing_key_func.o 2>$@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	  echo 1>&2 "Link of missing_key_func should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	  rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	  exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	fi
 @GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@debug_msg_cdebug.o: debug_msg.cc gcctestdir/as
 @GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@	$(CXXCOMPILE) -Bgcctestdir/ -O0 -g -Wa,--compress-debug-sections -c -w -o $@ $(srcdir)/debug_msg.cc
 @GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@odr_violation1_cdebug.o: odr_violation1.cc gcctestdir/as
diff --git a/gold/testsuite/missing_key_func.cc b/gold/testsuite/missing_key_func.cc
new file mode 100644
index 0000000..5a5b7d9
--- /dev/null
+++ b/gold/testsuite/missing_key_func.cc
@@ -0,0 +1,46 @@
+// basic_test.cc -- a test case for gold
+
+// Copyright 2013 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// Define a class, but leave its key function undefined.
+
+class C
+{
+ public:
+  C() : c(1) { }
+  virtual void set();
+  virtual void clear();
+  int c;
+};
+
+void
+C::clear()
+{
+  c = 0;
+}
+
+int
+main()
+{
+  C c;
+  c.clear();
+  return c.c;
+}
diff --git a/gold/testsuite/missing_key_func.sh b/gold/testsuite/missing_key_func.sh
new file mode 100755
index 0000000..54c7b57
--- /dev/null
+++ b/gold/testsuite/missing_key_func.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# missing_key_func.sh -- a test case for printing error messages when
+# a class is missing its key function.
+
+# Copyright 2013 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This file goes with debug_msg.cc, a C++ source file constructed to
+# have undefined references.  We compile that file with debug
+# information and then try to link it, and make sure the proper errors
+# are displayed.  The errors will be found in debug_msg.err.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+	echo "Did not find expected error in $1:"
+	echo "   $2"
+	echo ""
+	echo "Actual error output below:"
+	cat "$1"
+	exit 1
+    fi
+}
+
+check_missing()
+{
+    if grep -q "$2" "$1"
+    then
+	echo "Found unexpected error in $1:"
+	echo "   $2"
+	echo ""
+	echo "Actual error output below:"
+	cat "$1"
+	exit 1
+    fi
+}
+
+check missing_key_func.err "error: undefined reference to 'vtable for C'"
+check missing_key_func.err "class is missing its key function"


More information about the Binutils mailing list