From 529e5fc9c0fd011fdd6e4eec2f5ec3451873cd56 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 21 Jun 2010 18:33:49 +0200 Subject: [PATCH] re PR target/44575 (__builtin_va_arg overwrites into adjacent stack location) PR target/44575 * config/i386/i386.c (ix86_gimplify_va_arg): When copying va_arg from a set of register save slots into a temporary, if the container is bigger than type size, do the copying using smaller mode or using memcpy. * gcc.c-torture/execute/pr44575.c: New test. From-SVN: r161097 --- gcc/ChangeLog | 6 +++ gcc/config/i386/i386.c | 44 ++++++++++++++--- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.c-torture/execute/pr44575.c | 49 +++++++++++++++++++ 4 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr44575.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f6e1007baab..140b9406f27 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -47,6 +47,12 @@ * stmt.c (resolve_asm_operand_names): Fix handling of %%. + PR target/44575 + * config/i386/i386.c (ix86_gimplify_va_arg): When copying + va_arg from a set of register save slots into a temporary, + if the container is bigger than type size, do the copying + using smaller mode or using memcpy. + PR bootstrap/44426 * sel-sched-dump.h (sel_prepare_string_for_dot_label): Remove prototype. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index f9c0718e391..7d97a6a0061 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -7267,7 +7267,7 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, } if (need_temp) { - int i; + int i, prev_size = 0; tree temp = create_tmp_var (type, "va_arg_tmp"); /* addr = &temp; */ @@ -7279,13 +7279,29 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, rtx slot = XVECEXP (container, 0, i); rtx reg = XEXP (slot, 0); enum machine_mode mode = GET_MODE (reg); - tree piece_type = lang_hooks.types.type_for_mode (mode, 1); - tree addr_type = build_pointer_type (piece_type); - tree daddr_type = build_pointer_type_for_mode (piece_type, - ptr_mode, true); + tree piece_type; + tree addr_type; + tree daddr_type; tree src_addr, src; int src_offset; tree dest_addr, dest; + int cur_size = GET_MODE_SIZE (mode); + + if (prev_size + cur_size > size) + { + cur_size = size - prev_size; + mode = mode_for_size (cur_size * BITS_PER_UNIT, MODE_INT, 1); + if (mode == BLKmode) + mode = QImode; + } + piece_type = lang_hooks.types.type_for_mode (mode, 1); + if (mode == GET_MODE (reg)) + addr_type = build_pointer_type (piece_type); + else + addr_type = build_pointer_type_for_mode (piece_type, ptr_mode, + true); + daddr_type = build_pointer_type_for_mode (piece_type, ptr_mode, + true); if (SSE_REGNO_P (REGNO (reg))) { @@ -7300,14 +7316,26 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, src_addr = fold_convert (addr_type, src_addr); src_addr = fold_build2 (POINTER_PLUS_EXPR, addr_type, src_addr, size_int (src_offset)); - src = build_va_arg_indirect_ref (src_addr); dest_addr = fold_convert (daddr_type, addr); dest_addr = fold_build2 (POINTER_PLUS_EXPR, daddr_type, dest_addr, size_int (INTVAL (XEXP (slot, 1)))); - dest = build_va_arg_indirect_ref (dest_addr); + if (cur_size == GET_MODE_SIZE (mode)) + { + src = build_va_arg_indirect_ref (src_addr); + dest = build_va_arg_indirect_ref (dest_addr); - gimplify_assign (dest, src, pre_p); + gimplify_assign (dest, src, pre_p); + } + else + { + tree copy + = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY], + 3, dest_addr, src_addr, + size_int (cur_size)); + gimplify_and_add (copy, pre_p); + } + prev_size += cur_size; } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5ac708a2d3c..b61001c1e35 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-06-21 Jakub Jelinek + + PR target/44575 + * gcc.c-torture/execute/pr44575.c: New test. + 2010-06-21 Tobias Burnus PR fortran/40632 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr44575.c b/gcc/testsuite/gcc.c-torture/execute/pr44575.c new file mode 100644 index 00000000000..62a7d7800b0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr44575.c @@ -0,0 +1,49 @@ +/* PR target/44575 */ + +#include + +int fails = 0; +struct S { float a[3]; }; +struct S a[5]; + +void +check (int z, ...) +{ + struct S arg, *p; + va_list ap; + int j = 0, k = 0; + int i; + va_start (ap, z); + for (i = 2; i < 4; ++i) + { + p = 0; + j++; + k += 2; + switch ((z << 4) | i) + { + case 0x12: + case 0x13: + p = &a[2]; + arg = va_arg (ap, struct S); + break; + default: + ++fails; + break; + } + if (p && p->a[2] != arg.a[2]) + ++fails; + if (fails) + break; + } + va_end (ap); +} + +int +main () +{ + a[2].a[2] = -49026; + check (1, a[2], a[2]); + if (fails) + abort (); + return 0; +} -- 2.30.2