Hi! As the testcase shows, if there is a reinterpret_cast, ubsan reference instrumentation can ICE, because for NOP_EXPR to REFERENCE_TYPE we pass argument of that NOP_EXPR, and if it is not a POINTER_TYPE or POINTER_TYPE to a different type, we can get the type to use in the diagnostics wrong or ICE.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2014-11-18 Jakub Jelinek <ja...@redhat.com> PR sanitizer/63813 * c-ubsan.c (ubsan_maybe_instrument_reference_or_call): Change type argument to ptype, set type to TREE_TYPE (ptype). Don't call get_pointer_alignment for non-pointers. Use ptype, or if it is reference type, corresponding pointer type, as type of kind argument. (ubsan_maybe_instrument_reference, ubsan_maybe_instrument_member_call): Adjust callers. * g++.dg/ubsan/pr63813.C: New test. --- gcc/c-family/c-ubsan.c.jj 2014-10-29 09:49:47.000000000 +0100 +++ gcc/c-family/c-ubsan.c 2014-11-18 12:31:42.700607456 +0100 @@ -383,18 +383,19 @@ ubsan_maybe_instrument_array_ref (tree * } static tree -ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree type, +ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype, enum ubsan_null_ckind ckind) { - tree orig_op = op; - bool instrument = false; - unsigned int mina = 0; - if (current_function_decl == NULL_TREE || lookup_attribute ("no_sanitize_undefined", DECL_ATTRIBUTES (current_function_decl))) return NULL_TREE; + tree type = TREE_TYPE (ptype); + tree orig_op = op; + bool instrument = false; + unsigned int mina = 0; + if (flag_sanitize & SANITIZE_ALIGNMENT) { mina = min_align_of_type (type); @@ -431,13 +432,20 @@ ubsan_maybe_instrument_reference_or_call } else if (flag_sanitize & SANITIZE_NULL) instrument = true; - if (mina && mina > get_pointer_alignment (op) / BITS_PER_UNIT) - instrument = true; + if (mina && mina > 1) + { + if (!POINTER_TYPE_P (TREE_TYPE (op)) + || mina > get_pointer_alignment (op) / BITS_PER_UNIT) + instrument = true; + } } if (!instrument) return NULL_TREE; op = save_expr (orig_op); - tree kind = build_int_cst (TREE_TYPE (op), ckind); + 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, @@ -453,7 +461,7 @@ ubsan_maybe_instrument_reference (tree s { tree op = TREE_OPERAND (stmt, 0); op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op, - TREE_TYPE (TREE_TYPE (stmt)), + TREE_TYPE (stmt), UBSAN_REF_BINDING); if (op) TREE_OPERAND (stmt, 0) = op; @@ -471,7 +479,7 @@ ubsan_maybe_instrument_member_call (tree || !POINTER_TYPE_P (TREE_TYPE (op))) return; op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op, - TREE_TYPE (TREE_TYPE (op)), + TREE_TYPE (op), is_ctor ? UBSAN_CTOR_CALL : UBSAN_MEMBER_CALL); if (op) --- gcc/testsuite/g++.dg/ubsan/pr63813.C.jj 2014-11-18 12:37:57.790991586 +0100 +++ gcc/testsuite/g++.dg/ubsan/pr63813.C 2014-11-18 12:50:58.723345975 +0100 @@ -0,0 +1,12 @@ +// PR sanitizer/63813 +// { dg-do compile } +// { dg-options "-fsanitize=undefined -O1" } + +struct A {}; +struct B { long foo () const; A &bar () const; }; + +A & +B::bar () const +{ + return *reinterpret_cast <A *> (foo ()); +} Jakub