Hi! I've backported following 5 patches to 7.x. The PR81715 one, because it could be risky, is enabled only for -fsanitize=kernel-address which it has been reported for and where it causes major issues for the kernel during sanitization.
Bootstrapped/regtested on x86_64-linux and i686-linux, committed to 7 branch. Jakub
2017-10-27 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-09-15 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/82192 * combine.c (make_extraction): Don't look through non-paradoxical SUBREGs or TRUNCATE if pos + len is or might be bigger than inner's mode. * gcc.c-torture/execute/pr82192.c: New test. --- gcc/combine.c (revision 252823) +++ gcc/combine.c (revision 252824) @@ -7442,7 +7442,14 @@ make_extraction (machine_mode mode, rtx if (pos_rtx && CONST_INT_P (pos_rtx)) pos = INTVAL (pos_rtx), pos_rtx = 0; - if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner)) + if (GET_CODE (inner) == SUBREG + && subreg_lowpart_p (inner) + && (paradoxical_subreg_p (inner) + /* If trying or potentionally trying to extract + bits outside of is_mode, don't look through + non-paradoxical SUBREGs. See PR82192. */ + || (pos_rtx == NULL_RTX + && pos + len <= GET_MODE_PRECISION (is_mode)))) { /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...), consider just the QI as the memory to extract from. @@ -7468,7 +7475,12 @@ make_extraction (machine_mode mode, rtx if (new_rtx != 0) return gen_rtx_ASHIFT (mode, new_rtx, XEXP (inner, 1)); } - else if (GET_CODE (inner) == TRUNCATE) + else if (GET_CODE (inner) == TRUNCATE + /* If trying or potentionally trying to extract + bits outside of is_mode, don't look through + TRUNCATE. See PR82192. */ + && pos_rtx == NULL_RTX + && pos + len <= GET_MODE_PRECISION (is_mode)) inner = XEXP (inner, 0); inner_mode = GET_MODE (inner); --- gcc/testsuite/gcc.c-torture/execute/pr82192.c (nonexistent) +++ gcc/testsuite/gcc.c-torture/execute/pr82192.c (revision 252824) @@ -0,0 +1,22 @@ +/* PR rtl-optimization/82192 */ + +unsigned long long int a = 0x95dd3d896f7422e2ULL; +struct S { unsigned int m : 13; } b; + +__attribute__((noinline, noclone)) void +foo (void) +{ + b.m = ((unsigned) a) >> (0x644eee9667723bf7LL + | a & ~0xdee27af8U) - 0x644eee9667763bd8LL; +} + +int +main () +{ + if (__INT_MAX__ != 0x7fffffffULL) + return 0; + foo (); + if (b.m != 0) + __builtin_abort (); + return 0; +}
2017-10-27 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-09-18 Jakub Jelinek <ja...@redhat.com> PR c/82234 * doc/extend.texi: Add @findex entry for __builtin_shuffle. --- gcc/doc/extend.texi (revision 252946) +++ gcc/doc/extend.texi (revision 252947) @@ -9683,6 +9683,7 @@ For mixed operations between a scalar @c @code{s && v} is equivalent to @code{s?v!=0:0} (the evaluation is short-circuit) and @code{v && s} is equivalent to @code{v!=0 & (s?-1:0)}. +@findex __builtin_shuffle Vector shuffling is available using functions @code{__builtin_shuffle (vec, mask)} and @code{__builtin_shuffle (vec0, vec1, mask)}.
2017-10-27 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-09-21 Jakub Jelinek <ja...@redhat.com> PR sanitizer/81715 * tree-inline.c (expand_call_inline): Emit clobber stmts for VAR_DECLs to which addressable non-volatile parameters are mapped and for id->retvar after the return value assignment, though for -fsanitize=kernel-address only. Clear id->retval and id->retbnd after inlining. * g++.dg/asan/pr81715.C: New test. --- gcc/tree-inline.c (revision 253064) +++ gcc/tree-inline.c (revision 253065) @@ -4796,6 +4796,23 @@ expand_call_inline (basic_block bb, gimp reset_debug_bindings (id, stmt_gsi); + if (flag_stack_reuse != SR_NONE + && (flag_sanitize & SANITIZE_KERNEL_ADDRESS) != 0) + for (tree p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p)) + if (!TREE_THIS_VOLATILE (p)) + { + tree *varp = id->decl_map->get (p); + if (varp && VAR_P (*varp) && !is_gimple_reg (*varp)) + { + tree clobber = build_constructor (TREE_TYPE (*varp), NULL); + gimple *clobber_stmt; + TREE_THIS_VOLATILE (clobber) = 1; + clobber_stmt = gimple_build_assign (*varp, clobber); + gimple_set_location (clobber_stmt, gimple_location (stmt)); + gsi_insert_before (&stmt_gsi, clobber_stmt, GSI_SAME_STMT); + } + } + /* Reset the escaped solution. */ if (cfun->gimple_df) pt_solution_reset (&cfun->gimple_df->escaped); @@ -4846,6 +4863,24 @@ expand_call_inline (basic_block bb, gimp stmt = gimple_build_assign (gimple_call_lhs (stmt), use_retvar); gsi_replace (&stmt_gsi, stmt, false); maybe_clean_or_replace_eh_stmt (old_stmt, stmt); + /* Append a clobber for id->retvar if easily possible. */ + if (flag_stack_reuse != SR_NONE + && (flag_sanitize & SANITIZE_KERNEL_ADDRESS) != 0 + && id->retvar + && VAR_P (id->retvar) + && id->retvar != return_slot + && id->retvar != modify_dest + && !TREE_THIS_VOLATILE (id->retvar) + && !is_gimple_reg (id->retvar) + && !stmt_ends_bb_p (stmt)) + { + tree clobber = build_constructor (TREE_TYPE (id->retvar), NULL); + gimple *clobber_stmt; + TREE_THIS_VOLATILE (clobber) = 1; + clobber_stmt = gimple_build_assign (id->retvar, clobber); + gimple_set_location (clobber_stmt, gimple_location (old_stmt)); + gsi_insert_after (&stmt_gsi, clobber_stmt, GSI_SAME_STMT); + } /* Copy bounds if we copy structure with bounds. */ if (chkp_function_instrumented_p (id->dst_fn) @@ -4884,8 +4919,26 @@ expand_call_inline (basic_block bb, gimp SSA_NAME_DEF_STMT (name) = gimple_build_nop (); } } + /* Replace with a clobber for id->retvar. */ + else if (flag_stack_reuse != SR_NONE + && (flag_sanitize & SANITIZE_KERNEL_ADDRESS) != 0 + && id->retvar + && VAR_P (id->retvar) + && id->retvar != return_slot + && id->retvar != modify_dest + && !TREE_THIS_VOLATILE (id->retvar) + && !is_gimple_reg (id->retvar)) + { + tree clobber = build_constructor (TREE_TYPE (id->retvar), NULL); + gimple *clobber_stmt; + TREE_THIS_VOLATILE (clobber) = 1; + clobber_stmt = gimple_build_assign (id->retvar, clobber); + gimple_set_location (clobber_stmt, gimple_location (stmt)); + gsi_replace (&stmt_gsi, clobber_stmt, false); + maybe_clean_or_replace_eh_stmt (stmt, clobber_stmt); + } else - gsi_remove (&stmt_gsi, true); + gsi_remove (&stmt_gsi, true); } /* Put returned bounds into the correct place if required. */ @@ -4934,6 +4987,8 @@ expand_call_inline (basic_block bb, gimp cg_edge->callee->remove (); id->block = NULL_TREE; + id->retvar = NULL_TREE; + id->retbnd = NULL_TREE; successfully_inlined = true; egress: --- gcc/testsuite/g++.dg/asan/pr81715.C (nonexistent) +++ gcc/testsuite/g++.dg/asan/pr81715.C (revision 253065) @@ -0,0 +1,36 @@ +// PR sanitizer/81715 +// { dg-do compile } +// Verify the variables for inlined foo parameters are reused +// { dg-options "-fno-sanitize=address -fsanitize=kernel-address -O2 -Wframe-larger-than=16384" } + +struct S { int a, b, c, d, e; char f[1024]; }; +void baz (int *, int *, int *, struct S *, int *, int *); + +static inline struct S +foo (int a, int b, int c, struct S d, int e, int f) +{ + struct S s; + baz (&a, &b, &c, &d, &e, &f); + s = d; + return s; +} + +struct S g[64]; + +void +bar (int a, int b, int c, struct S d, int e, int f) +{ +#define A(N) \ + g[N+0] = foo (a, b, c, d, e, f); \ + g[N+1] = foo (a, b, c, d, e, f); \ + g[N+2] = foo (a, b, c, d, e, f); \ + g[N+3] = foo (a, b, c, d, e, f); \ + g[N+4] = foo (a, b, c, d, e, f); \ + g[N+5] = foo (a, b, c, d, e, f); \ + g[N+6] = foo (a, b, c, d, e, f); \ + g[N+7] = foo (a, b, c, d, e, f); \ + foo (a, b, c, d, e, f); \ + foo (a, b, c, d, e, f) + A(0); A(8); A(16); A(24); + A(32); A(40); A(48); A(56); +}
2017-10-27 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-10-04 Jakub Jelinek <ja...@redhat.com> PR c++/82373 * error.c (dump_function_decl): If show_return, call dump_type_suffix on the same return type dump_type_prefix has been called on. * g++.dg/cpp1y/pr82373.C: New test. --- gcc/cp/error.c (revision 253417) +++ gcc/cp/error.c (revision 253418) @@ -1574,6 +1574,7 @@ dump_function_decl (cxx_pretty_printer * int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME); tree exceptions; bool constexpr_p; + tree ret = NULL_TREE; flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); if (TREE_CODE (t) == TEMPLATE_DECL) @@ -1636,7 +1637,7 @@ dump_function_decl (cxx_pretty_printer * && !DECL_DESTRUCTOR_P (t) && !deduction_guide_p (t)); if (show_return) { - tree ret = fndecl_declared_return_type (t); + ret = fndecl_declared_return_type (t); dump_type_prefix (pp, ret, flags); } @@ -1677,7 +1678,7 @@ dump_function_decl (cxx_pretty_printer * } if (show_return) - dump_type_suffix (pp, TREE_TYPE (fntype), flags); + dump_type_suffix (pp, ret, flags); else if (deduction_guide_p (t)) { pp_cxx_ws_string (pp, "->"); --- gcc/testsuite/g++.dg/cpp1y/pr82373.C (nonexistent) +++ gcc/testsuite/g++.dg/cpp1y/pr82373.C (revision 253418) @@ -0,0 +1,20 @@ +// PR c++/82373 +// { dg-do compile { target c++14 } } + +namespace N +{ + int (*fp)(int); + auto foo(int a) // { dg-message "In function 'auto N::foo\\(int\\)'" "" { target *-*-* } 0 } + { + if (a) + return fp; + return nullptr; // { dg-error "inconsistent deduction for auto return type: 'int \\(\\*\\)\\(int\\)' and then 'std::nullptr_t'" } */ + } +} +int (*fp2)(int); +auto bar(int a) // { dg-message "In function 'auto bar\\(int\\)'" "" { target *-*-* } 0 } +{ + if (a) + return fp2; + return nullptr; // { dg-error "inconsistent deduction for auto return type: 'int \\(\\*\\)\\(int\\)' and then 'std::nullptr_t'" } */ +}
2017-10-27 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-10-12 Jakub Jelinek <ja...@redhat.com> PR c++/82159 * expr.c (store_field): Don't optimize away bitsize == 0 store from CALL_EXPR with addressable return type. * g++.dg/opt/pr82159-2.C: New test. --- gcc/expr.c (revision 253672) +++ gcc/expr.c (revision 253673) @@ -6749,8 +6749,11 @@ store_field (rtx target, HOST_WIDE_INT b return const0_rtx; /* If we have nothing to store, do nothing unless the expression has - side-effects. */ - if (bitsize == 0) + side-effects. Don't do that for zero sized addressable lhs of + calls. */ + if (bitsize == 0 + && (!TREE_ADDRESSABLE (TREE_TYPE (exp)) + || TREE_CODE (exp) != CALL_EXPR)) return expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL); if (GET_CODE (target) == CONCAT) --- gcc/testsuite/g++.dg/opt/pr82159-2.C (nonexistent) +++ gcc/testsuite/g++.dg/opt/pr82159-2.C (revision 253673) @@ -0,0 +1,65 @@ +// PR c++/82159 +// { dg-do compile } +// { dg-options "" } + +template <typename T> struct D { T e; }; +struct F : D<int[0]> { + F(const F &); +}; +struct G : F { + template <class T> G operator-(T); +}; +template <class T> struct I { + typedef typename T::template J<I> ak; +}; +template <class T> struct K { typename I<T>::ak an; }; +struct H { + G l; +}; +struct C { + ~C(); +}; +template <class T> struct M : T { + template <typename U, typename V> M(U, V); + H h; + virtual void foo() { T::bar(&h); } +}; +template <int, typename> class A; +template <class> struct B { + typedef int BT; + struct BC {}; + template <class T> struct BD { + G g; + BD(BT, T n) : g(n.l - 0) {} + }; + B(BT, BC); +}; +template <typename> struct O; +template <int T, typename U> +struct O<B<A<T, U> > > : public B<A<T, U> >::BC {}; +struct L : B<A<2, double> > { + struct P : C { + void bar(H *x) { + BT a; + BD<H>(a, *x); + } + }; + template <typename U, typename V> L(U x, V n) : B(x, n) {} + int ll; + virtual int baz() { M<P>(this, ll); } +}; +template <typename> class Q { + O<B<A<2, double> > > q; + virtual L baz() { L(0, q); } +}; +template <template <class> class T> struct R { + R() { T<int>(); } +}; +struct S { + template <class> class J : R<Q> {}; +}; +void foo() { K<S> c; } + +int main() { + return 0; +}