From 984b20545fee1f42c758006b8144159319a8ecf7 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 15 Apr 2015 16:59:01 +0930 Subject: [PATCH] re PR target/65408 (powerpc64 function argument passing may access invalid memory) PR target/65408 PR target/58744 PR middle-end/36043 * calls.c (load_register_parameters): Don't load past end of mem unless suitably aligned. From-SVN: r222115 --- gcc/ChangeLog | 8 +++ gcc/calls.c | 40 ++++++++---- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.dg/pr65408.c | 112 +++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr65408.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e52771f7923..c68a2fac882 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2015-04-15 Alan Modra + + PR target/65408 + PR target/58744 + PR middle-end/36043 + * calls.c (load_register_parameters): Don't load past end of + mem unless suitably aligned. + 2015-04-15 Nick Clifton * config/rl78/rl78.c (rl78_expand_prologue): Mark large stack diff --git a/gcc/calls.c b/gcc/calls.c index 970415d6592..32ea4eb1f54 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -2099,6 +2099,26 @@ load_register_parameters (struct arg_data *args, int num_actuals, (XEXP (args[i].value, 0), size))) *sibcall_failure = 1; + if (size % UNITS_PER_WORD == 0 + || MEM_ALIGN (mem) % BITS_PER_WORD == 0) + move_block_to_reg (REGNO (reg), mem, nregs, args[i].mode); + else + { + if (nregs > 1) + move_block_to_reg (REGNO (reg), mem, nregs - 1, + args[i].mode); + rtx dest = gen_rtx_REG (word_mode, REGNO (reg) + nregs - 1); + unsigned int bitoff = (nregs - 1) * BITS_PER_WORD; + unsigned int bitsize = size * BITS_PER_UNIT - bitoff; + rtx x = extract_bit_field (mem, bitsize, bitoff, 1, + dest, word_mode, word_mode); + if (BYTES_BIG_ENDIAN) + x = expand_shift (LSHIFT_EXPR, word_mode, x, + BITS_PER_WORD - bitsize, dest, 1); + if (x != dest) + emit_move_insn (dest, x); + } + /* Handle a BLKmode that needs shifting. */ if (nregs == 1 && size < UNITS_PER_WORD #ifdef BLOCK_REG_PADDING @@ -2106,22 +2126,18 @@ load_register_parameters (struct arg_data *args, int num_actuals, #else && BYTES_BIG_ENDIAN #endif - ) + ) { - rtx tem = operand_subword_force (mem, 0, args[i].mode); - rtx ri = gen_rtx_REG (word_mode, REGNO (reg)); - rtx x = gen_reg_rtx (word_mode); + rtx dest = gen_rtx_REG (word_mode, REGNO (reg)); int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT; - enum tree_code dir = BYTES_BIG_ENDIAN ? RSHIFT_EXPR - : LSHIFT_EXPR; + enum tree_code dir = (BYTES_BIG_ENDIAN + ? RSHIFT_EXPR : LSHIFT_EXPR); + rtx x; - emit_move_insn (x, tem); - x = expand_shift (dir, word_mode, x, shift, ri, 1); - if (x != ri) - emit_move_insn (ri, x); + x = expand_shift (dir, word_mode, dest, shift, dest, 1); + if (x != dest) + emit_move_insn (dest, x); } - else - move_block_to_reg (REGNO (reg), mem, nregs, args[i].mode); } /* When a parameter is a block, and perhaps in other cases, it is diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2f6ef32fe3d..db3d1d325cd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2015-04-15 Alan Modra + + * gcc.dg/pr65408.c: New. + 2015-04-14 Yvan Roux PR target/65729 diff --git a/gcc/testsuite/gcc.dg/pr65408.c b/gcc/testsuite/gcc.dg/pr65408.c new file mode 100644 index 00000000000..8eec1d2dc36 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr65408.c @@ -0,0 +1,112 @@ +/* PR middle-end/36043 target/58744 target/65408 */ +/* { dg-do run { target mmap } } */ +/* { dg-options "-O2" } */ + +#include +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +#ifndef MAP_ANON +#define MAP_ANON 0 +#endif +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +typedef struct +{ + unsigned char r; + unsigned char g; + unsigned char b; +} __attribute__((packed)) pr58744; + +typedef struct +{ + unsigned short r; + unsigned short g; + unsigned short b; +} pr36043; + +typedef struct +{ + int r; + int g; + int b; +} pr65408; + +__attribute__ ((noinline, noclone)) +void +f1a (pr58744 x) +{ + if (x.r != 1 || x.g != 2 || x.b != 3) + __builtin_abort(); +} + +__attribute__ ((noinline, noclone)) +void +f1 (pr58744 *x) +{ + f1a (*x); +} + +__attribute__ ((noinline, noclone)) +void +f2a (pr36043 x) +{ + if (x.r != 1 || x.g != 2 || x.b != 3) + __builtin_abort(); +} + +__attribute__ ((noinline, noclone)) +void +f2 (pr36043 *x) +{ + f2a (*x); +} + +__attribute__ ((noinline, noclone)) +void +f3a (pr65408 x) +{ + if (x.r != 1 || x.g != 2 || x.b != 3) + __builtin_abort(); +} + +__attribute__ ((noinline, noclone)) +void +f3 (pr65408 *x) +{ + f3a (*x); +} + +int +main () +{ + char *p = mmap ((void *) 0, 131072, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (p == MAP_FAILED) + return 0; + char *endp = p + 65536; + if (munmap (endp, 65536) < 0) + return 0; + + pr58744 *s1 = (pr58744 *) endp - 1; + s1->r = 1; + s1->g = 2; + s1->b = 3; + f1 (s1); + + pr36043 *s2 = (pr36043 *) endp - 1; + s2->r = 1; + s2->g = 2; + s2->b = 3; + f2 (s2); + + pr65408 *s3 = (pr65408 *) endp - 1; + s3->r = 1; + s3->g = 2; + s3->b = 3; + f3 (s3); + + return 0; +} -- 2.30.2