From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 38962 invoked by alias); 6 Dec 2018 12:09:19 -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 38939 invoked by uid 89); 6 Dec 2018 12:09:18 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-10.9 required=5.0 tests=BAYES_00,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=sums, machine_mode, known_eq, 15AM X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 06 Dec 2018 12:09:16 +0000 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E944725EC0; Thu, 6 Dec 2018 12:09:14 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-117-214.ams2.redhat.com [10.36.117.214]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6BB7B101963E; Thu, 6 Dec 2018 12:09:14 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id wB6C9C8J020863; Thu, 6 Dec 2018 13:09:12 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id wB6C9Anc020862; Thu, 6 Dec 2018 13:09:10 +0100 Date: Thu, 06 Dec 2018 12:09:00 -0000 From: Jakub Jelinek To: Richard Biener Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] Fix VRP with -fno-delete-null-pointer-checks (PR c/88367, take 2) Message-ID: <20181206120909.GQ12380@tucnak> Reply-To: Jakub Jelinek References: <20181206064535.GN12380@tucnak> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.9.2 (2017-12-15) X-IsSubscribed: yes X-SW-Source: 2018-12/txt/msg00358.txt.bz2 On Thu, Dec 06, 2018 at 10:05:15AM +0100, Richard Biener wrote: > Note I wonder if with -fwrapv-pointer NULL automatically becomes a > valid address? Or is only wrapping around half of the address > space UB? Hadn't thought about -fwrapv-pointer, I guess we (especially with -fno-delete-null-pointer-checks) need to be even more conservative in that case. Furthermore, I've discovered that the ADDR_EXPR of MEM_REF case actually uses get_base_address and therefore the offset on MEM_REF is just one of the many possible offsets in the play. So, this patch punts for -fwrapv-pointer in some further cases, and adjusts the vr-values.c ADDR_EXPR handling code so that it sums up all 2 or 3 offsets together and looks at the resulting sign. If -fdelete-null-pointer-checks -fno-wrapv-pointer, it does what it did before in tree-vrp.c and in vr-values.c is even more aggressive than before, as in even if the base pointer is varying etc., if the sum of all the offsets is provably non-zero, the result is non-NULL. For -fno-delete-null-pointer-checks -fno-wrapv-pointer it does this only if the resulting offset is positive. Does this look ok? 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-06 11:19:24.170939864 +0100 +++ gcc/tree-vrp.c 2018-12-06 11:50:12.104711210 +0100 @@ -1673,9 +1673,26 @@ 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)) + && !TYPE_OVERFLOW_WRAPS (expr_type) + && (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-12-06 11:19:23.550950006 +0100 +++ gcc/vr-values.c 2018-12-06 12:59:28.269999920 +0100 @@ -297,14 +297,48 @@ vr_values::vrp_stmt_computes_nonzero (gi && gimple_assign_rhs_code (stmt) == ADDR_EXPR) { tree expr = gimple_assign_rhs1 (stmt); - tree base = get_base_address (TREE_OPERAND (expr, 0)); + poly_int64 bitsize, bitpos; + tree offset; + machine_mode mode; + int unsignedp, reversep, volatilep; + tree base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize, + &bitpos, &offset, &mode, &unsignedp, + &reversep, &volatilep); if (base != NULL_TREE && 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)) + poly_offset_int off = 0; + bool off_cst = false; + if (offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST) + { + off = mem_ref_offset (base); + if (offset) + off += poly_offset_int::from (wi::to_poly_wide (offset), + SIGNED); + off <<= LOG2_BITS_PER_UNIT; + off += bitpos; + off_cst = true; + } + /* If &X->a is equal to X and X is ~[0, 0], the result is too. + For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't + allow going from non-NULL pointer to NULL. */ + if ((off_cst && known_eq (off, 0)) + || (flag_delete_null_pointer_checks + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)))) + { + 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, for -fdelete-null-pointer-checks also "negative" + ones. Punt for unknown offsets (e.g. variable ones). */ + if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)) + && off_cst + && known_ne (off, 0) + && (flag_delete_null_pointer_checks || known_gt (off, 0))) return true; } } --- gcc/testsuite/gcc.dg/tree-ssa/pr88367.c.jj 2018-12-06 11:46:51.915985811 +0100 +++ gcc/testsuite/gcc.dg/tree-ssa/pr88367.c 2018-12-06 13:00:14.692248340 +0100 @@ -0,0 +1,31 @@ +/* PR c/88367 */ +/* { dg-do compile } */ +/* { dg-options "-fno-delete-null-pointer-checks -O2 -fdump-tree-optimized -fno-wrapv-pointer" } */ +/* { 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