From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 48987 invoked by alias); 6 Dec 2018 09:05:22 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 48967 invoked by uid 89); 6 Dec 2018 09:05:21 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-11.9 required=5.0 tests=BAYES_00,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 06 Dec 2018 09:05:17 +0000 Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 73270AC3E; Thu, 6 Dec 2018 09:05:15 +0000 (UTC) Date: Thu, 06 Dec 2018 09:05:00 -0000 From: Richard Biener To: Jakub Jelinek cc: gcc-patches@gcc.gnu.org Subject: Re: [PATCH] Fix VRP with -fno-delete-null-pointer-checks (PR c/88367) In-Reply-To: <20181206064535.GN12380@tucnak> Message-ID: References: <20181206064535.GN12380@tucnak> User-Agent: Alpine 2.20 (LSU 67 2015-01-07) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-SW-Source: 2018-12/txt/msg00347.txt.bz2 On Thu, 6 Dec 2018, Jakub Jelinek wrote: > Hi! > > If we consider -fno-delete-null-pointer-checks as a way to support e.g. AVR > and other targets which can validly place objects at NULL rather than a way > to workaround UBs in code, I believe the following testcase must pass if > there is e.g. > char a[32]; // And this object ends up at address 0 > void bar (void); > int main () { foo (&a[3]); baz (&a[6]); } > but fails right now. As mentioned in the PR, in GCC 8 we used to do: > else if (code == POINTER_PLUS_EXPR) > { > /* For pointer types, we are really only interested in asserting > whether the expression evaluates to non-NULL. */ > if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1)) > set_value_range_to_nonnull (vr, expr_type); > and that triggered pretty much never, as range_is_nonnull requires that the > offset is ~[0, 0] exactly, e.g. if it is a constant, it is never that way, > but now we do: > if (!range_includes_zero_p (&vr0) || !range_includes_zero_p (&vr1)) > which is e.g. always if the offset is constant non-zero. > > I hope we can still say that pointer wrapping even with > -fno-delete-null-pointer-checks is UB, so this patch differentiates between > positive offsets (in ssizetype), negative offsets (in ssizetype) and zero > offsets and handles both the same for both ptr p+ offset and &MEM_REF[ptr, offset] > If offset is 0 and ptr is ~[0, 0], then the result is ~[0, 0] as before. > If offset is positive in ssizetype, then even for VARYING ptr the result is > ~[0, 0] pointer. If the offset is (or maybe could be) negative in > ssizetype, then for -fno-delete-null-pointer-checks the result is VARYING, > as we could go from a non-NULL pointer back to NULL on those targets; for > -fdelete-null-pointer-checks we do what we've done before, i.e. ~[0, 0]. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? OK. Note I wonder if with -fwrapv-pointer NULL automatically becomes a valid address? Or is only wrapping around half of the address space UB? Richard. > 2018-12-06 Jakub Jelinek > > PR c/88367 > * tree-vrp.c (extract_range_from_binary_expr): For POINTER_PLUS_EXPR > with -fno-delete-null-pointer-checks, set_nonnull only if the pointer > is non-NULL and offset is known to have most significant bit clear. > * vr-values.c (vr_values::vrp_stmt_computes_nonzero): For ADDR_EXPR > of MEM_EXPR, return true if the MEM_EXPR has non-zero offset with > most significant bit clear. If offset does have most significant bit > set and -fno-delete-null-pointer-checks, don't return true even if > the base pointer is non-NULL. > > * gcc.dg/tree-ssa/pr88367.c: New test. > > --- gcc/tree-vrp.c.jj 2018-12-04 13:00:02.408635579 +0100 > +++ gcc/tree-vrp.c 2018-12-05 19:07:36.187567781 +0100 > @@ -1673,9 +1673,25 @@ extract_range_from_binary_expr (value_ra > else if (code == POINTER_PLUS_EXPR) > { > /* For pointer types, we are really only interested in asserting > - whether the expression evaluates to non-NULL. */ > - if (!range_includes_zero_p (&vr0) > - || !range_includes_zero_p (&vr1)) > + whether the expression evaluates to non-NULL. > + With -fno-delete-null-pointer-checks we need to be more > + conservative. As some object might reside at address 0, > + then some offset could be added to it and the same offset > + subtracted again and the result would be NULL. > + E.g. > + static int a[12]; where &a[0] is NULL and > + ptr = &a[6]; > + ptr -= 6; > + ptr will be NULL here, even when there is POINTER_PLUS_EXPR > + where the first range doesn't include zero and the second one > + doesn't either. As the second operand is sizetype (unsigned), > + consider all ranges where the MSB could be set as possible > + subtractions where the result might be NULL. */ > + if ((!range_includes_zero_p (&vr0) > + || !range_includes_zero_p (&vr1)) > + && (flag_delete_null_pointer_checks > + || (range_int_cst_p (&vr1) > + && !tree_int_cst_sign_bit (vr1.max ())))) > vr->set_nonnull (expr_type); > else if (range_is_null (&vr0) && range_is_null (&vr1)) > vr->set_null (expr_type); > --- gcc/vr-values.c.jj 2018-11-29 08:41:33.152749436 +0100 > +++ gcc/vr-values.c 2018-12-05 19:37:56.222582823 +0100 > @@ -303,8 +303,17 @@ vr_values::vrp_stmt_computes_nonzero (gi > && TREE_CODE (base) == MEM_REF > && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) > { > - value_range *vr = get_value_range (TREE_OPERAND (base, 0)); > - if (!range_includes_zero_p (vr)) > + if (integer_zerop (TREE_OPERAND (base, 1)) > + || flag_delete_null_pointer_checks) > + { > + value_range *vr = get_value_range (TREE_OPERAND (base, 0)); > + if (!range_includes_zero_p (vr)) > + return true; > + } > + /* If MEM_REF has a "positive" offset, consider it non-NULL > + always. */ > + if (integer_nonzerop (TREE_OPERAND (base, 1)) > + && !tree_int_cst_sign_bit (TREE_OPERAND (base, 1))) > return true; > } > } > --- gcc/testsuite/gcc.dg/tree-ssa/pr88367.c.jj 2018-12-05 19:24:36.386727781 +0100 > +++ gcc/testsuite/gcc.dg/tree-ssa/pr88367.c 2018-12-05 19:40:43.228839763 +0100 > @@ -0,0 +1,31 @@ > +/* PR c/88367 */ > +/* { dg-do compile } */ > +/* { dg-options "-fno-delete-null-pointer-checks -O2 -fdump-tree-optimized" } */ > +/* { dg-final { scan-tree-dump-not "link_error \\(\\);" "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "bar \\(\\);" 2 "optimized" } } */ > + > +void bar (void); > +void link_error (void); > + > +void > +foo (char *p) > +{ > + if (!p) > + return; > + p += 3; > + if (!p) > + link_error (); > + p -= 6; > + if (!p) > + bar (); > +} > + > +void > +baz (char *p) > +{ > + if (!p) > + return; > + p -= 6; > + if (!p) > + bar (); > +} > > Jakub > > -- Richard Biener SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)