Hi!

Since late C++ folding has been committed, we don't sanitize some reference
bindings to NULL.  Earlier we had always NOP_EXPR to REFERENCE_TYPE say from
INTEGER_CST or whatever else, but cp_fold can now turn that right into
INTEGER_CST with REFERENCE_TYPE.  The following patch sanitizes even those.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2017-03-23  Jakub Jelinek  <ja...@redhat.com>

        PR c++/79572
        * c-ubsan.h (ubsan_maybe_instrument_reference): Change argument to
        tree *.
        * c-ubsan.c (ubsan_maybe_instrument_reference): Likewise.  Handle
        not just NOP_EXPR to REFERENCE_TYPE, but also INTEGER_CST with
        REFERENCE_TYPE.

        * cp-gimplify.c (cp_genericize_r): Sanitize INTEGER_CSTs with
        REFERENCE_TYPE.  Adjust ubsan_maybe_instrument_reference caller
        for NOP_EXPR to REFERENCE_TYPE.

        * g++.dg/ubsan/null-8.C: New test.

--- gcc/c-family/c-ubsan.h.jj   2017-01-01 12:45:46.000000000 +0100
+++ gcc/c-family/c-ubsan.h      2017-03-23 09:13:16.287888726 +0100
@@ -28,7 +28,7 @@ extern tree ubsan_instrument_return (loc
 extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
 extern bool ubsan_array_ref_instrumented_p (const_tree);
 extern void ubsan_maybe_instrument_array_ref (tree *, bool);
-extern void ubsan_maybe_instrument_reference (tree);
+extern void ubsan_maybe_instrument_reference (tree *);
 extern void ubsan_maybe_instrument_member_call (tree, bool);
 
 /* Declare this here as well as in ubsan.h. */
--- gcc/c-family/c-ubsan.c.jj   2017-01-01 12:45:46.000000000 +0100
+++ gcc/c-family/c-ubsan.c      2017-03-23 09:18:51.775486699 +0100
@@ -458,17 +458,26 @@ ubsan_maybe_instrument_reference_or_call
   return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
 }
 
-/* Instrument a NOP_EXPR to REFERENCE_TYPE if needed.  */
+/* Instrument a NOP_EXPR to REFERENCE_TYPE or INTEGER_CST with REFERENCE_TYPE
+   type if needed.  */
 
 void
-ubsan_maybe_instrument_reference (tree stmt)
+ubsan_maybe_instrument_reference (tree *stmt_p)
 {
-  tree op = TREE_OPERAND (stmt, 0);
+  tree stmt = *stmt_p;
+  tree op = stmt;
+  if (TREE_CODE (stmt) == NOP_EXPR)
+    op = TREE_OPERAND (stmt, 0);
   op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
                                                 TREE_TYPE (stmt),
                                                 UBSAN_REF_BINDING);
   if (op)
-    TREE_OPERAND (stmt, 0) = op;
+    {
+      if (TREE_CODE (stmt) == NOP_EXPR) 
+       TREE_OPERAND (stmt, 0) = op;
+      else
+       *stmt_p = op;
+    }
 }
 
 /* Instrument a CALL_EXPR to a method if needed.  */
--- gcc/cp/cp-gimplify.c.jj     2017-03-03 13:23:58.000000000 +0100
+++ gcc/cp/cp-gimplify.c        2017-03-23 09:21:26.693460888 +0100
@@ -1130,6 +1130,19 @@ cp_genericize_r (tree *stmt_p, int *walk
        }
     }
 
+  if (TREE_CODE (stmt) == INTEGER_CST
+      && TREE_CODE (TREE_TYPE (stmt)) == REFERENCE_TYPE
+      && (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
+      && !wtd->no_sanitize_p)
+    {
+      ubsan_maybe_instrument_reference (stmt_p);
+      if (*stmt_p != stmt)
+       {
+         *walk_subtrees = 0;
+         return NULL_TREE;
+       }
+    }
+
   /* Other than invisiref parms, don't walk the same tree twice.  */
   if (p_set->contains (stmt))
     {
@@ -1477,7 +1490,7 @@ cp_genericize_r (tree *stmt_p, int *walk
       if ((flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
          && TREE_CODE (stmt) == NOP_EXPR
          && TREE_CODE (TREE_TYPE (stmt)) == REFERENCE_TYPE)
-       ubsan_maybe_instrument_reference (stmt);
+       ubsan_maybe_instrument_reference (stmt_p);
       else if (TREE_CODE (stmt) == CALL_EXPR)
        {
          tree fn = CALL_EXPR_FN (stmt);
--- gcc/testsuite/g++.dg/ubsan/null-8.C.jj      2017-03-23 09:42:31.664696676 
+0100
+++ gcc/testsuite/g++.dg/ubsan/null-8.C 2017-03-23 09:43:31.501908802 +0100
@@ -0,0 +1,19 @@
+// PR c++/79572
+// { dg-do run }
+// { dg-options "-fsanitize=null -std=c++14" }
+// { dg-output "reference binding to null pointer of type 'const int'" }
+
+void
+foo (const int &iref)
+{
+  if (&iref)
+    __builtin_printf ("iref %d\n", iref);
+  else
+    __builtin_printf ("iref is NULL\n");
+}
+
+int
+main ()
+{
+  foo (*((int*) __null));
+}

        Jakub

Reply via email to