From: Jakub Jelinek Date: Fri, 1 Oct 2010 13:13:31 +0000 (+0200) Subject: backport: re PR target/45843 (__builtin_va_arg overwrites into adjacent stack location) X-Git-Tag: releases/gcc-4.4.6~338 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=11a5fedde5f76d9f9a21c0ff3d7a21abbcdeb512;p=thirdparty%2Fgcc.git backport: re PR target/45843 (__builtin_va_arg overwrites into adjacent stack location) Backport from mainline 2010-09-30 Jakub Jelinek PR target/45843 * config/i386/i386.c (ix86_gimplify_va_arg): Use INTVAL (XEXP (slot, 1)) as prev_size. 2010-06-21 Jakub Jelinek 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. Backport from mainline 2010-09-30 Jakub Jelinek * g++.dg/torture/pr45843.C: New test. 2010-06-21 Jakub Jelinek PR target/44575 * gcc.c-torture/execute/pr44575.c: New test. From-SVN: r164884 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bf70aa28306f..43a324132cc1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2010-10-01 Jakub Jelinek + + Backport from mainline + 2010-09-30 Jakub Jelinek + + PR target/45843 + * config/i386/i386.c (ix86_gimplify_va_arg): Use + INTVAL (XEXP (slot, 1)) as prev_size. + + 2010-06-21 Jakub Jelinek + + 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. + 2010-10-01 Jakub Jelinek * BASE-VER: Set to 4.4.6. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 2fc03586224d..112b1b1d92ea 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -6956,7 +6956,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; */ @@ -6968,13 +6968,31 @@ 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); + + gcc_assert (prev_size <= INTVAL (XEXP (slot, 1))); + prev_size = INTVAL (XEXP (slot, 1)); + 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))) { @@ -6989,14 +7007,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); + size_int (prev_size)); + 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 ac1281daaaba..ee343be18d32 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2010-10-01 Jakub Jelinek + + Backport from mainline + 2010-09-30 Jakub Jelinek + + * g++.dg/torture/pr45843.C: New test. + + 2010-06-21 Jakub Jelinek + + PR target/44575 + * gcc.c-torture/execute/pr44575.c: New test. + 2010-10-01 Release Manager * GCC 4.4.5 released. diff --git a/gcc/testsuite/g++.dg/torture/pr45843.C b/gcc/testsuite/g++.dg/torture/pr45843.C new file mode 100644 index 000000000000..f77b8cb0135d --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr45843.C @@ -0,0 +1,28 @@ +// PR target/45843 +// { dg-do run } + +#include + +extern "C" void abort (); +struct S { struct T { } a[14]; char b; }; +struct S arg, s; + +void +foo (int z, ...) +{ + char c; + va_list ap; + va_start (ap, z); + c = 'a'; + arg = va_arg (ap, struct S); + if (c != 'a') + abort (); + va_end (ap); +} + +int +main () +{ + foo (1, s); + return 0; +} 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 000000000000..62a7d7800b0f --- /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; +}