diff options
author | Jakob Hasse <0xjakob@users.noreply.github.com> | 2022-04-26 12:03:47 +0800 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2022-11-05 14:03:08 +0000 |
commit | b83f01d0057578ebc1785f858fbfd46cdc210560 (patch) | |
tree | 8c24796d5e642fb83dd49271cb7b29f76329b5f1 /libstdc++-v3 | |
parent | 7c6008e75df80607f8104e665e0448a0a9cbf85a (diff) | |
download | gcc-b83f01d0057578ebc1785f858fbfd46cdc210560.zip gcc-b83f01d0057578ebc1785f858fbfd46cdc210560.tar.gz gcc-b83f01d0057578ebc1785f858fbfd46cdc210560.tar.bz2 |
libstdc++: fix pointer type exception catch (no RTTI) [PR105387]
__pbase_type_info::__do_catch(), used to catch pointer type exceptions,
did not check if the type info object to compare against is a pointer
type info object before doing a static down-cast to a pointer type info
object. If RTTI is disabled, this leads to the following situation:
Since a pointer type info object has additional fields, they would
end up being undefined if the actual type info object was not a pointer
type info object.
A simple check has been added before the down-cast happens.
Note that a consequence of this check is that exceptions of type
pointer-to-member cannot be caught anymore.
In case RTTI is enabled, this does not seem to be a problem because
RTTI-based checks would run before and prevent running into the bad
down-cast. Hence, the fix is disabled if RTTI is enabled and exceptions
of type pointer-to-member can still be caught.
libstdc++-v3/ChangeLog:
PR libstdc++/105387
* libsupc++/pbase_type_info.cc (__do_catch) [!__cpp_rtti]: Add
check that the thrown type is actually a pointer.
* testsuite/18_support/105387.cc: New test.
* testsuite/18_support/105387_memptr.cc: New test.
Signed-off-by: Jakob Hasse <jakob.hasse@espressif.com>
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/libsupc++/pbase_type_info.cc | 7 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/18_support/105387.cc | 63 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/18_support/105387_memptr.cc | 25 |
3 files changed, 94 insertions, 1 deletions
diff --git a/libstdc++-v3/libsupc++/pbase_type_info.cc b/libstdc++-v3/libsupc++/pbase_type_info.cc index 7e5720b..934e049 100644 --- a/libstdc++-v3/libsupc++/pbase_type_info.cc +++ b/libstdc++-v3/libsupc++/pbase_type_info.cc @@ -74,7 +74,12 @@ __do_catch (const type_info *thr_type, // Therefore there must at least be a qualification conversion involved // But for that to be valid, our outer pointers must be const qualified. return false; - + +#if !__cpp_rtti + if (!thr_type->__is_pointer_p ()) + return false; +#endif + const __pbase_type_info *thrown_type = static_cast <const __pbase_type_info *> (thr_type); diff --git a/libstdc++-v3/testsuite/18_support/105387.cc b/libstdc++-v3/testsuite/18_support/105387.cc new file mode 100644 index 0000000..c4a2345 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/105387.cc @@ -0,0 +1,63 @@ +// { dg-do run } + +#include <stdexcept> +#include <cxxabi.h> +#include <testsuite_hooks.h> + +// Test cases for PR libstdc++/105387 + +// This test is to trigger undefined behavior if the bug 105387 is present +// in the code. Note, however, given that the bug is present, this test runs +// into undefined behavior which can also mean that it passes. +// It has been observed to fail quite reliably on x86_64-linux-gnu but only +// fail sporadically on Xtensa, depending on the code placement. +void portable_test() +{ + bool exception_thrown = false; + try { + throw std::runtime_error("test"); + } catch (const char *e) { + VERIFY(false); + } catch (const std::exception &e) { + exception_thrown = true; + } + VERIFY(exception_thrown); +} + +// This test relies on the types defined in the files typeinfo and cxxabi.h +// It is therefore less portable then the test case above but should be +// guaranteed to fail if the implementation has the bug 105387. +// +// This test case checks that __pbase_type_info::__do_catch() behaves +// correctly when called with a non-pointer type info object as argument. +// In particular, __pbase_type_info::__do_catch() should not cast +// the given type object into a pointer type and try to access the +// extended fields. + +void non_portable_test() +{ + // Create a zero-initialized buffer for allocation of the type object + unsigned char buffer [sizeof(__cxxabiv1::__fundamental_type_info) * 2] = {}; + + // Use placement-new to create the fundamental type info object in the + // first half of the buffer. Whenever that type info object will be + // casted to a pointer type info object, the extended fields of the + // pointer type info object will be in the second half of the buffer + // and hence be guaranteed zero. + __cxxabiv1::__fundamental_type_info *p_fund_info + = new(buffer) __cxxabiv1::__fundamental_type_info("fund_type"); + + __cxxabiv1::__pointer_type_info ptr_info("ptr_type", 0, p_fund_info); + + // __do_catch is declared protected in __pointer_type_info, but public in + // type_info, so we upcast it here + std::type_info *abstract_ptr_info = static_cast<std::type_info*>(&ptr_info); + VERIFY(abstract_ptr_info->__do_catch(p_fund_info, 0, 1) == false); +} + +int main() +{ + portable_test(); + non_portable_test(); + return 0; +} diff --git a/libstdc++-v3/testsuite/18_support/105387_memptr.cc b/libstdc++-v3/testsuite/18_support/105387_memptr.cc new file mode 100644 index 0000000..f5612f4 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/105387_memptr.cc @@ -0,0 +1,25 @@ +#include <testsuite_hooks.h> + +// Test related to PR libstdc++/105387 +// Check that pointer-to-member type exceptions can still be caught with -frtti. +// { dg-require-effective-target rtti } + +void test_catch_ptr_to_member() +{ + bool exception_thrown = false; + struct X { int i; }; + try { + throw &X::i; + } + catch (const int X::*) { + exception_thrown = true; + } + + VERIFY(exception_thrown); +} + +int main() +{ + test_catch_ptr_to_member(); + return 0; +} |