From patchwork Fri Nov 22 09:28:52 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 293385 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)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 7E2F42C00CB for ; Fri, 22 Nov 2013 21:21:33 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :resent-from:resent-date:resent-message-id:resent-to:date:from :to:cc:subject:message-id:reply-to:mime-version:content-type; q= dns; s=default; b=Xj7aXN7II7Q/h7/tYT8fOMZ2rZd4pyeaR9PqZTl0/O5/7u RNVoNt/u/n7zhR6+iGkyORz3tFR1EVEVpCHk60cA18Oebzibyf3ZMblDATePB54D /2zxAvHD1vciIdfefoFKYHt5FztYkcoyBHyR4U0+TgFF62VmStv58ROgeyoAQ= 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 :resent-from:resent-date:resent-message-id:resent-to:date:from :to:cc:subject:message-id:reply-to:mime-version:content-type; s= default; bh=BGwR+FyrGx9aXYj0Ixt+Xo/1B6Q=; b=UYpmZ2EJBO1/BeBy8PZa FOid3pwM5BtOwop+3UZH5DhMSM+LngWthEULu2xE+0mEpQsrSJWa53VjsJqMycg2 02DuGnQzNDLk9WQaMSCiAGg1Pmf0XHcH7mLGc7XDpKPG7en/m38nyDxsaak7gwgg RYE7/dbrLSA2IuCALZ3aMNU= Received: (qmail 23532 invoked by alias); 22 Nov 2013 10:21:21 -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 23483 invoked by uid 89); 22 Nov 2013 10:21:21 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=AWL, BAYES_50, RDNS_NONE, SPF_HELO_PASS, SPF_PASS autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from Unknown (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 22 Nov 2013 10:21:19 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id rAMALCkE014582 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 22 Nov 2013 05:21:12 -0500 Received: from tucnak.zalov.cz (vpn1-7-171.ams2.redhat.com [10.36.7.171]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id rAMALACC002996 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Fri, 22 Nov 2013 05:21:12 -0500 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.14.7/8.14.7) with ESMTP id rAMALA0N008815 for ; Fri, 22 Nov 2013 11:21:10 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.14.7/8.14.7/Submit) id rAMALAsE008814 for gcc-patches@gcc.gnu.org; Fri, 22 Nov 2013 11:21:10 +0100 Resent-From: Jakub Jelinek Resent-Date: Fri, 22 Nov 2013 11:21:09 +0100 Resent-Message-ID: <20131122102109.GG21875@tucnak.zalov.cz> Resent-To: gcc-patches@gcc.gnu.org Date: Fri, 22 Nov 2013 10:28:52 +0100 From: Jakub Jelinek To: Jason Merrill , Marek Polacek Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] Implement -fsanitize=return (for C++ only) Message-ID: <20131122092852.GU892@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Hi! Working virtually out of Pago Pago right now. In C++, falling through the end of a function that returns a value without returning a value is undefined behavior (unlike C?), so this patch implements instrumentation of it. Ok for trunk? 2013-11-21 Jakub Jelinek * ubsan.c (ubsan_source_location): Don't crash on unknown locations. (ubsan_pass): Ignore clobber stmts. * sanitizer.def (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN): New built-in. * opts.c (common_handle_option): Add -fsanitize=return. * flag-types.h (enum sanitize_code): Add SANITIZE_RETURN and or it into SANITIZE_UNDEFINED. c-family/ * c-ubsan.h (ubsan_instrument_return): New prototype. * c-ubsan.c (ubsan_instrument_return): New function. cp/ * cp-gimplify.c: Include target.h and c-family/c-ubsan.h. (cp_genericize): Handle -fsanitize=return. testsuite/ * g++.dg/ubsan/return-1.C: New test. * g++.dg/ubsan/return-2.C: New test. Jakub --- gcc/ubsan.c.jj 2013-11-22 01:40:03.000000000 +0100 +++ gcc/ubsan.c 2013-11-22 10:05:29.491725405 +0100 @@ -227,8 +227,8 @@ ubsan_source_location (location_t loc) xloc = expand_location (loc); /* Fill in the values from LOC. */ - size_t len = strlen (xloc.file); - tree str = build_string (len + 1, xloc.file); + size_t len = xloc.file ? strlen (xloc.file) : 0; + tree str = build_string (len + 1, xloc.file ? xloc.file : ""); TREE_TYPE (str) = build_array_type (char_type_node, build_index_type (size_int (len))); TREE_READONLY (str) = 1; @@ -642,7 +642,7 @@ ubsan_pass (void) { struct walk_stmt_info wi; gimple stmt = gsi_stmt (gsi); - if (is_gimple_debug (stmt)) + if (is_gimple_debug (stmt) || gimple_clobber_p (stmt)) { gsi_next (&gsi); continue; --- gcc/sanitizer.def.jj 2013-11-22 01:40:03.000000000 +0100 +++ gcc/sanitizer.def 2013-11-22 09:44:03.818203700 +0100 @@ -297,6 +297,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HAN "__ubsan_handle_builtin_unreachable", BT_FN_VOID_PTR, ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_MISSING_RETURN, + "__ubsan_handle_missing_return", + BT_FN_VOID_PTR, + ATTR_NORETURN_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE, "__ubsan_handle_vla_bound_not_positive", BT_FN_VOID_PTR_PTR, --- gcc/opts.c.jj 2013-11-22 01:40:05.000000000 +0100 +++ gcc/opts.c 2013-11-22 09:08:12.537971216 +0100 @@ -1457,6 +1457,7 @@ common_handle_option (struct gcc_options { "unreachable", SANITIZE_UNREACHABLE, sizeof "unreachable" - 1 }, { "vla-bound", SANITIZE_VLA, sizeof "vla-bound" - 1 }, + { "return", SANITIZE_RETURN, sizeof "return" - 1 }, { "null", SANITIZE_NULL, sizeof "null" - 1 }, { NULL, 0, 0 } }; --- gcc/flag-types.h.jj 2013-11-22 01:40:03.000000000 +0100 +++ gcc/flag-types.h 2013-11-22 09:07:29.150236112 +0100 @@ -212,8 +212,9 @@ enum sanitize_code { SANITIZE_UNREACHABLE = 1 << 4, SANITIZE_VLA = 1 << 5, SANITIZE_NULL = 1 << 6, + SANITIZE_RETURN = 1 << 8, SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE - | SANITIZE_VLA | SANITIZE_NULL + | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN }; /* flag_vtable_verify initialization levels. */ --- gcc/c-family/c-ubsan.h.jj 2013-11-12 11:31:11.000000000 +0100 +++ gcc/c-family/c-ubsan.h 2013-11-22 09:38:31.654851809 +0100 @@ -24,5 +24,6 @@ along with GCC; see the file COPYING3. extern tree ubsan_instrument_division (location_t, tree, tree); extern tree ubsan_instrument_shift (location_t, enum tree_code, tree, tree); extern tree ubsan_instrument_vla (location_t, tree); +extern tree ubsan_instrument_return (location_t); #endif /* GCC_C_UBSAN_H */ --- gcc/c-family/c-ubsan.c.jj 2013-11-19 21:56:20.000000000 +0100 +++ gcc/c-family/c-ubsan.c 2013-11-22 09:52:31.810642606 +0100 @@ -179,3 +179,14 @@ ubsan_instrument_vla (location_t loc, tr return t; } + +/* Instrument missing return in C++ functions returning non-void. */ + +tree +ubsan_instrument_return (location_t loc) +{ + tree data = ubsan_create_data ("__ubsan_missing_return_data", loc, + NULL,NULL_TREE); + tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN); + return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data)); +} --- gcc/cp/cp-gimplify.c.jj 2013-11-19 21:56:25.000000000 +0100 +++ gcc/cp/cp-gimplify.c 2013-11-22 09:53:49.852263241 +0100 @@ -34,6 +34,8 @@ along with GCC; see the file COPYING3. #include "pointer-set.h" #include "flags.h" #include "splay-tree.h" +#include "target.h" +#include "c-family/c-ubsan.h" /* Forward declarations. */ @@ -1235,6 +1237,54 @@ cp_genericize (tree fndecl) walk_tree's hash functionality. */ cp_genericize_tree (&DECL_SAVED_TREE (fndecl)); + if ((flag_sanitize & SANITIZE_RETURN) + && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))) + && !DECL_CONSTRUCTOR_P (fndecl) + && !DECL_DESTRUCTOR_P (fndecl) + && targetm.warn_func_return (fndecl)) + { + tree t = DECL_SAVED_TREE (fndecl); + while (t) + { + switch (TREE_CODE (t)) + { + case BIND_EXPR: + t = BIND_EXPR_BODY (t); + continue; + case TRY_FINALLY_EXPR: + t = TREE_OPERAND (t, 0); + continue; + case STATEMENT_LIST: + { + tree_stmt_iterator i = tsi_last (t); + if (!tsi_end_p (i)) + { + t = tsi_stmt (i); + continue; + } + } + break; + case RETURN_EXPR: + t = NULL_TREE; + break; + default: + break; + } + break; + } + if (t) + { + t = DECL_SAVED_TREE (fndecl); + if (TREE_CODE (t) == BIND_EXPR + && TREE_CODE (BIND_EXPR_BODY (t)) == STATEMENT_LIST) + { + tree_stmt_iterator i = tsi_last (BIND_EXPR_BODY (t)); + t = ubsan_instrument_return (DECL_SOURCE_LOCATION (fndecl)); + tsi_link_after (&i, t, TSI_NEW_STMT); + } + } + } + /* Do everything else. */ c_genericize (fndecl); --- gcc/testsuite/g++.dg/ubsan/return-1.C.jj 2013-11-22 10:09:27.730525521 +0100 +++ gcc/testsuite/g++.dg/ubsan/return-1.C 2013-11-22 10:20:25.124405610 +0100 @@ -0,0 +1,27 @@ +// { dg-do run } +// { dg-options "-fsanitize=return" } +// { dg-shouldfail "ubsan" } + +struct S { S (); ~S (); }; + +S::S () {} +S::~S () {} + +int +foo (int x) +{ + S a; + { + S b; + if (x) + return 1; + } +} + +int +main () +{ + foo (0); +} + +// { dg-output "execution reached the end of a value-returning function without returning a value" } --- gcc/testsuite/g++.dg/ubsan/return-2.C.jj 2013-11-22 10:09:31.050510359 +0100 +++ gcc/testsuite/g++.dg/ubsan/return-2.C 2013-11-22 10:09:23.734570198 +0100 @@ -0,0 +1,25 @@ +// { dg-do run } +// { dg-options "-fsanitize=return" } + +struct S { S (); ~S (); }; + +S::S () {} +S::~S () {} + +int +foo (int x) +{ + S a; + { + S b; + if (x) + return 1; + } +} + +int +main () +{ + foo (1); + foo (14); +}