Patchwork [ubsan] Add libcall arguments

login
register
mail settings
Submitter Marek Polacek
Date July 5, 2013, 2:04 p.m.
Message ID <20130705140431.GB21800@redhat.com>
Download mbox | patch
Permalink /patch/257178/
State New
Headers show

Comments

Marek Polacek - July 5, 2013, 2:04 p.m.
This patch adds creating and passing the arguments for the ubsan
library.  So, we can finally make use of the ubsan library.  We
currently sanitize only divisions by zero and shifts.  What it can do
now is e.g. for:
int main (void) { long int a = 4; int b = 113; return a << b; }
it at runtime says:
xx.c:1:57: runtime error: shift exponent 113 is too large for 64-bit type long int

There are a few things I'm not entirely happy about; I have yet to handle
freeing the hash table, but I think I'll need the GTY machinery for
this (ubsan is not a pass, so I can't just call it at the end of the
pas).  Or maybe just create a destructor and use append_to_statement_list.

The code is still somewhat in flux and may be quite messy, but I
wanted to push this one before doing something else.

Commited to ubsan branch.

2013-07-05  Marek Polacek  <polacek@redhat.com>

	* c-ubsan.c (struct ubsan_typedesc): Declare.
	(ubsan_typedesc_ht): New hashtable.
	(ubsan_typedesc_hasher::hash): New function.
	(ubsan_typedesc_hasher::equal): Likewise.
	(ubsan_typedesc_init): Likewise.
	(ubsan_typedesc_get_alloc_pool): Likewise.
	(get_typedesc_hash_table): Likewise.
	(ubsan_typedesc_new): Likewise.
	(empty_ubsan_typedesc_hash_table): Likewise.
	(uptr_type): Likewise.
	(ubsan_encode_value): Likewise.
	(ubsan_type_descriptor_type): Likewise.
	(ubsan_source_location_type): Likewise.
	(ubsan_source_location): Likewise.
	(get_tinfo_for_type): Likewise.
	(ubsan_type_descriptor): Likewise.
	(ubsan_create_data): Likewise.
	(ubsan_instrument_division): Create and pass arguments for the ubsan
	library.
	(ubsan_instrument_shift): Likewise.


	Marek
Jason Merrill - July 18, 2013, 7:47 p.m.
On 07/05/2013 10:04 AM, Marek Polacek wrote:
> +/* This type represents an entry in the hash table.  */

Please describe the hash table more up here.  What are you tracking?

> +  hashval_t h = iterative_hash_object (data->type, 0);
> +  h = iterative_hash_object (data->decl, h);

If you hash the decl as well as the type, the find_slot in 
ubsan_type_descriptor will almost never find an existing entry.

> +uptr_type (void)
> +{
> +  return build_nonstandard_integer_type (POINTER_SIZE, 1);

Why not use uintptr_type_node?

> I have yet to handle
> freeing the hash table, but I think I'll need the GTY machinery for
> this (ubsan is not a pass, so I can't just call it at the end of the
> pas).  Or maybe just create a destructor and use append_to_statement_list.

That won't work; append_to_statement_list is for things that happen at 
runtime, but freeing the hash table is something that needs to happen in 
the compiler.

> +/* This routine returns a magic number for TYPE.
> +   ??? This is probably too ugly.  Tweak it.  */
> +
> +static unsigned short
> +get_tinfo_for_type (tree type)

Why map from size to some magic number rather than use the size 
directly?  Also, "tinfo" sounds to me like something to do with C++ 
type_info.

Jason
Jakub Jelinek - July 19, 2013, 3:20 p.m.
On Thu, Jul 18, 2013 at 03:47:28PM -0400, Jason Merrill wrote:
> Please describe the hash table more up here.  What are you tracking?
> 
> >+  hashval_t h = iterative_hash_object (data->type, 0);
> >+  h = iterative_hash_object (data->decl, h);
> 
> If you hash the decl as well as the type, the find_slot in
> ubsan_type_descriptor will almost never find an existing entry.

Yeah.

> >I have yet to handle
> >freeing the hash table, but I think I'll need the GTY machinery for
> >this (ubsan is not a pass, so I can't just call it at the end of the
> >pas).  Or maybe just create a destructor and use append_to_statement_list.
> 
> That won't work; append_to_statement_list is for things that happen
> at runtime, but freeing the hash table is something that needs to
> happen in the compiler.

Also, I wonder if we need to free the hash table ever, the only meaningful
place would be when we are done with compilation, if all uses of this (even
in the future) are from the FEs, perhaps freeing the hash table somewhere
after parsing of the whole CU finished would be fine, but if we need it even
from the middle-end, that might be too early.

> >+/* This routine returns a magic number for TYPE.
> >+   ??? This is probably too ugly.  Tweak it.  */
> >+
> >+static unsigned short
> >+get_tinfo_for_type (tree type)
> 
> Why map from size to some magic number rather than use the size
> directly?  Also, "tinfo" sounds to me like something to do with C++
> type_info.

Yeah, get_ubsan_type_info_for_type would be better, plus
The docs say that it should be log2 of the bit width, so I'd expect that
you return
(exact_log2 (TYPE_PRECISION (type)) << 1) | !TYPE_UNSIGNED (type)
(perhaps with error if exact_log2 returns -1) and thus handle all possible
type bitsizes.  Or if you prefer to use GET_MODE_BITSIZE, that.

Have you checked what clang does if you use typedefs?  Does it use
the names appearing in the typedefs rather than their underlying types,
or is it TYPE_MAIN_VARIANT (type) actually?

Also:

ASM_FORMAT_PRIVATE_NAME (tmp_name, ".Lubsan_type", type_var_id_num++);

I don't think the . at the beginning is going to work everywhere
(on targets that don't support dots in labels),
I think you want ASM_GENERATE_INTERNAL_LABEL instead and just use
"Lubsan_type" as the second argument (note, this macro needs a buffer,
doesn't alloca it).

	Jakub
Marek Polacek - July 19, 2013, 6:58 p.m.
On Fri, Jul 19, 2013 at 05:20:39PM +0200, Jakub Jelinek wrote:
> > >I have yet to handle
> > >freeing the hash table, but I think I'll need the GTY machinery for
> > >this (ubsan is not a pass, so I can't just call it at the end of the
> > >pas).  Or maybe just create a destructor and use append_to_statement_list.
> > 
> > That won't work; append_to_statement_list is for things that happen
> > at runtime, but freeing the hash table is something that needs to
> > happen in the compiler.
> 
> Also, I wonder if we need to free the hash table ever, the only meaningful
> place would be when we are done with compilation, if all uses of this (even
> in the future) are from the FEs, perhaps freeing the hash table somewhere
> after parsing of the whole CU finished would be fine, but if we need it even
> from the middle-end, that might be too early.

I'm afraid we'll need it even from the middle-end, at least when doing
the signed overflow sanitization.

> > >+/* This routine returns a magic number for TYPE.
> > >+   ??? This is probably too ugly.  Tweak it.  */
> > >+
> > >+static unsigned short
> > >+get_tinfo_for_type (tree type)
> > 
> > Why map from size to some magic number rather than use the size
> > directly?  Also, "tinfo" sounds to me like something to do with C++
> > type_info.
> 
> Yeah, get_ubsan_type_info_for_type would be better, plus
> The docs say that it should be log2 of the bit width, so I'd expect that
> you return
> (exact_log2 (TYPE_PRECISION (type)) << 1) | !TYPE_UNSIGNED (type)
> (perhaps with error if exact_log2 returns -1) and thus handle all possible
> type bitsizes.  Or if you prefer to use GET_MODE_BITSIZE, that.

Ah, that's much better.  I did it like that; also included the
checking of return value of exact_log2.  And yeah, the name wasn't
very nice, so I've renamed it.

> Have you checked what clang does if you use typedefs?  Does it use
> the names appearing in the typedefs rather than their underlying types,
> or is it TYPE_MAIN_VARIANT (type) actually?

Good point.  E.g. for
typedef const unsigned int foo_t;
clang says 'unsigned int'.  But we didn't do it; we'd output the foo_t
type.  I've adjusted that, so now we print the underlying type as
clang does.

> Also:
> 
> ASM_FORMAT_PRIVATE_NAME (tmp_name, ".Lubsan_type", type_var_id_num++);
> 
> I don't think the . at the beginning is going to work everywhere
> (on targets that don't support dots in labels),
> I think you want ASM_GENERATE_INTERNAL_LABEL instead and just use
> "Lubsan_type" as the second argument (note, this macro needs a buffer,
> doesn't alloca it).

Okay, fixed.  Thanks,

	Marek

Patch

--- gcc/c-family/c-ubsan.c.mp	2013-07-05 14:41:56.823158917 +0200
+++ gcc/c-family/c-ubsan.c	2013-07-05 14:42:12.499214028 +0200
@@ -22,9 +22,459 @@  along with GCC; see the file COPYING3.
 #include "system.h"
 #include "coretypes.h"
 #include "tree.h"
+#include "alloc-pool.h"
+#include "cgraph.h"
+#include "gimple.h"
+#include "hash-table.h"
+#include "output.h"
+#include "toplev.h"
 #include "c-family/c-common.h"
 #include "c-family/c-ubsan.h"
 
+/* This type represents an entry in the hash table.  */
+struct ubsan_typedesc
+{
+  tree type;
+  tree decl;
+};
+
+static alloc_pool ubsan_typedesc_alloc_pool;
+
+/* Hash table for type descriptors.  */
+struct ubsan_typedesc_hasher
+  : typed_noop_remove <ubsan_typedesc>
+{
+  typedef ubsan_typedesc value_type;
+  typedef ubsan_typedesc compare_type;
+
+  static inline hashval_t hash (const value_type *);
+  static inline bool equal (const value_type *, const compare_type *);
+};
+
+/* Hash a memory reference.  */
+
+inline hashval_t
+ubsan_typedesc_hasher::hash (const ubsan_typedesc *data)
+{
+  hashval_t h = iterative_hash_object (data->type, 0);
+  h = iterative_hash_object (data->decl, h);
+  return h;
+}
+
+/* Compare two data types.  */
+
+inline bool
+ubsan_typedesc_hasher::equal (const ubsan_typedesc *d1,
+			      const ubsan_typedesc *d2)
+{
+  /* ??? Here, the types should have identical __typekind,
+     _typeinfo and __typename.  Is this enough?  */
+  return d1->type == d2->type;
+}
+
+static hash_table <ubsan_typedesc_hasher> ubsan_typedesc_ht;
+
+/* Initializes an instance of ubsan_typedesc.  */
+
+static void
+ubsan_typedesc_init (ubsan_typedesc *data, tree type, tree decl)
+{
+  data->type = type;
+  data->decl = decl;
+}
+
+/* This creates the alloc pool used to store the instances of
+   ubsan_typedesc that are stored in the hash table ubsan_typedesc_ht.  */
+
+static alloc_pool
+ubsan_typedesc_get_alloc_pool ()
+{
+  if (ubsan_typedesc_alloc_pool == NULL)
+    ubsan_typedesc_alloc_pool = create_alloc_pool ("ubsan_typedesc",
+						   sizeof (ubsan_typedesc),
+						   10);
+  // XXX But where do we free this?  We'll need GTY machinery.
+  return ubsan_typedesc_alloc_pool;
+}
+
+/* Returns a reference to the hash table containing data type.
+   This function ensures that the hash table is created.  */
+
+static hash_table <ubsan_typedesc_hasher> &
+get_typedesc_hash_table ()
+{
+  if (!ubsan_typedesc_ht.is_created ())
+    ubsan_typedesc_ht.create (10);
+
+  return ubsan_typedesc_ht;
+}
+
+/* Allocates memory for an instance of ubsan_typedesc into the memory
+   pool returned by ubsan_typedesc_get_alloc_pool and initialize it.
+   TYPE describes a particular type, DECL is its VAR_DECL.  */
+
+static ubsan_typedesc *
+ubsan_typedesc_new (tree type, tree decl)
+{
+  ubsan_typedesc *desc =
+    (ubsan_typedesc *) pool_alloc (ubsan_typedesc_get_alloc_pool ());
+
+  ubsan_typedesc_init (desc, type, decl);
+  return desc;
+}
+
+/* Clear all entries from the type descriptor hash table.  */
+
+static void
+empty_ubsan_typedesc_hash_table ()
+{
+  // XXX But when do we call this?
+  if (ubsan_typedesc_ht.is_created ())
+    ubsan_typedesc_ht.empty ();
+}
+
+/* Build the ubsan uptr type.  */
+
+static tree
+uptr_type (void)
+{
+  return build_nonstandard_integer_type (POINTER_SIZE, 1);
+}
+
+/* Helper routine, which encodes a value in the uptr type.
+   Arguments with precision <= POINTER_SIZE are passed directly,
+   the rest is passed by reference.  T is a value we are to encode.  */
+
+static tree
+ubsan_encode_value (tree t)
+{
+  tree type = TREE_TYPE (t);
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+      if (TYPE_PRECISION (type) <= POINTER_SIZE)
+	return fold_build1 (NOP_EXPR, uptr_type (), 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 (uptr_type (), 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 ();
+    }
+}
+
+/* Build
+   struct __ubsan_type_descriptor
+   {
+     unsigned short __typekind;
+     unsigned short __typeinfo;
+     char __typename[];
+   }
+   type.  */
+
+static tree
+ubsan_type_descriptor_type (void)
+{
+  static const char *field_names[3]
+    = { "__typekind", "__typeinfo", "__typename" };
+  tree fields[3], ret;
+  tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
+  tree flex_arr_type = build_array_type (char_type_node, itype);
+
+  ret = make_node (RECORD_TYPE);
+  for (int i = 0; i < 3; i++)
+    {
+      fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+			      get_identifier (field_names[i]),
+			      (i == 2) ? flex_arr_type
+			      : short_unsigned_type_node);
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = get_identifier ("__ubsan_type_descriptor");
+  layout_type (ret);
+  return ret;
+}
+
+/* Build
+   struct __ubsan_source_location
+   {
+     const char *__filename;
+     unsigned int __line;
+     unsigned int __column;
+   }
+   type.  */
+
+static tree
+ubsan_source_location_type (void)
+{
+  static const char *field_names[3]
+    = { "__filename", "__line", "__column" };
+  tree fields[3], ret;
+
+  ret = make_node (RECORD_TYPE);
+  for (int i = 0; i < 3; i++)
+    {
+      fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+			      get_identifier (field_names[i]),
+			      (i == 0) ? const_string_type_node
+			      : unsigned_type_node);
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = get_identifier ("__ubsan_source_location");
+  layout_type (ret);
+  return ret;
+}
+
+/* Helper routine that returns a CONSTRUCTOR of __ubsan_source_location
+   type with its fields filled from a location_t LOC.  */
+
+static tree
+ubsan_source_location (location_t loc)
+{
+  expanded_location xloc;
+  tree type = ubsan_source_location_type ();
+  vec<constructor_elt, va_gc> *v;
+
+  xloc = expand_location (loc);
+
+  /* Fill in the values from LOC.  */
+  vec_alloc (v, 3);
+  tree ctor = build_constructor (type, v);
+  size_t len = strlen (xloc.file);
+  tree str = build_string (len + 1, xloc.file);
+  TREE_TYPE (str) = build_array_type (char_type_node,
+				      build_index_type (size_int (len)));
+  TREE_READONLY (str) = 1;
+  TREE_STATIC (str) = 1;
+  str = build_fold_addr_expr_loc (loc, str);
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, str);
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (unsigned_type_node,
+						       xloc.line));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (unsigned_type_node,
+						       xloc.column));
+  TREE_CONSTANT (ctor) = 1;
+  TREE_STATIC (ctor) = 1;
+
+  return ctor;
+}
+
+/* This routine returns a magic number for TYPE.
+   ??? This is probably too ugly.  Tweak it.  */
+
+static unsigned short
+get_tinfo_for_type (tree type)
+{
+  unsigned short tinfo;
+
+  switch (GET_MODE_SIZE (TYPE_MODE (type)))
+    {
+    case 4:
+      tinfo = 5;
+      break;
+    case 8:
+      tinfo = 6;
+      break;
+    case 16:
+      tinfo = 7;
+      break;
+    default:
+      error ("unexpected size of type %qT", type);
+    }
+
+  tinfo <<= 1;
+
+  /* The MSB here says whether the value is signed or not.  */
+  tinfo |= !TYPE_UNSIGNED (type);
+  return tinfo;
+}
+
+/* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
+   descriptor.  It first looks into the hash table; if not found,
+   create the VAR_DECL, put it into the hash table and return the
+   ADDR_EXPR of it.  TYPE describes a particular type.  */
+
+static tree
+ubsan_type_descriptor (tree type)
+{
+  hash_table <ubsan_typedesc_hasher> ht = get_typedesc_hash_table ();
+  ubsan_typedesc d;
+  ubsan_typedesc_init (&d, type, NULL);
+
+  ubsan_typedesc **slot = ht.find_slot (&d, INSERT);
+  if (*slot != NULL)
+    /* We have the VAR_DECL in the table.  Return it.  */
+    return (*slot)->decl;
+
+  tree dtype = ubsan_type_descriptor_type ();
+  vec<constructor_elt, va_gc> *v;
+  const char *tname;
+  unsigned short tkind, tinfo;
+
+  /* At least for INTEGER_TYPE/REAL_TYPE/COMPLEX_TYPE, this should work.
+     ??? For e.g. type_unsigned_for (type), the TYPE_NAME would be NULL.  */
+  if (TYPE_NAME (type) != NULL)
+    tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+  else
+    tname = "<unknown>";
+  if (TREE_CODE (type) == INTEGER_TYPE)
+    {
+      /* For INTEGER_TYPE, this is 0x0000.  */
+      tkind = 0x000;
+      tinfo = get_tinfo_for_type (type);
+    }
+  else if (TREE_CODE (type) == REAL_TYPE)
+    /* We don't have float support yet.  */
+    gcc_unreachable ();
+  else
+    gcc_unreachable ();
+
+  /* Create a new VAR_DECL of type descriptor.  */
+  char *tmp_name;
+  static unsigned int type_var_id_num;
+  ASM_FORMAT_PRIVATE_NAME (tmp_name, ".Lubsan_type", type_var_id_num++);
+  tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
+			  dtype);
+  TREE_STATIC (decl) = 1;
+  TREE_PUBLIC (decl) = 0;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  DECL_EXTERNAL (decl) = 0;
+
+  vec_alloc (v, 3);
+  tree ctor = build_constructor (dtype, v);
+  size_t len = strlen (tname);
+  tree str = build_string (len + 1, tname);
+  TREE_TYPE (str) = build_array_type (char_type_node,
+				      build_index_type (size_int (len)));
+  TREE_READONLY (str) = 1;
+  TREE_STATIC (str) = 1;
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (short_unsigned_type_node,
+						       tkind));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (short_unsigned_type_node,
+						       tinfo));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, str);
+
+  TREE_CONSTANT (ctor) = 1;
+  TREE_STATIC (ctor) = 1;
+  DECL_INITIAL (decl) = ctor;
+  rest_of_decl_compilation (decl, 1, 0);
+
+  /* Save the address of the VAR_DECL into the hash table.  */
+  decl = build_fold_addr_expr (decl);
+  *slot = ubsan_typedesc_new (type, decl);
+
+  return decl;
+}
+
+/* Create a structure for the ubsan library.  NAME is a name of the new
+   structure.  The arguments in ... are of __ubsan_type_descriptor type
+   and there are at most two of them.  */
+
+static tree
+ubsan_create_data (const char *name, location_t loc, ...)
+{
+  va_list args;
+  tree ret, t;
+  tree fields[3];
+  vec<tree, va_gc> *saved_args = NULL;
+  size_t i = 0;
+
+  /* Firstly, create a pointer to type descriptor type.  */
+  tree td_type = ubsan_type_descriptor_type ();
+  TYPE_READONLY (td_type) = 1;
+  td_type = build_pointer_type (td_type);
+
+  /* Create the structure type.  */
+  ret = make_node (RECORD_TYPE);
+  if (loc != UNKNOWN_LOCATION)
+    {
+      fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
+			      ubsan_source_location_type ());
+      DECL_CONTEXT (fields[i]) = ret;
+      i++;
+    }
+
+  va_start (args, loc);
+  for (t = va_arg (args, tree); t != NULL_TREE;
+       i++, t = va_arg (args, tree))
+    {
+      gcc_checking_assert (i < 3);
+      /* Save the tree argument for later use.  */
+      vec_safe_push (saved_args, t);
+      fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
+			      td_type);
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = get_identifier (name);
+  layout_type (ret);
+  va_end (args);
+
+  /* Now, fill in the type.  */
+  char *tmp_name;
+  static unsigned int ubsan_var_id_num;
+  ASM_FORMAT_PRIVATE_NAME (tmp_name, ".Lubsan_data", ubsan_var_id_num++);
+  tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
+			 ret);
+  TREE_STATIC (var) = 1;
+  TREE_PUBLIC (var) = 0;
+  DECL_ARTIFICIAL (var) = 1;
+  DECL_IGNORED_P (var) = 1;
+  DECL_EXTERNAL (var) = 0;
+
+  vec<constructor_elt, va_gc> *v;
+  vec_alloc (v, i);
+  tree ctor = build_constructor (ret, v);
+
+  /* If desirable, set the __ubsan_source_location element.  */
+  if (loc != UNKNOWN_LOCATION)
+    CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc));
+
+  size_t nelts = vec_safe_length (saved_args);
+  for (i = 0; i < nelts; i++)
+    {
+      t = (*saved_args)[i];
+      CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t);
+    }
+
+  TREE_CONSTANT (ctor) = 1;
+  TREE_STATIC (ctor) = 1;
+  DECL_INITIAL (var) = ctor;
+  rest_of_decl_compilation (var, 1, 0);
+
+  return var;
+}
+
 /* Instrument division by zero and INT_MIN / -1.  If not instrumenting,
    return NULL_TREE.  */
 
@@ -38,6 +488,7 @@  ubsan_instrument_division (location_t lo
      because they are already converted to RESULT_TYPE.  */
   gcc_assert (type == TREE_TYPE (op1));
 
+  /* TODO: REAL_TYPE is not supported yet.  */
   if (TREE_CODE (type) != INTEGER_TYPE)
     return NULL_TREE;
 
@@ -63,8 +514,13 @@  ubsan_instrument_division (location_t lo
       x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
       t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
     }
+  tree data = ubsan_create_data ("__ubsan_overflow_data",
+				 loc, ubsan_type_descriptor (type),
+				 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, 0);
+  tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
+			    ubsan_encode_value (op1));
   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
 
   return t;
@@ -78,10 +534,12 @@  ubsan_instrument_shift (location_t loc,
 			tree op0, tree op1)
 {
   tree t, tt = NULL_TREE;
-  tree op1_utype = unsigned_type_for (TREE_TYPE (op1));
-  HOST_WIDE_INT op0_prec = TYPE_PRECISION (TREE_TYPE (op0));
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  tree op1_utype = unsigned_type_for (type1);
+  HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
   tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);
-  tree precm1 = build_int_cst (TREE_TYPE (op1), op0_prec - 1);
+  tree precm1 = build_int_cst (type1, op0_prec - 1);
 
   t = fold_convert_loc (loc, op1_utype, op1);
   t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1);
@@ -90,11 +548,11 @@  ubsan_instrument_shift (location_t loc,
      (unsigned) x >> (precm1 - y)
      if non-zero, is undefined.  */
   if (code == LSHIFT_EXPR
-      && !TYPE_UNSIGNED (TREE_TYPE (op0))
+      && !TYPE_UNSIGNED (type0)
       && flag_isoc99)
     {
       tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1);
-      tt = fold_convert_loc (loc, unsigned_type_for (TREE_TYPE (op0)), op0);
+      tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
       tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
       tt = fold_build2 (NE_EXPR, boolean_type_node, tt,
 			build_int_cst (TREE_TYPE (tt), 0));
@@ -108,19 +566,25 @@  ubsan_instrument_shift (location_t loc,
       && (cxx_dialect == cxx11 || cxx_dialect == cxx1y))
     {
       tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1);
-      tt = fold_convert_loc (loc, unsigned_type_for (TREE_TYPE (op0)), op0);
+      tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
       tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
       tt = fold_build2 (GT_EXPR, boolean_type_node, tt,
 			build_int_cst (TREE_TYPE (tt), 1));
       x = fold_build2 (LT_EXPR, boolean_type_node, op0,
-		       build_int_cst (TREE_TYPE (op0), 0));
+		       build_int_cst (type0, 0));
       tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
     }
+  tree data = ubsan_create_data ("__ubsan_shift_data",
+				 loc, ubsan_type_descriptor (type0),
+				 ubsan_type_descriptor (type1), NULL_TREE);
+
+  data = build_fold_addr_expr_loc (loc, data);
 
   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, 0);
+  tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
+			    ubsan_encode_value (op1));
   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
 
   return t;