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>
This commit is contained in:
parent
7c6008e75d
commit
b83f01d005
3 changed files with 94 additions and 1 deletions
|
@ -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);
|
||||
|
||||
|
|
63
libstdc++-v3/testsuite/18_support/105387.cc
Normal file
63
libstdc++-v3/testsuite/18_support/105387.cc
Normal file
|
@ -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;
|
||||
}
|
25
libstdc++-v3/testsuite/18_support/105387_memptr.cc
Normal file
25
libstdc++-v3/testsuite/18_support/105387_memptr.cc
Normal file
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue