From 27674ca63c662a635f3a645a28790bde40ed11ab Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 27 Mar 2015 09:33:20 +0000 Subject: [PATCH] re PR sanitizer/65583 ([UBSAN] ICE segfault in inline_edge_summary) PR sanitizer/65583 * ubsan.c (ubsan_create_edge): New function. (instrument_bool_enum_load): Call it. (instrument_nonnull_arg): Likewise. (instrument_nonnull_return): Likewise. (instrument_object_size): Likewise. * g++.dg/ubsan/pr65583.C: New test. From-SVN: r221723 --- gcc/ChangeLog | 9 ++ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/ubsan/pr65583.C | 140 +++++++++++++++++++++++++++ gcc/ubsan.c | 35 ++++++- 4 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/ubsan/pr65583.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e014dd89e32..37258ad187c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2015-03-27 Marek Polacek + + PR sanitizer/65583 + * ubsan.c (ubsan_create_edge): New function. + (instrument_bool_enum_load): Call it. + (instrument_nonnull_arg): Likewise. + (instrument_nonnull_return): Likewise. + (instrument_object_size): Likewise. + 2015-03-26 Jan Hubicka * lto-streamer.h (class lto_location_cache): Turn loc_cache into diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 135dfc03e9e..9cbe0f93570 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-03-27 Marek Polacek + + PR sanitizer/65583 + * g++.dg/ubsan/pr65583.C: New test. + 2015-03-26 Jan Hubicka * gcc.c-torture/compile/20150327.c: New testcase. diff --git a/gcc/testsuite/g++.dg/ubsan/pr65583.C b/gcc/testsuite/g++.dg/ubsan/pr65583.C new file mode 100644 index 00000000000..4e1149e9cb6 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/pr65583.C @@ -0,0 +1,140 @@ +// PR sanitizer/65583 +// { dg-do compile } +// { dg-options "-std=c++11 -fsanitize=undefined" } + +namespace std +{ + inline namespace __cxx11 + { + } + template < typename > class allocator; + template < class _CharT > struct char_traits; + namespace __cxx11 + { + template < typename _CharT, typename _Traits = + char_traits < _CharT >, typename _Alloc = + allocator < _CharT > >class basic_string; + typedef basic_string < char >string; + } +} +namespace std +{ + template < typename _Tp, _Tp __v > struct integral_constant + { + static constexpr _Tp value = __v; + }; + typedef integral_constant < bool, true > true_type; +} +namespace __gnu_cxx +{ + template < typename _Tp > class new_allocator + { + public: + typedef long unsigned size_type; + typedef _Tp value_type; + template < typename _Tp1 > struct rebind + { + typedef new_allocator < _Tp1 > other; + }; + }; +} +namespace std +{ + template < typename _Tp > using __allocator_base = + __gnu_cxx::new_allocator < _Tp >; + template < typename _Tp > class allocator:public __allocator_base < _Tp > + { + }; + template < typename _Alloc, typename _Tp > class __alloctr_rebind_helper + { + template < typename _Alloc2, typename _Tp2 > + static constexpr true_type _S_chk (typename _Alloc2::template rebind < + _Tp2 >::other *); + public: + using __type = decltype (_S_chk < _Alloc, _Tp > (nullptr)); + }; + template < typename _Alloc, typename _Tp, bool = + __alloctr_rebind_helper < _Alloc, + _Tp >::__type::value > struct __alloctr_rebind; + template < typename _Alloc, typename _Tp > struct __alloctr_rebind <_Alloc, + _Tp, true > + { + typedef typename _Alloc::template rebind < _Tp >::other __type; + }; + template < typename _Alloc > struct allocator_traits + { + typedef typename _Alloc::value_type value_type; + static value_type *_S_pointer_helper (...); + typedef decltype (_S_pointer_helper ((_Alloc *) 0)) __pointer; + typedef __pointer pointer; + template < typename _Tp > + static typename _Tp::size_type _S_size_type_helper (_Tp *); + typedef decltype (_S_size_type_helper ((_Alloc *) 0)) __size_type; + typedef __size_type size_type; + template < typename _Tp > using rebind_alloc = + typename __alloctr_rebind < _Alloc, _Tp >::__type; + }; +} +namespace __gnu_cxx +{ + template < typename _Alloc > struct __alloc_traits:std::allocator_traits < + _Alloc > + { + typedef std::allocator_traits < _Alloc > _Base_type; + template < typename _Tp > struct rebind + { + typedef typename _Base_type::template rebind_alloc < _Tp > other; + }; + }; +} +namespace std +{ + namespace __cxx11 + { + template < typename _CharT, typename _Traits, + typename _Alloc > class basic_string + { + typedef typename __gnu_cxx::__alloc_traits < _Alloc >::template rebind < + _CharT >::other _Char_alloc_type; + typedef __gnu_cxx::__alloc_traits < _Char_alloc_type > _Alloc_traits; + typedef _Char_alloc_type allocator_type; + typedef typename _Alloc_traits::size_type size_type; + typedef typename _Alloc_traits::pointer pointer; + struct _Alloc_hider:allocator_type + { + _Alloc_hider (pointer __dat, const _Alloc & __a) + { + } + }; + _Alloc_hider _M_dataplus; + union + { + size_type _M_allocated_capacity; + }; + pointer _M_local_data () + { + } + void _M_dispose () + { + _M_destroy (_M_allocated_capacity); + } + void _M_destroy (size_type __size) throw () + { + } + public: + basic_string (const _CharT * __s, const _Alloc & __a = _Alloc ()):_M_dataplus (_M_local_data (), + __a) + { + _M_dispose (); + } + }; + } + class FileHandle + { + std::string fname; + FileHandle (const char *fname); + }; + FileHandle::FileHandle (const char *fname):fname (fname) + { + } +} diff --git a/gcc/ubsan.c b/gcc/ubsan.c index 0e23d919744..b9d9f30e660 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -686,6 +686,21 @@ is_ubsan_builtin_p (tree t) "__builtin___ubsan_", 18) == 0; } +/* Create a callgraph edge for statement STMT. */ + +static void +ubsan_create_edge (gimple stmt) +{ + gcall *call_stmt = dyn_cast (stmt); + basic_block bb = gimple_bb (stmt); + int freq = compute_call_stmt_bb_frequency (current_function_decl, bb); + cgraph_node *node = cgraph_node::get (current_function_decl); + tree decl = gimple_call_fndecl (call_stmt); + if (decl) + node->create_edge (cgraph_node::get_create (decl), call_stmt, bb->count, + freq); +} + /* Expand the UBSAN_BOUNDS special builtin function. */ bool @@ -1483,6 +1498,7 @@ instrument_bool_enum_load (gimple_stmt_iterator *gsi) } gimple_set_location (g, loc); gsi_insert_before (&gsi2, g, GSI_SAME_STMT); + ubsan_create_edge (g); *gsi = gsi_for_stmt (stmt); } @@ -1670,6 +1686,7 @@ instrument_nonnull_arg (gimple_stmt_iterator *gsi) } gimple_set_location (g, loc[0]); gsi_insert_before (gsi, g, GSI_SAME_STMT); + ubsan_create_edge (g); } *gsi = gsi_for_stmt (stmt); } @@ -1722,6 +1739,7 @@ instrument_nonnull_return (gimple_stmt_iterator *gsi) } gimple_set_location (g, loc[0]); gsi_insert_before (gsi, g, GSI_SAME_STMT); + ubsan_create_edge (g); *gsi = gsi_for_stmt (stmt); } flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks; @@ -1818,6 +1836,7 @@ instrument_object_size (gimple_stmt_iterator *gsi, bool is_lhs) tree sizet; tree base_addr = base; + gimple bos_stmt = NULL; if (decl_p) base_addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (base)), base); @@ -1834,6 +1853,17 @@ instrument_object_size (gimple_stmt_iterator *gsi, bool is_lhs) integer_zero_node); sizet = force_gimple_operand_gsi (gsi, sizet, false, NULL_TREE, true, GSI_SAME_STMT); + /* If the call above didn't end up being an integer constant, go one + statement back and get the __builtin_object_size stmt. Save it, + we might need it later. */ + if (SSA_VAR_P (sizet)) + { + gsi_prev (gsi); + bos_stmt = gsi_stmt (*gsi); + + /* Move on to where we were. */ + gsi_next (gsi); + } } else return; @@ -1870,7 +1900,10 @@ instrument_object_size (gimple_stmt_iterator *gsi, bool is_lhs) } } - /* Nope. Emit the check. */ + if (bos_stmt && gimple_call_builtin_p (bos_stmt, BUILT_IN_OBJECT_SIZE)) + ubsan_create_edge (bos_stmt); + + /* We have to emit the check. */ t = force_gimple_operand_gsi (gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); ptr = force_gimple_operand_gsi (gsi, ptr, true, NULL_TREE, true, -- 2.30.2