When we're passing ADDR_EXPR of long long int argument in -m32 mode,
the ADDR_EXPR's VAR_DECL has to have its DECL_RTL set and
corresponding stack slot allocated, it seems.  Otherwise we ICE
when expanding a function with such argument.  This patch does that
and adds a testcase for it.

Bootstrapped, ran ubsan testsuite on x86_64-unknown-linux-gnu.
Ok for trunk?

2013-12-05  Marek Polacek  <pola...@redhat.com>

        PR sanitizer/59333
        * ubsan.c: Include rtl.h.
        (ubsan_encode_value): Add new parameter.  If expanding, assign
        a stack slot for DECL_RTL of the temporary.  Handle BOOLEAN_TYPE and
        ENUMERAL_TYPE.
        (ubsan_build_overflow_builtin): Adjust ubsan_encode_value
        call.
        * ubsan.h (ubsan_encode_value): Adjust declaration.
c-family/
        * c-ubsan.c (ubsan_instrument_division): Adjust ubsan_encode_value
        call.
        (ubsan_instrument_shift): Likewise.
        (ubsan_instrument_vla): Likewise.
testsuite/
        * c-c++-common/ubsan/pr59333.c: New test.

--- gcc/c-family/c-ubsan.c.mp   2013-12-05 11:24:08.570201260 +0100
+++ gcc/c-family/c-ubsan.c      2013-12-05 11:26:25.401721067 +0100
@@ -78,8 +78,8 @@ ubsan_instrument_division (location_t lo
                                 NULL_TREE);
   data = build_fold_addr_expr_loc (loc, data);
   tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW);
-  tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
-                           ubsan_encode_value (op1));
+  tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0, false),
+                           ubsan_encode_value (op1, false));
   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
 
   return t;
@@ -152,8 +152,8 @@ ubsan_instrument_shift (location_t loc,
   t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t,
                   tt ? tt : integer_zero_node);
   tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS);
-  tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
-                           ubsan_encode_value (op1));
+  tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0, false),
+                           ubsan_encode_value (op1, false));
   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
 
   return t;
@@ -174,7 +174,8 @@ ubsan_instrument_vla (location_t loc, tr
                                 NULL_TREE);
   data = build_fold_addr_expr_loc (loc, data);
   tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE);
-  tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size));
+  tt = build_call_expr_loc (loc, tt, 2, data,
+                           ubsan_encode_value (size, false));
   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
 
   return t;
--- gcc/ubsan.h.mp      2013-12-05 11:25:18.979469651 +0100
+++ gcc/ubsan.h 2013-12-05 11:25:28.958507098 +0100
@@ -41,7 +41,7 @@ extern tree ubsan_instrument_unreachable
 extern tree ubsan_create_data (const char *, location_t,
                               const struct ubsan_mismatch_data *, ...);
 extern tree ubsan_type_descriptor (tree, bool);
-extern tree ubsan_encode_value (tree);
+extern tree ubsan_encode_value (tree, bool);
 extern bool is_ubsan_builtin_p (tree);
 extern tree ubsan_build_overflow_builtin (tree_code, location_t, tree, tree, 
tree);
 
--- gcc/ubsan.c.mp      2013-12-05 09:40:39.676771966 +0100
+++ gcc/ubsan.c 2013-12-05 11:35:06.907851149 +0100
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.
 #include "cfgloop.h"
 #include "ubsan.h"
 #include "c-family/c-common.h"
+#include "rtl.h"
 
 /* Map from a tree to a VAR_DECL tree.  */
 
@@ -102,45 +103,50 @@ decl_for_type_insert (tree type, tree de
 
 /* Helper routine, which encodes a value in the pointer_sized_int_node.
    Arguments with precision <= POINTER_SIZE are passed directly,
-   the rest is passed by reference.  T is a value we are to encode.  */
+   the rest is passed by reference.  T is a value we are to encode.
+   IN_EXPAND_P is true if this function is called during expansion.  */
 
 tree
-ubsan_encode_value (tree t)
+ubsan_encode_value (tree t, bool in_expand_p)
 {
   tree type = TREE_TYPE (t);
-  switch (TREE_CODE (type))
-    {
-    case INTEGER_TYPE:
-      if (TYPE_PRECISION (type) <= POINTER_SIZE)
+  const unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  if (bitsize <= POINTER_SIZE)
+    switch (TREE_CODE (type))
+      {
+      case BOOLEAN_TYPE:
+      case ENUMERAL_TYPE:
+      case INTEGER_TYPE:
        return fold_build1 (NOP_EXPR, pointer_sized_int_node, t);
+      case REAL_TYPE:
+       {
+         tree itype = build_nonstandard_integer_type (bitsize, true);
+         t = fold_build1 (VIEW_CONVERT_EXPR, itype, t);
+         return fold_convert (pointer_sized_int_node, t);
+       }
+      default:
+       gcc_unreachable ();
+      }
+  else
+    {
+      if (!TREE_ADDRESSABLE (t))
+       {
+         /* The reason for this is that we don't want to pessimize
+            code by making vars unnecessarily addressable.  */
+         tree var = create_tmp_var (type, NULL);
+         tree tem = build2 (MODIFY_EXPR, void_type_node, var, t);
+         if (in_expand_p)
+           {
+             SET_DECL_RTL (var,
+                           assign_stack_temp_for_type (TYPE_MODE (type),
+                           GET_MODE_SIZE (TYPE_MODE (type)), type));
+             return build_fold_addr_expr (var);
+           }
+         t = build_fold_addr_expr (var);
+         return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t);
+       }
       else
        return build_fold_addr_expr (t);
-    case REAL_TYPE:
-      {
-       unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
-       if (bitsize <= POINTER_SIZE)
-         {
-           tree itype = build_nonstandard_integer_type (bitsize, true);
-           t = fold_build1 (VIEW_CONVERT_EXPR, itype, t);
-           return fold_convert (pointer_sized_int_node, t);
-         }
-       else
-         {
-           if (!TREE_ADDRESSABLE (t))
-             {
-               /* The reason for this is that we don't want to pessimize
-                  code by making vars unnecessarily addressable.  */
-               tree var = create_tmp_var (TREE_TYPE (t), NULL);
-               tree tem = build2 (MODIFY_EXPR, void_type_node, var, t);
-               t = build_fold_addr_expr (var);
-               return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t);
-             }
-           else
-             return build_fold_addr_expr (t);
-         }
-      }
-    default:
-      gcc_unreachable ();
     }
 }
 
@@ -663,8 +669,9 @@ ubsan_build_overflow_builtin (tree_code
   tree fn = builtin_decl_explicit (fn_code);
   return build_call_expr_loc (loc, fn, 2 + (code != NEGATE_EXPR),
                              build_fold_addr_expr_loc (loc, data),
-                             ubsan_encode_value (op0),
-                             op1 ? ubsan_encode_value (op1) : NULL_TREE);
+                             ubsan_encode_value (op0, true),
+                             op1 ? ubsan_encode_value (op1, true)
+                                 : NULL_TREE);
 }
 
 /* Perform the signed integer instrumentation.  GSI is the iterator
--- gcc/testsuite/c-c++-common/ubsan/pr59333.c.mp       2013-12-05 
11:30:36.984759390 +0100
+++ gcc/testsuite/c-c++-common/ubsan/pr59333.c  2013-12-05 11:31:36.599979040 
+0100
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined" } */
+
+long long int
+foo (long long int i, long long int j)
+{
+  return i * j;
+}

        Marek

Reply via email to