@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tm.h"
#include "c-family/c-common.h"
+#include "tree-iterator.h"
#include "ubsan.h"
#include "c-family/c-ubsan.h"
#include "stor-layout.h"
@@ -398,22 +399,15 @@ ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one)
}
}
-static tree
-ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
- enum ubsan_null_ckind ckind)
+static bool
+ubsan_should_instrument_reference_or_call (tree op, tree ptype,
+ unsigned int &mina)
{
- if (!sanitize_flags_p (SANITIZE_ALIGNMENT | SANITIZE_NULL)
- || current_function_decl == NULL_TREE)
- return NULL_TREE;
-
- tree type = TREE_TYPE (ptype);
- tree orig_op = op;
bool instrument = false;
- unsigned int mina = 0;
if (sanitize_flags_p (SANITIZE_ALIGNMENT))
{
- mina = min_align_of_type (type);
+ mina = min_align_of_type (TREE_TYPE (ptype));
if (mina <= 1)
mina = 0;
}
@@ -454,19 +448,68 @@ ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
instrument = true;
}
}
- if (!instrument)
+ return instrument;
+}
+
+static tree
+ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
+ enum ubsan_null_ckind ckind,
+ bool use_save_expr, tree *stmt_p,
+ tree *copied_call)
+{
+ if (!sanitize_flags_p (SANITIZE_ALIGNMENT | SANITIZE_NULL)
+ || current_function_decl == NULL_TREE)
return NULL_TREE;
- op = save_expr (orig_op);
+
+ unsigned int mina = 0;
+ if (!ubsan_should_instrument_reference_or_call (op, ptype, mina))
+ return NULL_TREE;
+
gcc_assert (POINTER_TYPE_P (ptype));
if (TREE_CODE (ptype) == REFERENCE_TYPE)
ptype = build_pointer_type (TREE_TYPE (ptype));
tree kind = build_int_cst (ptype, ckind);
tree align = build_int_cst (pointer_sized_int_node, mina);
- tree call
- = build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node,
- 3, op, kind, align);
- TREE_SIDE_EFFECTS (call) = 1;
- return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
+
+ if (use_save_expr)
+ {
+ op = save_expr (op);
+ tree call = build_call_expr_internal_loc (
+ loc, IFN_UBSAN_NULL, void_type_node, 3, op, kind, align);
+ TREE_SIDE_EFFECTS (call) = 1;
+ return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
+ }
+ else
+ {
+ tree stmt = *stmt_p;
+ tree var
+ = build_decl (EXPR_LOCATION (stmt), VAR_DECL, NULL, ptr_type_node);
+ DECL_ARTIFICIAL (var) = 1;
+ DECL_IGNORED_P (var) = 1;
+ DECL_NAMELESS (var) = 1;
+ TREE_READONLY (var) = 0;
+ DECL_EXTERNAL (var) = 0;
+ TREE_STATIC (var) = 0;
+
+ tree exprs = NULL_TREE;
+
+ tree modify_expr
+ = build2 (MODIFY_EXPR, ptr_type_node, var, CALL_EXPR_ARG (stmt, 0));
+ append_to_statement_list (modify_expr, &exprs);
+
+ tree sanitize_expr = build_call_expr_internal_loc (
+ loc, IFN_UBSAN_NULL, void_type_node, 3, var, kind, align);
+ append_to_statement_list (sanitize_expr, &exprs);
+
+ tree call_expr = copy_node (stmt);
+ CALL_EXPR_ARG (call_expr, 0) = var;
+ *copied_call = call_expr;
+ append_to_statement_list (call_expr, &exprs);
+
+ tree bind = build3 (BIND_EXPR, void_type_node, var, exprs, NULL);
+ TREE_SIDE_EFFECTS (bind) = 1;
+ return bind;
+ }
}
/* Instrument a NOP_EXPR to REFERENCE_TYPE or INTEGER_CST with REFERENCE_TYPE
@@ -481,7 +524,8 @@ ubsan_maybe_instrument_reference (tree *stmt_p)
op = TREE_OPERAND (stmt, 0);
op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
TREE_TYPE (stmt),
- UBSAN_REF_BINDING);
+ UBSAN_REF_BINDING, true,
+ stmt_p, NULL);
if (op)
{
if (TREE_CODE (stmt) == NOP_EXPR)
@@ -493,19 +537,28 @@ ubsan_maybe_instrument_reference (tree *stmt_p)
/* Instrument a CALL_EXPR to a method if needed. */
-void
-ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor)
+tree
+ubsan_maybe_instrument_member_call (tree *stmt_p, bool is_ctor, bool is_dtor)
{
+ tree stmt = *stmt_p;
if (call_expr_nargs (stmt) == 0)
- return;
+ return NULL_TREE;
tree op = CALL_EXPR_ARG (stmt, 0);
- if (op == error_mark_node
- || !POINTER_TYPE_P (TREE_TYPE (op)))
- return;
- op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
- TREE_TYPE (op),
- is_ctor ? UBSAN_CTOR_CALL
- : UBSAN_MEMBER_CALL);
+ if (op == error_mark_node || !POINTER_TYPE_P (TREE_TYPE (op)))
+ return NULL_TREE;
+ tree node;
+ op = ubsan_maybe_instrument_reference_or_call (
+ EXPR_LOCATION (stmt), op, TREE_TYPE (op),
+ is_ctor ? UBSAN_CTOR_CALL : UBSAN_MEMBER_CALL, !is_dtor, stmt_p, &node);
if (op)
- CALL_EXPR_ARG (stmt, 0) = op;
+ {
+ if (!is_dtor)
+ CALL_EXPR_ARG (stmt, 0) = op;
+ else
+ {
+ *stmt_p = op;
+ return node;
+ }
+ }
+ return NULL_TREE;
}
@@ -29,6 +29,6 @@ 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_member_call (tree, bool);
+extern tree ubsan_maybe_instrument_member_call (tree *, bool, bool);
#endif /* GCC_C_UBSAN_H */
@@ -824,6 +824,7 @@ omp_cxx_notice_variable (struct cp_genericize_omp_taskreg *omp_ctx, tree decl)
struct cp_genericize_data
{
hash_set<tree> *p_set;
+ hash_set<tree> *instrumented_dtor_set;
auto_vec<tree> bind_expr_stack;
struct cp_genericize_omp_taskreg *omp_ctx;
tree try_block;
@@ -1435,12 +1436,25 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
&& INDIRECT_TYPE_P (TREE_TYPE (fn))
&& TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) == METHOD_TYPE)
{
+ bool is_func
+ = TREE_CODE (fn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL;
bool is_ctor
- = TREE_CODE (fn) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
- && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0));
- if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT))
- ubsan_maybe_instrument_member_call (stmt, is_ctor);
+ = is_func && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0));
+ bool is_dtor
+ = is_func && DECL_DESTRUCTOR_P (TREE_OPERAND (fn, 0));
+ tree node;
+ if (!wtd->instrumented_dtor_set->contains (stmt)
+ && sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT)
+ && (node = ubsan_maybe_instrument_member_call (stmt_p,
+ is_ctor,
+ is_dtor)))
+ {
+ wtd->instrumented_dtor_set->add (node);
+ tree result = cp_genericize_r (stmt_p, walk_subtrees, data);
+ wtd->instrumented_dtor_set->remove (node);
+ return result;
+ }
if (sanitize_flags_p (SANITIZE_VPTR) && !is_ctor)
cp_ubsan_maybe_instrument_member_call (stmt);
}
@@ -1592,6 +1606,7 @@ cp_genericize_tree (tree* t_p, bool handle_invisiref_parm_p)
struct cp_genericize_data wtd;
wtd.p_set = new hash_set<tree>;
+ wtd.instrumented_dtor_set = new hash_set<tree>;
wtd.bind_expr_stack.create (0);
wtd.omp_ctx = NULL;
wtd.try_block = NULL_TREE;
@@ -1599,6 +1614,7 @@ cp_genericize_tree (tree* t_p, bool handle_invisiref_parm_p)
wtd.handle_invisiref_parm_p = handle_invisiref_parm_p;
cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
delete wtd.p_set;
+ delete wtd.instrumented_dtor_set;
if (sanitize_flags_p (SANITIZE_VPTR))
cp_ubsan_instrument_member_accesses (t_p);
}
new file mode 100644
@@ -0,0 +1,79 @@
+// { dg-do run }
+// { dg-options "-fsanitize=undefined -Wall -Werror -std=c++20" }
+#if __has_include(<coroutine>)
+#include <coroutine>
+#elif defined(__clang__) && __has_include(<experimental/coroutine>)
+#include <experimental/coroutine>
+namespace std
+{
+using namespace experimental;
+}
+#endif
+#include <utility>
+
+struct coro
+{
+ struct promise_type
+ {
+ coro
+ get_return_object ()
+ {
+ return {};
+ }
+
+ std::suspend_never
+ initial_suspend () noexcept
+ {
+ return {};
+ }
+
+ std::suspend_never
+ final_suspend () noexcept
+ {
+ return {};
+ }
+
+ void
+ unhandled_exception () {}
+
+ void
+ return_void () {}
+ };
+
+ bool
+ await_ready ()
+ {
+ return true;
+ }
+
+ void
+ await_resume () {}
+
+ template <typename U>
+ void
+ await_suspend (U &) {}
+};
+
+struct b
+{
+ ~b () {}
+};
+
+struct a
+{
+ a (b) {}
+ ~a () {}
+};
+
+coro
+f (b obj)
+{
+ auto obj2 = a{ obj };
+ co_return;
+}
+
+int
+main ()
+{
+ f ({});
+}