On December 30, 2020 10:30:33 AM GMT+01:00, Jakub Jelinek <ja...@redhat.com> wrote: >Hi! > >The following testcase is diagnosed by UBSan as invalid, even when it >is >valid. >We have a derived type Base2 at offset 1 with alignment 1 and do: >(const Derived &) ((const Base2 *) this + -1) >but the folder before ubsan in the FE gets a chance to instrument it >optimizes that into: >(const Derived &) this + -1 >and so we require that this has 8-byte alignment which Derived class >needs. > >Fixed by avoiding such an optimization when -fsanitize=alignment is in >effect if it would affect the alignments (and guarded with >!in_gimple_form >because we don't really care during GIMPLE, though pointer conversions >are >useless then and so such folding isn't needed very much during GIMPLE). > >Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Ok. Richard. >2020-12-30 Jakub Jelinek <ja...@redhat.com> > > PR c++/98206 > * fold-const.c: Include asan.h. > (fold_unary_loc): Don't optimize (ptr_type) (((ptr_type2) x) p+ y) > into ((ptr_type) x) p+ y if sanitizing alignment in GENERIC and > ptr_type points to type with higher alignment than ptr_type2. > > * g++.dg/ubsan/align-4.C: New test. > >--- gcc/fold-const.c.jj 2020-12-21 10:14:39.409173804 +0100 >+++ gcc/fold-const.c 2020-12-29 15:40:34.283148245 +0100 >@@ -82,6 +82,7 @@ along with GCC; see the file COPYING3. > #include "attribs.h" > #include "tree-vector-builder.h" > #include "vec-perm-indices.h" >+#include "asan.h" > > /* Nonzero if we are folding constants inside an initializer; zero > otherwise. */ >@@ -9392,8 +9393,17 @@ fold_unary_loc (location_t loc, enum tre > tree arg00 = TREE_OPERAND (arg0, 0); > tree arg01 = TREE_OPERAND (arg0, 1); > >- return fold_build_pointer_plus_loc >- (loc, fold_convert_loc (loc, type, arg00), arg01); >+ /* If -fsanitize=alignment, avoid this optimization in GENERIC >+ when the pointed type needs higher alignment than >+ the p+ first operand's pointed type. */ >+ if (!in_gimple_form >+ && sanitize_flags_p (SANITIZE_ALIGNMENT) >+ && (min_align_of_type (TREE_TYPE (type)) >+ > min_align_of_type (TREE_TYPE (TREE_TYPE (arg00))))) >+ return NULL_TREE; >+ >+ arg00 = fold_convert_loc (loc, type, arg00); >+ return fold_build_pointer_plus_loc (loc, arg00, arg01); > } > > /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types >--- gcc/testsuite/g++.dg/ubsan/align-4.C.jj 2020-12-29 >15:28:11.811501092 +0100 >+++ gcc/testsuite/g++.dg/ubsan/align-4.C 2020-12-29 15:29:54.198348346 >+0100 >@@ -0,0 +1,31 @@ >+// PR c++/98206 >+// { dg-do run } >+// { dg-options "-fsanitize=alignment -std=c++11 >-fno-sanitize-recover=alignment" } >+ >+template <typename Derived> >+struct Base1 >+{ >+ char c1; >+}; >+ >+template <typename Derived> >+struct Base2 >+{ >+ char c2; >+ const Derived &get2 () const { return static_cast<const Derived &> >(*this); } >+}; >+ >+struct X : public Base1<X>, public Base2<X> >+{ >+ X (const char *d) : data{d} {} >+ const char *data; >+}; >+ >+int >+main () >+{ >+ X x = X{"cheesecake"}; >+ const char *p = x.get2 ().data; >+ if (p[0] != 'c') >+ __builtin_abort (); >+} > > Jakub