@@ -24,5 +24,6 @@ along with GCC; see the file COPYING3.
extern tree ubsan_instrument_division (location_t, tree, tree);
extern tree ubsan_instrument_shift (location_t, enum tree_code, tree, tree);
extern tree ubsan_instrument_vla (location_t, tree);
+extern tree ubsan_instrument_reference (location_t, tree);
#endif /* GCC_C_UBSAN_H */
@@ -179,3 +179,30 @@ ubsan_instrument_vla (location_t loc, tr
return t;
}
+
+/* Instrument reference binding, that is, ensure that the reference
+ declaration doesn't bind the reference to a NULL pointer. */
+
+tree
+ubsan_instrument_reference (location_t loc, tree init)
+{
+ if (!INDIRECT_REF_P (init))
+ /* This may happen, e.g. int &&r4 = p;, so don't put an assert here. */
+ return init;
+
+ init = TREE_OPERAND (init, 0);
+ tree eq_expr = fold_build2 (EQ_EXPR, boolean_type_node, init,
+ build_zero_cst (TREE_TYPE (init)));
+ const struct ubsan_mismatch_data m
+ = { build_zero_cst (pointer_sized_int_node),
+ build_int_cst (unsigned_char_type_node, UBSAN_REF_BINDING)};
+ tree data = ubsan_create_data ("__ubsan_null_data",
+ loc, &m,
+ ubsan_type_descriptor (TREE_TYPE (init),
+ true), NULL_TREE);
+ data = build_fold_addr_expr_loc (loc, data);
+ tree fn = builtin_decl_implicit (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH);
+ fn = build_call_expr_loc (loc, fn, 2, data,
+ build_zero_cst (pointer_sized_int_node));
+ return fold_build3 (COND_EXPR, void_type_node, eq_expr, fn, void_zero_node);
+}
@@ -6216,6 +6217,11 @@ cp_finish_decl (tree decl, tree init, bo
if (decl_maybe_constant_var_p (decl))
TREE_CONSTANT (decl) = 1;
}
+ if (flag_sanitize & SANITIZE_NULL
+ && TREE_CODE (type) == REFERENCE_TYPE)
+ init = fold_build2 (COMPOUND_EXPR, TREE_TYPE (init),
+ ubsan_instrument_reference (input_location, init),
+ init);
}
if (processing_template_decl)
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=null -w -std=c++11" } */
+
+typedef const long int L;
+
+int
+main (void)
+{
+ int *p = 0;
+ L *l = 0;
+
+ int &r = *p;
+ auto &r2 = *p;
+ L &lr = *l;
+
+ /* Try an rvalue reference. */
+ auto &&r3 = *p;
+}
+
+/* { dg-output "reference binding to null pointer of type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*reference binding to null pointer of type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*reference binding to null pointer of type 'const L'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*reference binding to null pointer of type 'int'(\n|\r\n|\r)" } */