Bug 175453 - Catching C++ std::bad_cast doesn't work in FreeBSD 9.1
Summary: Catching C++ std::bad_cast doesn't work in FreeBSD 9.1
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: standards (show other bugs)
Version: 9.1-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-standards (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-01-20 17:00 UTC by Hongli Lai
Modified: 2014-06-06 08:05 UTC (History)
1 user (show)

See Also:


Attachments
file.txt (445 bytes, text/plain)
2013-01-20 17:00 UTC, Hongli Lai
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Hongli Lai 2013-01-20 17:00:00 UTC
C++ code is not able to catch std::bad_cast exceptions, even though it should. If a dynamic_cast is within a try-catch block, then that block fails to catch std::bad_cast, and the program crashes with an uncaught exception as a result.

I've attached a reproducible test case. You can also find it at http://forums.freebsd.org/showthread.php?p=205804#post205804 and http://stackoverflow.com/questions/14413703/why-does-catching-stdbad-cast-not-work-on-freebsd-9. The code is compiled with the following GCC version:

$ gcc -v
Using built-in specs.
Target: amd64-undermydesk-freebsd
Configured with: FreeBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070831 patched [FreeBSD]

FreeBSD 9.1 seems to be the only platform on which this bug appears. The code works as expected on Linux and OS X. According to a commenter, FreeBSD 9.0 works as expected too. According to another commenter the code fails on FreeBSD 9.1 with Clang too.

Fix: Patch attached with submission follows:
How-To-Repeat: See attached C++ program.
Comment 1 Eitan Adler freebsd_committer freebsd_triage 2013-01-26 17:07:14 UTC
This bug is probably well understood by now, but here is a minimal
testcase for it (no includes, as few C++ features as possible):

 extern "C++" {
    namespace std {
      class exception   {
          const char* name() const     {
   }
     };
           class bad_cast : public exception   {
     };
   }
      }
      class foo {
   public:     virtual ~foo() {
  }
   };
       class bar: public foo {
   public:     int val;
       bar(): val(123) {
  }
   };
       static void cast_test(const foo &f) {
       try {
           const bar &b = dynamic_cast<const bar &>(f);
       }
   catch (const std::bad_cast &) {
       }
   }
       int main() {
       foo f;
       cast_test(f);
   }


-- 
Eitan Adler
Comment 2 dfilter service freebsd_committer freebsd_triage 2013-01-28 11:13:35 UTC
Author: theraven
Date: Mon Jan 28 11:12:49 2013
New Revision: 246028
URL: http://svnweb.freebsd.org/changeset/base/246028

Log:
  Fix some symbol version mismatches between libstdc++ and libsupc++/libcxxrt
  that were causing the runtime and STL libraries to see different versions of
  various classes and functions when libstdc++ is used as a filter.
  
  Note: This changes the ABI for libcxxrt, but libcxxrt is currently only in
  -STABLE for testing and is not used by anything unless explicitly enabled by
  the end user.  No default compiler configurations use it.
  
  libc++ will need to be recompiled after this change.  make buildworld will do
  this automatically, but make in lib/libc++ will not necessarily work unless the
  new libcxxrt is installed first.
  
  PR:		kern/171610, stand/175453
  Reviewed by:	kib
  MFC after:	1 week

Modified:
  head/gnu/lib/libsupc++/Version.map
  head/lib/libcxxrt/Version.map

Modified: head/gnu/lib/libsupc++/Version.map
==============================================================================
--- head/gnu/lib/libsupc++/Version.map	Mon Jan 28 10:52:24 2013	(r246027)
+++ head/gnu/lib/libsupc++/Version.map	Mon Jan 28 11:12:49 2013	(r246028)
@@ -142,8 +142,37 @@ GLIBCXX_3.4 {
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
     _ZdlPvRKSt9nothrow_t;
+    extern "C++" {
+      std::set_new_handler*;
+      std::set_terminate*;
+      std::set_unexpected*;
+
+      std::bad_alloc;
+      std::bad_cast;
+      std::exception*;
+
+      "typeinfo for std::bad_alloc";
+      "typeinfo for std::bad_cast";
+      "typeinfo for std::exception";
+
+      "typeinfo name for std::bad_alloc";
+      "typeinfo name for std::bad_cast";
+      "typeinfo name for std::exception";
+
+      "vtable for std::bad_alloc";
+      "vtable for std::bad_cast";
+      "vtable for std::exception";
+    };
 };
 
+GLIBCXX_3.4.9 {
+    extern "C++" {
+        "std::bad_alloc::what() const";
+        "std::bad_cast::what() const";
+        "std::bad_typeid::what() const";
+    };
+} GLIBCXX_3.4;
+
 CXXABI_1.3.1 {
 
     __cxa_get_exception_ptr;

Modified: head/lib/libcxxrt/Version.map
==============================================================================
--- head/lib/libcxxrt/Version.map	Mon Jan 28 10:52:24 2013	(r246027)
+++ head/lib/libcxxrt/Version.map	Mon Jan 28 11:12:49 2013	(r246028)
@@ -209,18 +209,7 @@ CXXABI_1.3 {
 
         "std::type_info::type_info(std::type_info const&)";
         "std::type_info::type_info(std::type_info const&)";
-        "std::type_info::~type_info()";
-        "std::type_info::~type_info()";
-        "std::type_info::~type_info()";
         "std::type_info::operator=(std::type_info const&)";
-        "std::unexpected()";
-        "std::get_terminate()";
-        "std::set_terminate(void (*)())";
-        "std::get_unexpected()";
-        "std::set_unexpected(void (*)())";
-        "std::set_new_handler(void (*)())";
-        "std::uncaught_exception()";
-        "std::terminate()";
 
 
         # Extensions
@@ -243,67 +232,22 @@ CXXABI_1.3.1 {
 CXXRT_1.0 {
 
     extern "C++" {
-        "std::bad_cast::what() const";
-        "std::bad_typeid::what() const";
-        "std::bad_alloc::what() const";
-        "std::exception::what() const";
         "std::type_info::name() const";
         "std::type_info::before(std::type_info const&) const";
         "std::type_info::operator==(std::type_info const&) const";
         "std::type_info::operator!=(std::type_info const&) const";
-        "std::bad_typeid::bad_typeid(std::bad_typeid const&)";
-        "std::bad_typeid::bad_typeid()";
-        "std::bad_typeid::bad_typeid(std::bad_typeid const&)";
-        "std::bad_typeid::bad_typeid()";
-        "std::bad_typeid::~bad_typeid()";
-        "std::bad_typeid::~bad_typeid()";
-        "std::bad_typeid::~bad_typeid()";
-        "std::bad_typeid::operator=(std::bad_typeid const&)";
         "std::bad_cast::bad_cast(std::bad_cast const&)";
         "std::bad_cast::bad_cast()";
         "std::bad_cast::bad_cast(std::bad_cast const&)";
         "std::bad_cast::bad_cast()";
-        "std::bad_cast::~bad_cast()";
-        "std::bad_cast::~bad_cast()";
-        "std::bad_cast::~bad_cast()";
         "std::bad_cast::operator=(std::bad_cast const&)";
-        "std::bad_alloc::bad_alloc(std::bad_alloc const&)";
-        "std::bad_alloc::bad_alloc()";
-        "std::bad_alloc::bad_alloc(std::bad_alloc const&)";
-        "std::bad_alloc::bad_alloc()";
-        "std::bad_alloc::~bad_alloc()";
-        "std::bad_alloc::~bad_alloc()";
-        "std::bad_alloc::~bad_alloc()";
-        "std::bad_alloc::operator=(std::bad_alloc const&)";
         "std::exception::exception(std::exception const&)";
         "std::exception::exception()";
         "std::exception::exception(std::exception const&)";
         "std::exception::exception()";
-        "std::exception::~exception()";
-        "std::exception::~exception()";
-        "std::exception::~exception()";
         "std::exception::operator=(std::exception const&)";
 
 
-        "vtable for std::bad_typeid";
-        "vtable for std::bad_cast";
-        "vtable for std::bad_alloc";
-        "vtable for std::exception";
-        "vtable for std::type_info";
-        "typeinfo for std::bad_typeid";
-        "typeinfo for std::bad_cast";
-        "typeinfo for std::bad_alloc";
-        "typeinfo for std::exception";
-        "typeinfo for std::type_info";
-        "typeinfo name for std::bad_typeid";
-        "typeinfo name for std::bad_cast";
-        "typeinfo name for std::bad_alloc";
-        "typeinfo name for std::exception";
-        "typeinfo name for std::type_info";
-
-        "std::type_info::__is_function_p() const";
-        "std::type_info::__do_upcast(__cxxabiv1::__class_type_info const*, void**) const";
-        "std::type_info::__is_pointer_p() const";
 
 
 
@@ -317,6 +261,7 @@ CXXRT_1.0 {
 
 } CXXABI_1.3.1;
 
+
 GLIBCXX_3.4 {
     extern "C++" {
         "operator delete[](void*)";
@@ -327,5 +272,50 @@ GLIBCXX_3.4 {
         "operator new[](unsigned long)";
         "operator new(unsigned long)";
         "operator new(unsigned long, std::nothrow_t const&)";
+
+        "std::unexpected()";
+        "std::get_terminate()";
+        "std::get_unexpected()";
+        "std::uncaught_exception()";
+        "std::terminate()";
+
+        "std::type_info::~type_info()";
+        "std::bad_cast::~bad_cast()";
+        "std::exception::~exception()";
+
+        std::set_new_handler*;
+        std::set_terminate*;
+        std::set_unexpected*;
+        std::exception*;
+        std::bad_alloc;
+        std::bad_typeid;
+        std::type_info*;
+
+        "vtable for std::bad_alloc";
+        "vtable for std::bad_cast";
+        "vtable for std::bad_typeid";
+        "vtable for std::exception";
+        "vtable for std::type_info";
+
+        "typeinfo for std::bad_alloc";
+        "typeinfo for std::bad_typeid";
+        "typeinfo for std::exception";
+        "typeinfo for std::bad_cast";
+        "typeinfo for std::exception";
+        "typeinfo for std::type_info";
+        "typeinfo name for std::bad_typeid";
+        "typeinfo name for std::bad_cast";
+        "typeinfo name for std::exception";
+        "typeinfo name for std::type_info";
+
     };
 };
+
+GLIBCXX_3.4.9 {
+    extern "C++" {
+        "std::bad_typeid::what() const";
+        "std::bad_cast::what() const";
+        "std::bad_alloc::what() const";
+    };
+} GLIBCXX_3.4;
+
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 3 dfilter service freebsd_committer freebsd_triage 2013-02-05 19:11:05 UTC
Author: dim
Date: Tue Feb  5 19:10:50 2013
New Revision: 246368
URL: http://svnweb.freebsd.org/changeset/base/246368

Log:
  MFC r246028 (by theraven):
  
    Fix some symbol version mismatches between libstdc++ and libsupc++/libcxxrt
    that were causing the runtime and STL libraries to see different versions of
    various classes and functions when libstdc++ is used as a filter.
  
    Note: This changes the ABI for libcxxrt, but libcxxrt is currently only in
    -STABLE for testing and is not used by anything unless explicitly enabled by
    the end user.  No default compiler configurations use it.
  
    libc++ will need to be recompiled after this change.  make buildworld will do
    this automatically, but make in lib/libc++ will not necessarily work unless the
    new libcxxrt is installed first.
  
    PR:		kern/171610, stand/175453
    Reviewed by:	kib
  
  MFC r246297:
  
    Add several missing symbols to libcxxrt's symbol version map, and remove
    a few duplicates.  This should fix building world with -stdlib=libc++
    after r246028.
  
    Submitted by:	Yamaya Takashi <yamayan@kbh.biglobe.ne.jp>

Modified:
  stable/9/gnu/lib/libsupc++/Version.map
  stable/9/lib/libcxxrt/Version.map
Directory Properties:
  stable/9/gnu/lib/libsupc++/   (props changed)
  stable/9/lib/libcxxrt/   (props changed)

Modified: stable/9/gnu/lib/libsupc++/Version.map
==============================================================================
--- stable/9/gnu/lib/libsupc++/Version.map	Tue Feb  5 18:55:09 2013	(r246367)
+++ stable/9/gnu/lib/libsupc++/Version.map	Tue Feb  5 19:10:50 2013	(r246368)
@@ -142,8 +142,37 @@ GLIBCXX_3.4 {
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
     _ZdlPvRKSt9nothrow_t;
+    extern "C++" {
+      std::set_new_handler*;
+      std::set_terminate*;
+      std::set_unexpected*;
+
+      std::bad_alloc;
+      std::bad_cast;
+      std::exception*;
+
+      "typeinfo for std::bad_alloc";
+      "typeinfo for std::bad_cast";
+      "typeinfo for std::exception";
+
+      "typeinfo name for std::bad_alloc";
+      "typeinfo name for std::bad_cast";
+      "typeinfo name for std::exception";
+
+      "vtable for std::bad_alloc";
+      "vtable for std::bad_cast";
+      "vtable for std::exception";
+    };
 };
 
+GLIBCXX_3.4.9 {
+    extern "C++" {
+        "std::bad_alloc::what() const";
+        "std::bad_cast::what() const";
+        "std::bad_typeid::what() const";
+    };
+} GLIBCXX_3.4;
+
 CXXABI_1.3.1 {
 
     __cxa_get_exception_ptr;

Modified: stable/9/lib/libcxxrt/Version.map
==============================================================================
--- stable/9/lib/libcxxrt/Version.map	Tue Feb  5 18:55:09 2013	(r246367)
+++ stable/9/lib/libcxxrt/Version.map	Tue Feb  5 19:10:50 2013	(r246368)
@@ -208,19 +208,7 @@ CXXABI_1.3 {
         "typeinfo name for __cxxabiv1::__vmi_class_type_info";
 
         "std::type_info::type_info(std::type_info const&)";
-        "std::type_info::type_info(std::type_info const&)";
-        "std::type_info::~type_info()";
-        "std::type_info::~type_info()";
-        "std::type_info::~type_info()";
         "std::type_info::operator=(std::type_info const&)";
-        "std::unexpected()";
-        "std::get_terminate()";
-        "std::set_terminate(void (*)())";
-        "std::get_unexpected()";
-        "std::set_unexpected(void (*)())";
-        "std::set_new_handler(void (*)())";
-        "std::uncaught_exception()";
-        "std::terminate()";
 
 
         # Extensions
@@ -243,69 +231,22 @@ CXXABI_1.3.1 {
 CXXRT_1.0 {
 
     extern "C++" {
-        "std::bad_cast::what() const";
-        "std::bad_typeid::what() const";
-        "std::bad_alloc::what() const";
-        "std::exception::what() const";
         "std::type_info::name() const";
         "std::type_info::before(std::type_info const&) const";
         "std::type_info::operator==(std::type_info const&) const";
         "std::type_info::operator!=(std::type_info const&) const";
-        "std::bad_typeid::bad_typeid(std::bad_typeid const&)";
-        "std::bad_typeid::bad_typeid()";
-        "std::bad_typeid::bad_typeid(std::bad_typeid const&)";
-        "std::bad_typeid::bad_typeid()";
-        "std::bad_typeid::~bad_typeid()";
-        "std::bad_typeid::~bad_typeid()";
-        "std::bad_typeid::~bad_typeid()";
-        "std::bad_typeid::operator=(std::bad_typeid const&)";
         "std::bad_cast::bad_cast(std::bad_cast const&)";
         "std::bad_cast::bad_cast()";
-        "std::bad_cast::bad_cast(std::bad_cast const&)";
-        "std::bad_cast::bad_cast()";
-        "std::bad_cast::~bad_cast()";
-        "std::bad_cast::~bad_cast()";
-        "std::bad_cast::~bad_cast()";
         "std::bad_cast::operator=(std::bad_cast const&)";
-        "std::bad_alloc::bad_alloc(std::bad_alloc const&)";
-        "std::bad_alloc::bad_alloc()";
-        "std::bad_alloc::bad_alloc(std::bad_alloc const&)";
-        "std::bad_alloc::bad_alloc()";
-        "std::bad_alloc::~bad_alloc()";
-        "std::bad_alloc::~bad_alloc()";
-        "std::bad_alloc::~bad_alloc()";
-        "std::bad_alloc::operator=(std::bad_alloc const&)";
-        "std::exception::exception(std::exception const&)";
-        "std::exception::exception()";
+        "std::bad_typeid::bad_typeid(std::bad_typeid const&)";
+        "std::bad_typeid::bad_typeid()";
+        "std::bad_typeid::operator=(std::bad_typeid const&)";
         "std::exception::exception(std::exception const&)";
         "std::exception::exception()";
-        "std::exception::~exception()";
-        "std::exception::~exception()";
-        "std::exception::~exception()";
         "std::exception::operator=(std::exception const&)";
-
-
-        "vtable for std::bad_typeid";
-        "vtable for std::bad_cast";
-        "vtable for std::bad_alloc";
-        "vtable for std::exception";
-        "vtable for std::type_info";
-        "typeinfo for std::bad_typeid";
-        "typeinfo for std::bad_cast";
-        "typeinfo for std::bad_alloc";
-        "typeinfo for std::exception";
-        "typeinfo for std::type_info";
-        "typeinfo name for std::bad_typeid";
-        "typeinfo name for std::bad_cast";
-        "typeinfo name for std::bad_alloc";
-        "typeinfo name for std::exception";
-        "typeinfo name for std::type_info";
-
-        "std::type_info::__is_function_p() const";
-        "std::type_info::__do_upcast(__cxxabiv1::__class_type_info const*, void**) const";
-        "std::type_info::__is_pointer_p() const";
-
-
+        "std::bad_alloc::bad_alloc(std::bad_alloc const&)";
+        "std::bad_alloc::bad_alloc()";
+        "std::bad_alloc::operator=(std::bad_alloc const&)";
 
     };
     __cxa_allocate_dependent_exception;
@@ -317,6 +258,7 @@ CXXRT_1.0 {
 
 } CXXABI_1.3.1;
 
+
 GLIBCXX_3.4 {
     extern "C++" {
         "operator delete[](void*)";
@@ -327,5 +269,51 @@ GLIBCXX_3.4 {
         "operator new[](unsigned long)";
         "operator new(unsigned long)";
         "operator new(unsigned long, std::nothrow_t const&)";
+
+        "std::unexpected()";
+        "std::get_terminate()";
+        "std::get_unexpected()";
+        "std::uncaught_exception()";
+        "std::terminate()";
+
+        "std::type_info::~type_info()";
+        "std::bad_cast::~bad_cast()";
+        "std::bad_typeid::~bad_typeid()";
+        "std::exception::~exception()";
+        "std::bad_alloc::~bad_alloc()";
+
+        "std::exception::what() const";
+
+        std::set_new_handler*;
+        std::set_terminate*;
+        std::set_unexpected*;
+        std::type_info::__*;
+
+        "vtable for std::bad_alloc";
+        "vtable for std::bad_cast";
+        "vtable for std::bad_typeid";
+        "vtable for std::exception";
+        "vtable for std::type_info";
+
+        "typeinfo for std::bad_alloc";
+        "typeinfo for std::bad_typeid";
+        "typeinfo for std::bad_cast";
+        "typeinfo for std::exception";
+        "typeinfo for std::type_info";
+        "typeinfo name for std::bad_alloc";
+        "typeinfo name for std::bad_typeid";
+        "typeinfo name for std::bad_cast";
+        "typeinfo name for std::exception";
+        "typeinfo name for std::type_info";
+
     };
 };
+
+GLIBCXX_3.4.9 {
+    extern "C++" {
+        "std::bad_typeid::what() const";
+        "std::bad_cast::what() const";
+        "std::bad_alloc::what() const";
+    };
+} GLIBCXX_3.4;
+
Comment 4 wollman 2013-06-06 23:57:08 UTC
I think it would be worth adding this to the errata document for 9.1.
The patch for stable/9 applies cleanly to 9.1 and I'm working on
testing it right now.

-GAWollman
Comment 5 Garrett Wollman freebsd_committer freebsd_triage 2013-06-11 18:51:49 UTC
State Changed
From-To: open->patched

Fixed in HEAD and stable/9, will be in 9.2 release.
Comment 6 David Chisnall freebsd_committer freebsd_triage 2014-06-06 08:05:45 UTC
As per previous comment, merged to 9-STABLE prior to 9.2