From patchwork Thu Nov 20 17:14:52 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 412824 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 15D16140170 for ; Fri, 21 Nov 2014 04:15:11 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=pIrX0XR9QZzHKg1RKIWf8rvfH8S2/7BxjajMi6tTclFYvDvzCYHOt HWocxdBZj0AIjmuj74xfq1EC3+IBmW0GNqqTNjVS8l/zTnniSx8oyKjDV0vF9pYG D8RkGvqpbTfNIz9I4OrI4PkFKven9dNLFExFe6F9mokjP+kEDk+o2g= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=rZ2zwGMGZIbHKrs5D6BYZV/O+DA=; b=x0mJZ44JkNPehB82pegF 9Khvtgwl5uO++rsWeLB7AjmZI2CYU0Pa0ChlshTTc9PSxl5GE6wtp56LOQuZHjCk IQszwVDN65LrHb91g0kTJZPRAjImcuJKTXRt6pBCuXwOmmaKa51/EPhVRdT9s1r6 MTOLB0GJQjJfcw6Vy8g/MOs= Received: (qmail 6032 invoked by alias); 20 Nov 2014 17:15:00 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 5892 invoked by uid 89); 20 Nov 2014 17:14:59 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.4 required=5.0 tests=AWL, BAYES_00, FUZZY_PRICES, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 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 (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 20 Nov 2014 17:14:58 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sAKHEuvp022642 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Thu, 20 Nov 2014 12:14:56 -0500 Received: from redhat.com (ovpn-116-21.ams2.redhat.com [10.36.116.21]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sAKHEq2d025021 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=NO); Thu, 20 Nov 2014 12:14:55 -0500 Date: Thu, 20 Nov 2014 18:14:52 +0100 From: Marek Polacek To: Jakub Jelinek , GCC Patches , Jason Merrill Subject: [PATCH] Fix ubsan and C++14 constexpr ICEs (PR sanitizer/63956) Message-ID: <20141120171452.GG29446@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) This patch fixes a bunch of ICEs related to C++14 constexprs and -fsanitize=undefined. We should ignore ubsan internal functions and ubsan builtins in constexpr functions in cxx_eval_call_expression. Also add proper printing of internal functions into the C++ printer. Bootstrapped/regtested on ppc64-linux, ok for trunk? 2014-11-20 Marek Polacek PR sanitizer/63956 * constexpr.c: Include ubsan.h. (cxx_eval_call_expression): Bail out for IFN_UBSAN_{NULL,BOUNDS} internal functions and for ubsan builtins in constexpr functions. * error.c: Include internal-fn.h. (dump_expr): Add printing of internal functions. * g++.dg/ubsan/pr63956.C: New test. Marek diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index 2678223..684e36f 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "builtins.h" #include "tree-inline.h" +#include "ubsan.h" static bool verify_constant (tree, bool, bool *, bool *); #define VERIFY_CONSTANT(X) \ @@ -1151,6 +1152,16 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, constexpr_call *entry; bool depth_ok; + if (fun == NULL_TREE) + switch (CALL_EXPR_IFN (t)) + { + case IFN_UBSAN_NULL: + case IFN_UBSAN_BOUNDS: + return void_node; + default: + break; + } + if (TREE_CODE (fun) != FUNCTION_DECL) { /* Might be a constexpr function pointer. */ @@ -1171,6 +1182,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } if (DECL_CLONED_FUNCTION_P (fun)) fun = DECL_CLONED_FUNCTION (fun); + + if (!current_function_decl && is_ubsan_builtin_p (fun)) + return void_node; + if (is_builtin_fn (fun)) return cxx_eval_builtin_function_call (ctx, t, addr, non_constant_p, overflow_p); diff --git gcc/cp/error.c gcc/cp/error.c index 76f86cb..09789ad 100644 --- gcc/cp/error.c +++ gcc/cp/error.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "c-family/c-objc.h" #include "ubsan.h" +#include "internal-fn.h" #include // For placement-new. @@ -2037,6 +2038,14 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) tree fn = CALL_EXPR_FN (t); bool skipfirst = false; + /* Deal with internal functions. */ + if (fn == NULL_TREE) + { + pp_string (pp, internal_fn_name (CALL_EXPR_IFN (t))); + dump_call_expr_args (pp, t, flags, skipfirst); + break; + } + if (TREE_CODE (fn) == ADDR_EXPR) fn = TREE_OPERAND (fn, 0); diff --git gcc/testsuite/g++.dg/ubsan/pr63956.C gcc/testsuite/g++.dg/ubsan/pr63956.C index e69de29..7bc0b77 100644 --- gcc/testsuite/g++.dg/ubsan/pr63956.C +++ gcc/testsuite/g++.dg/ubsan/pr63956.C @@ -0,0 +1,172 @@ +// PR sanitizer/63956 +// { dg-do compile } +// { dg-options "-std=c++14 -fsanitize=undefined,float-divide-by-zero,float-cast-overflow" } + +#define SA(X) static_assert((X),#X) +#define INT_MIN (-__INT_MAX__ - 1) + +constexpr int +fn1 (int a, int b) +{ + if (b != 2) + a <<= b; + return a; +} + +constexpr int i1 = fn1 (5, 3); +constexpr int i2 = fn1 (5, -2); +constexpr int i3 = fn1 (5, sizeof (int) * __CHAR_BIT__); +constexpr int i4 = fn1 (5, 256); +constexpr int i5 = fn1 (5, 2); +constexpr int i6 = fn1 (-2, 4); +constexpr int i7 = fn1 (0, 2); + +SA (i1 == 40); +SA (i5 == 5); +SA (i7 == 0); + +constexpr int +fn2 (int a, int b) +{ + if (b != 2) + a >>= b; + return a; +} + +constexpr int j1 = fn2 (4, 1); +constexpr int j2 = fn2 (4, -1); +constexpr int j3 = fn2 (10, sizeof (int) * __CHAR_BIT__); +constexpr int j4 = fn2 (1, 256); +constexpr int j5 = fn2 (5, 2); +constexpr int j6 = fn2 (-2, 4); +constexpr int j7 = fn2 (0, 4); + +SA (j1 == 2); +SA (j5 == 5); +SA (j7 == 0); + +constexpr int +fn3 (int a, int b) +{ + if (b != 2) + a = a / b; + return a; +} + +constexpr int k1 = fn3 (8, 4); +constexpr int k2 = fn3 (7, 0); // { dg-error "is not a constant expression|constexpr call flows off" } +constexpr int k3 = fn3 (INT_MIN, -1); // { dg-error "overflow in constant expression|constexpr call flows off" } + +SA (k1 == 2); + +constexpr float +fn4 (float a, float b) +{ + if (b != 2.0) + a = a / b; + return a; +} + +constexpr float l1 = fn4 (5.0, 3.0); +constexpr float l2 = fn4 (7.0, 0.0); // { dg-error "is not a constant expression|constexpr call flows off" } + +constexpr int +fn5 (const int *a, int b) +{ + if (b != 2) + b = a[b]; + return b; +} + +constexpr int m1[4] = { 1, 2, 3, 4 }; +constexpr int m2 = fn5 (m1, 3); +constexpr int m3 = fn5 (m1, 4); // { dg-error "array subscript out of bound|constexpr call flows off" } + +constexpr int +fn6 (const int &a, int b) +{ + if (b != 2) + b = a; + return b; +} + +constexpr int +fn7 (const int *a, int b) +{ + if (b != 3) + return fn6 (*a, b); + return 7; +} + +constexpr int n1 = 7; +constexpr int n2 = fn7 (&n1, 5); +constexpr int n3 = fn7 ((const int *) 0, 8); // { dg-error "is not a constant expression|constexpr call flows off" } + +constexpr int +fn8 (int i) +{ + constexpr int g[10] = { }; + return g[i]; +} + +constexpr int o1 = fn8 (9); +constexpr int o2 = fn8 (10); // { dg-error "array subscript out of bound" } + +constexpr int +fn9 (int a, int b) +{ + if (b != 0) + return a + b; + return a; +} + +constexpr int p1 = fn9 (42, 7); +constexpr int p2 = fn9 (__INT_MAX__, 1); // { dg-error "overflow in constant expression" } +constexpr int p3 = fn9 (__INT_MAX__, -1); +constexpr int p4 = fn9 (INT_MIN, 1); +constexpr int p5 = fn9 (INT_MIN, -1); // { dg-error "overflow in constant expression" } + +SA (p1 == 49); +SA (p3 == __INT_MAX__ - 1); +SA (p4 == INT_MIN + 1); + +constexpr int +fn10 (int a, int b) +{ + if (b != 0) + return a * b; + return a; +} + +constexpr int q1 = fn10 (10, 10); +constexpr int q2 = fn10 (__INT_MAX__, 2); // { dg-error "overflow in constant expression" } +constexpr int q3 = fn10 (INT_MIN, 2); // { dg-error "overflow in constant expression" } +constexpr int q4 = fn10 (-1, -1); + +SA (q1 == 100); +SA (q4 == 1); + +constexpr int +fn11 (double d) +{ + int i = d; + if (i != 0) + return i; + return i * 2; +} + +constexpr int r1 = fn11 (3.4); +constexpr int r2 = fn11 (__builtin_inf ()); // { dg-error "overflow in constant expression|constexpr call flows off" } + +constexpr int +fn12 (int i) +{ + if (i == 42) + __builtin_unreachable (); // { dg-error "is not a constant expression" } + return i + 10; +} + +constexpr int s1 = fn12 (1); +constexpr int s2 = fn12 (42); // { dg-error "constexpr call flows off the end of the function" } + +SA (s1 == 11);