From patchwork Wed Jul 18 12:40:14 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 171661 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]) by ozlabs.org (Postfix) with SMTP id 2C7AB2C034B for ; Wed, 18 Jul 2012 22:41:14 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1343220075; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:Date:From:To:Cc:Subject:Message-ID:Reply-To: MIME-Version:Content-Type:Content-Disposition:User-Agent: Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:Sender:Delivered-To; bh=GiNroVxlQ7YZCfu2bxa8 Ys4/zzU=; b=wdKFoKdV2E0c94IaaYn29sLhWnjCulKMIdfI7zBsvqPLh6Jl6ooP PKM0M+YoxGtsnTSq3IhCQWbfB1JaE1qSh6YXK8w8I6jkc4qIytyZGUyHNYjZ6wFS cNL9ZoES8G4JilFjIOXa+bwVC1aI0qiD7YVjAV5b1+j/mKTcnkIa6NQ= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Received:Date:From:To:Cc:Subject:Message-ID:Reply-To:MIME-Version:Content-Type:Content-Disposition:User-Agent:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=YWgikteqMD9xY9LHikEhlBNN96tSWgzA4acgtErXLpxJ770P9YPAbsOYhgd4I5 Rf91J1KShwVHI3NAe0xC6sFhcSHpFv/UZ6610xpGEsZBw1naNu24hVV6Jp9fDGSP GKjWgiGFuCMdSRmEz/WZSLKuHrMA3F/UuX88HL3YIUxB4=; Received: (qmail 27930 invoked by alias); 18 Jul 2012 12:40:56 -0000 Received: (qmail 27854 invoked by uid 22791); 18 Jul 2012 12:40:48 -0000 X-SWARE-Spam-Status: No, hits=-6.3 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, SPF_HELO_PASS, TW_CP, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 18 Jul 2012 12:40:23 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q6ICeImB010887 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 18 Jul 2012 08:40:19 -0400 Received: from zalov.redhat.com (vpn1-6-80.ams2.redhat.com [10.36.6.80]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q6ICeGar013552 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 18 Jul 2012 08:40:18 -0400 Received: from zalov.cz (localhost [127.0.0.1]) by zalov.redhat.com (8.14.5/8.14.5) with ESMTP id q6ICeFR3001744; Wed, 18 Jul 2012 14:40:16 +0200 Received: (from jakub@localhost) by zalov.cz (8.14.5/8.14.5/Submit) id q6ICeFrW001741; Wed, 18 Jul 2012 14:40:15 +0200 Date: Wed, 18 Jul 2012 14:40:14 +0200 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Cc: "Joseph S. Myers" , Jason Merrill , Paolo Carlini Subject: [RFC PATCH] -Wsizeof-pointer-memaccess warning Message-ID: <20120718124014.GH9077@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 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 Hi! In order to provide my small part for the improved diagnostics goal in 4.8, this patch adds support for the -Wsizeof-pointer-memaccess warning clang has and is listed in the various summaries of gcc vs. clang diagnostics comparisons. The warning warns about common programming mistake of forgotting to dereference sizeof argument passed as last argument to some memory/string builtins like memset, memcpy etc. Haven't looked at clang implementation, just looked at what it produces on the testcase, the only difference appart from clang's two location + range carets compared to gcc single location caret is that for char c; ... memset (&c, 0, sizeof (&c)); gcc suggests to remove & while clang suggests to provide explicit length. The problem on the GCC side is that both the C and C++ FEs fold away the sizeof too early (well, C++ FE only when not in a template, otherwise SIZEOF_EXPR is created and guess one could tsubst its argument again). I've only done C FE right now, instead of constructing SIZEOF_EXPR always and folding it later on (which would be much more work and could risk regressions) I'm just remembering the last sizeof argument which is all that is needed for this kind of warning (yeah, admit not very nice, but works). For C++ I guess similar spot could be finish_call_expr (adding another argument, usually NULL, to it) that would be feeded by remembered last sizeof argument or during tsubst from SIZEOF_EXPR argument after tsubsting. On the c-family side, to have the messages translatable I need multiple variants of each message (for one warning 3 different suggestions, for the other warning one suggestion, times 2 {source,destination}). Ideally it would be times 4, also {first argument,second argument}, given that for memcmp/strncmp/strncasecmp it is hard to talk about source or destination argument, but apparently clang doesn't bother with that distinction either. Bootstrapped/regtested on x86_64-linux and i686-linux. Comments? 2012-07-18 Jakub Jelinek * doc/invoke.texi (-Wsizeof-pointer-memaccess): Document. c/ * c-tree.h (c_last_sizeof_arg, c_last_sizeof_arg_loc): Declare. * c-parser.c (c_parser_expr_list): Add sizeof_arg argument. Fill it in if non-NULL. (c_parser_attributes, c_parser_objc_keywordexpr): Adjust callers. (c_parser_postfix_expression_after_primary): Likewise. Call sizeof_pointer_memaccess_warning if needed. (sizeof_ptr_memacc_comptypes): New function. * c-typeck.c (c_last_sizeof_arg, c_last_sizeof_arg_loc): New global variables. (c_expr_sizeof_expr, c_expr_sizeof_type): Initialize them. cp/ * cp-tree.def (SIZEOF_EXPR): Move to c-common.def. c-family/ * c-common.c (sizeof_pointer_memaccess_warning): New function. * c.opt (-Wsizeof-pointer-memaccess): Add new option. * c-opts.c (c_common_handle_option): Enable it for -Wall. * c-common.h (sizeof_pointer_memaccess_warning): Add prototype. * c-common.def (SIZEOF_EXPR): Moved here from cp-tree.def. testsuite/ * gcc.dg/torture/Wsizeof-pointer-memaccess1.c: New test. Jakub --- gcc/c/c-tree.h.jj 2012-06-29 21:22:02.000000000 +0200 +++ gcc/c/c-tree.h 2012-07-17 17:27:12.596107848 +0200 @@ -573,6 +573,9 @@ extern int in_alignof; extern int in_sizeof; extern int in_typeof; +extern tree c_last_sizeof_arg; +extern location_t c_last_sizeof_arg_loc; + extern struct c_switch *c_switch_stack; extern tree c_objc_common_truthvalue_conversion (location_t, tree); --- gcc/c/c-parser.c.jj 2012-06-29 21:22:02.000000000 +0200 +++ gcc/c/c-parser.c 2012-07-18 12:03:17.725554622 +0200 @@ -1179,7 +1179,7 @@ static tree c_parser_transaction_cancel static struct c_expr c_parser_expression (c_parser *); static struct c_expr c_parser_expression_conv (c_parser *); static VEC(tree,gc) *c_parser_expr_list (c_parser *, bool, bool, - VEC(tree,gc) **); + VEC(tree,gc) **, tree *); static void c_parser_omp_construct (c_parser *); static void c_parser_omp_threadprivate (c_parser *); static void c_parser_omp_barrier (c_parser *); @@ -3578,7 +3578,8 @@ c_parser_attributes (c_parser *parser) { tree tree_list; c_parser_consume_token (parser); - expr_list = c_parser_expr_list (parser, false, true, NULL); + expr_list = c_parser_expr_list (parser, false, true, + NULL, NULL); tree_list = build_tree_list_vec (expr_list); attr_args = tree_cons (NULL_TREE, arg1, tree_list); release_tree_vector (expr_list); @@ -3590,7 +3591,8 @@ c_parser_attributes (c_parser *parser) attr_args = NULL_TREE; else { - expr_list = c_parser_expr_list (parser, false, true, NULL); + expr_list = c_parser_expr_list (parser, false, true, + NULL, NULL); attr_args = build_tree_list_vec (expr_list); release_tree_vector (expr_list); } @@ -6845,6 +6847,15 @@ c_parser_postfix_expression_after_paren_ return c_parser_postfix_expression_after_primary (parser, start_loc, expr); } +/* Callback function for sizeof_pointer_memaccess_warning to compare + types. */ + +static bool +sizeof_ptr_memacc_comptypes (tree type1, tree type2) +{ + return comptypes (type1, type2) == 1; +} + /* Parse a postfix expression after the initial primary or compound literal; that is, parse a series of postfix operators. @@ -6856,7 +6867,7 @@ c_parser_postfix_expression_after_primar struct c_expr expr) { struct c_expr orig_expr; - tree ident, idx; + tree ident, idx, sizeof_arg; VEC(tree,gc) *exprlist; VEC(tree,gc) *origtypes; while (true) @@ -6877,14 +6888,22 @@ c_parser_postfix_expression_after_primar case CPP_OPEN_PAREN: /* Function call. */ c_parser_consume_token (parser); + sizeof_arg = NULL_TREE; if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) exprlist = NULL; else - exprlist = c_parser_expr_list (parser, true, false, &origtypes); + exprlist = c_parser_expr_list (parser, true, false, &origtypes, + &sizeof_arg); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); orig_expr = expr; mark_exp_read (expr.value); + if (warn_sizeof_pointer_memaccess + && sizeof_arg != NULL_TREE) + sizeof_pointer_memaccess_warning (c_last_sizeof_arg_loc, + expr.value, exprlist, + sizeof_arg, + sizeof_ptr_memacc_comptypes); /* FIXME diagnostics: Ideally we want the FUNCNAME, not the "(" after the FUNCNAME, which is what we have now. */ expr.value = build_function_call_vec (op_loc, expr.value, exprlist, @@ -7045,7 +7064,7 @@ c_parser_expression_conv (c_parser *pars static VEC(tree,gc) * c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, - VEC(tree,gc) **p_orig_types) + VEC(tree,gc) **p_orig_types, tree *sizeof_arg) { VEC(tree,gc) *ret; VEC(tree,gc) *orig_types; @@ -7066,6 +7085,9 @@ c_parser_expr_list (c_parser *parser, bo VEC_quick_push (tree, ret, expr.value); if (orig_types != NULL) VEC_quick_push (tree, orig_types, expr.original_type); + if (sizeof_arg != NULL) + *sizeof_arg = expr.original_code == SIZEOF_EXPR + ? c_last_sizeof_arg : NULL_TREE; while (c_parser_next_token_is (parser, CPP_COMMA)) { c_parser_consume_token (parser); @@ -7078,6 +7100,9 @@ c_parser_expr_list (c_parser *parser, bo VEC_safe_push (tree, gc, ret, expr.value); if (orig_types != NULL) VEC_safe_push (tree, gc, orig_types, expr.original_type); + if (sizeof_arg != NULL) + *sizeof_arg = expr.original_code == SIZEOF_EXPR + ? c_last_sizeof_arg : NULL_TREE; } if (orig_types != NULL) *p_orig_types = orig_types; @@ -8157,7 +8182,8 @@ static tree c_parser_objc_keywordexpr (c_parser *parser) { tree ret; - VEC(tree,gc) *expr_list = c_parser_expr_list (parser, true, true, NULL); + VEC(tree,gc) *expr_list = c_parser_expr_list (parser, true, true, + NULL, NULL); if (VEC_length (tree, expr_list) == 1) { /* Just return the expression, remove a level of --- gcc/c/c-typeck.c.jj 2012-06-29 21:22:02.000000000 +0200 +++ gcc/c/c-typeck.c 2012-07-17 17:30:23.697033027 +0200 @@ -67,6 +67,12 @@ int in_sizeof; /* The level of nesting inside "typeof". */ int in_typeof; +/* The argument of last parsed sizeof expression, only to be tested + if expr.original_code == SIZEOF_EXPR. */ +tree c_last_sizeof_arg; +/* And its location_t. */ +location_t c_last_sizeof_arg_loc; + /* Nonzero if we've already printed a "missing braces around initializer" message within this initializer. */ static int missing_braces_mentioned; @@ -2603,7 +2609,9 @@ c_expr_sizeof_expr (location_t loc, stru tree folded_expr = c_fully_fold (expr.value, require_constant_value, &expr_const_operands); ret.value = c_sizeof (loc, TREE_TYPE (folded_expr)); - ret.original_code = ERROR_MARK; + c_last_sizeof_arg = expr.value; + c_last_sizeof_arg_loc = loc; + ret.original_code = SIZEOF_EXPR; ret.original_type = NULL; if (c_vla_type_p (TREE_TYPE (folded_expr))) { @@ -2631,7 +2639,9 @@ c_expr_sizeof_type (location_t loc, stru bool type_expr_const = true; type = groktypename (t, &type_expr, &type_expr_const); ret.value = c_sizeof (loc, type); - ret.original_code = ERROR_MARK; + c_last_sizeof_arg = type; + c_last_sizeof_arg_loc = loc; + ret.original_code = SIZEOF_EXPR; ret.original_type = NULL; if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) && c_vla_type_p (type)) --- gcc/cp/cp-tree.def.jj 2011-12-12 22:10:25.000000000 +0100 +++ gcc/cp/cp-tree.def 2012-07-17 14:20:50.794619437 +0200 @@ -2,7 +2,7 @@ additional tree codes used in the GNU C++ compiler (see tree.def for the standard codes). Copyright (C) 1987, 1988, 1990, 1993, 1997, 1998, 2003, 2004, 2005, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010, 2011 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010, 2011, 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) @@ -333,9 +333,6 @@ DEFTREECODE (TAG_DEFN, "tag_defn", tcc_e /* Represents an 'offsetof' expression during template expansion. */ DEFTREECODE (OFFSETOF_EXPR, "offsetof_expr", tcc_expression, 1) -/* Represents a 'sizeof' expression during template expansion. */ -DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1) - /* Represents the -> operator during template expansion. */ DEFTREECODE (ARROW_EXPR, "arrow_expr", tcc_expression, 1) --- gcc/doc/invoke.texi.jj 2012-07-16 14:38:13.000000000 +0200 +++ gcc/doc/invoke.texi 2012-07-18 12:24:14.919488086 +0200 @@ -263,9 +263,9 @@ Objective-C and Objective-C++ Dialects}. -Wpointer-arith -Wno-pointer-to-int-cast @gol -Wredundant-decls @gol -Wreturn-type -Wsequence-point -Wshadow @gol --Wsign-compare -Wsign-conversion -Wstack-protector @gol --Wstack-usage=@var{len} -Wstrict-aliasing -Wstrict-aliasing=n @gol --Wstrict-overflow -Wstrict-overflow=@var{n} @gol +-Wsign-compare -Wsign-conversion -Wsizeof-pointer-memaccess @gol +-Wstack-protector -Wstack-usage=@var{len} -Wstrict-aliasing @gol +-Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol -Wmissing-format-attribute @gol -Wswitch -Wswitch-default -Wswitch-enum -Wsync-nand @gol @@ -4324,6 +4324,16 @@ value, like assigning a signed integer e integer variable. An explicit cast silences the warning. In C, this option is enabled also by @option{-Wconversion}. +@item -Wsizeof-pointer-memaccess +@opindex Wsizeof-pointer-memaccess +@opindex Wno-sizeof-pointer-memaccess +Warn for suspicious length parameters to certain string and memory built-in +functions if the argument uses @code{sizeof}. This warning warns e.g.@: +about @code{memset (ptr, 0, sizeof (ptr));} if @code{ptr} is not an array, +but a pointer, and suggests a possible fix, or about +@code{memcpy (&foo, ptr, sizeof (&foo));}. This warning is enabled by +@option{-Wall}. + @item -Waddress @opindex Waddress @opindex Wno-address --- gcc/c-family/c-common.c.jj 2012-07-16 14:38:14.000000000 +0200 +++ gcc/c-family/c-common.c 2012-07-18 12:02:11.433915479 +0200 @@ -1841,6 +1841,149 @@ strict_aliasing_warning (tree otype, tre return false; } +/* Warn about memset (&a, 0, sizeof (&a)); and similar mistakes with + sizeof as last operand of certain builtins. */ + +void +sizeof_pointer_memaccess_warning (location_t loc, tree callee, + VEC(tree, gc) *params, tree sizeof_arg, + bool (*comp_types) (tree, tree)) +{ + tree type, dest = NULL_TREE, src = NULL_TREE, tem; + bool strop = false; + + if (TREE_CODE (callee) != FUNCTION_DECL + || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL + || sizeof_arg == error_mark_node + || VEC_length (tree, params) <= 1) + return; + + type = TYPE_P (sizeof_arg) ? sizeof_arg : TREE_TYPE (sizeof_arg); + if (!POINTER_TYPE_P (type)) + return; + + switch (DECL_FUNCTION_CODE (callee)) + { + case BUILT_IN_STRNCMP: + case BUILT_IN_STRNCASECMP: + case BUILT_IN_STRNCPY: + case BUILT_IN_STRNCAT: + strop = true; + /* FALLTHRU */ + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMMOVE: + case BUILT_IN_MEMCMP: + if (VEC_length (tree, params) < 3) + return; + src = VEC_index (tree, params, 1); + dest = VEC_index (tree, params, 0); + break; + case BUILT_IN_MEMSET: + if (VEC_length (tree, params) < 3) + return; + dest = VEC_index (tree, params, 0); + break; + case BUILT_IN_STRNDUP: + src = VEC_index (tree, params, 0); + strop = true; + break; + default: + break; + } + + if (dest + && (tem = tree_strip_nop_conversions (dest)) + && POINTER_TYPE_P (TREE_TYPE (tem)) + && comp_types (TREE_TYPE (TREE_TYPE (tem)), type)) + return; + + if (src + && (tem = tree_strip_nop_conversions (src)) + && POINTER_TYPE_P (TREE_TYPE (tem)) + && comp_types (TREE_TYPE (TREE_TYPE (tem)), type)) + return; + + if (dest) + { + if (!TYPE_P (sizeof_arg) + && operand_equal_p (dest, sizeof_arg, 0) + && comp_types (TREE_TYPE (dest), type)) + { + if (TREE_CODE (sizeof_arg) == ADDR_EXPR && !strop) + warning_at (loc, OPT_Wsizeof_pointer_memaccess, + "argument to % in %qD call is the same " + "expression as the destination; did you mean to " + "remove the addressof?", callee); + else if ((TYPE_PRECISION (TREE_TYPE (type)) + == TYPE_PRECISION (char_type_node)) + || strop) + warning_at (loc, OPT_Wsizeof_pointer_memaccess, + "argument to % in %qD call is the same " + "expression as the destination; did you mean to " + "provide an explicit length?", callee); + else + warning_at (loc, OPT_Wsizeof_pointer_memaccess, + "argument to % in %qD call is the same " + "expression as the destination; did you mean to " + "dereference it?", callee); + return; + } + + if (POINTER_TYPE_P (TREE_TYPE (dest)) + && !strop + && comp_types (TREE_TYPE (dest), type) + && !VOID_TYPE_P (TREE_TYPE (type))) + { + warning_at (loc, OPT_Wsizeof_pointer_memaccess, + "argument to % in %qD call is the same " + "pointer type %qT as the destination; expected %qT " + "or an explicit length", callee, TREE_TYPE (dest), + TREE_TYPE (TREE_TYPE (dest))); + return; + } + } + + if (src) + { + if (!TYPE_P (sizeof_arg) + && operand_equal_p (src, sizeof_arg, 0) + && comp_types (TREE_TYPE (src), type)) + { + if (TREE_CODE (sizeof_arg) == ADDR_EXPR && !strop) + warning_at (loc, OPT_Wsizeof_pointer_memaccess, + "argument to % in %qD call is the same " + "expression as the source; did you mean to " + "remove the addressof?", callee); + else if ((TYPE_PRECISION (TREE_TYPE (type)) + == TYPE_PRECISION (char_type_node)) + || strop) + warning_at (loc, OPT_Wsizeof_pointer_memaccess, + "argument to % in %qD call is the same " + "expression as the source; did you mean to " + "provide an explicit length?", callee); + else + warning_at (loc, OPT_Wsizeof_pointer_memaccess, + "argument to % in %qD call is the same " + "expression as the source; did you mean to " + "dereference it?", callee); + return; + } + + if (POINTER_TYPE_P (TREE_TYPE (src)) + && !strop + && comp_types (TREE_TYPE (src), type) + && !VOID_TYPE_P (TREE_TYPE (type))) + { + warning_at (loc, OPT_Wsizeof_pointer_memaccess, + "argument to % in %qD call is the same " + "pointer type %qT as the source; expected %qT " + "or an explicit length", callee, TREE_TYPE (src), + TREE_TYPE (TREE_TYPE (src))); + return; + } + } +} + /* Warn for unlikely, improbable, or stupid DECL declarations of `main'. */ --- gcc/c-family/c.opt.jj 2012-06-07 08:27:33.000000000 +0200 +++ gcc/c-family/c.opt 2012-07-17 17:32:45.123243139 +0200 @@ -474,6 +474,9 @@ Wmissing-field-initializers C ObjC C++ ObjC++ Var(warn_missing_field_initializers) Warning EnabledBy(Wextra) Warn about missing fields in struct initializers +Wsizeof-pointer-memaccess +C ObjC C++ ObjC++ Var(warn_sizeof_pointer_memaccess) Warning + Wsuggest-attribute=format C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning Warn about functions which might be candidates for format attributes --- gcc/c-family/c-opts.c.jj 2012-06-25 08:38:15.000000000 +0200 +++ gcc/c-family/c-opts.c 2012-07-17 17:32:38.759278771 +0200 @@ -374,6 +374,7 @@ c_common_handle_option (size_t scode, co warn_return_type = value; warn_sequence_point = value; /* Was C only. */ warn_switch = value; + warn_sizeof_pointer_memaccess = value; if (warn_strict_aliasing == -1) set_Wstrict_aliasing (&global_options, value); warn_address = value; --- gcc/c-family/c-common.h.jj 2012-07-16 14:38:14.000000000 +0200 +++ gcc/c-family/c-common.h 2012-07-17 17:29:12.232430457 +0200 @@ -1,6 +1,6 @@ /* Definitions for c-common.c. - Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 + Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -768,6 +768,9 @@ extern tree fix_string_type (tree); extern void constant_expression_warning (tree); extern void constant_expression_error (tree); extern bool strict_aliasing_warning (tree, tree, tree); +extern void sizeof_pointer_memaccess_warning (location_t, tree, + VEC(tree, gc) *, tree, + bool (*) (tree, tree)); extern void warnings_for_convert_and_check (tree, tree, tree); extern tree convert_and_check (tree, tree); extern void overflow_warning (location_t, tree); --- gcc/c-family/c-common.def.jj 2011-10-27 08:58:03.000000000 +0200 +++ gcc/c-family/c-common.def 2012-07-17 14:22:03.750206134 +0200 @@ -53,6 +53,10 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "exc number. */ DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3) +/* Represents a 'sizeof' expression during C++ template expansion, + or for the purpose of -Wsizeof-pointer-memaccess warning. */ +DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1) + /* Local variables: mode:c --- gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c.jj 2012-07-18 10:04:55.442095371 +0200 +++ gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c 2012-07-18 11:52:21.503691648 +0200 @@ -0,0 +1,698 @@ +/* Test -Wsizeof-pointer-memaccess warnings. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ +/* Test just twice, once with -O0 non-fortified, once with -O2 fortified. */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */ + +typedef __SIZE_TYPE__ size_t; +extern void *memset (void *, int, size_t); +extern void *memcpy (void *__restrict, const void *__restrict, size_t); +extern void *memmove (void *__restrict, const void *__restrict, size_t); +extern int memcmp (const void *, const void *, size_t); +extern char *strncpy (char *__restrict, const char *__restrict, size_t); +extern char *strncat (char *__restrict, const char *__restrict, size_t); +extern char *strndup (const char *, size_t); +extern int strncmp (const char *, const char *, size_t); +extern int strncasecmp (const char *, const char *, size_t); + +#ifdef __OPTIMIZE__ +# define bos(ptr) __builtin_object_size (ptr, 1) +# define bos0(ptr) __builtin_object_size (ptr, 0) + +__attribute__((__always_inline__, __gnu_inline__, __artificial__)) +extern inline void * +memset (void *dest, int c, size_t len) +{ + return __builtin___memset_chk (dest, c, len, bos0 (dest)); +} + +__attribute__((__always_inline__, __gnu_inline__, __artificial__)) +extern inline void * +memcpy (void *__restrict dest, const void *__restrict src, size_t len) +{ + return __builtin___memcpy_chk (dest, src, len, bos0 (dest)); +} + +__attribute__((__always_inline__, __gnu_inline__, __artificial__)) +extern inline void * +memmove (void *dest, const void *src, size_t len) +{ + return __builtin___memmove_chk (dest, src, len, bos0 (dest)); +} + +__attribute__((__always_inline__, __gnu_inline__, __artificial__)) +extern inline char * +strncpy (char *__restrict dest, const char *__restrict src, size_t len) +{ + return __builtin___strncpy_chk (dest, src, len, bos (dest)); +} + +__attribute__((__always_inline__, __gnu_inline__, __artificial__)) +extern inline char * +strncat (char *dest, const char *src, size_t len) +{ + return __builtin___strncat_chk (dest, src, len, bos (dest)); +} +#endif + +struct A { short a, b; int c, d; long e, f; }; +typedef struct A TA; +typedef struct A *PA; +typedef TA *PTA; +struct B {}; +typedef struct B TB; +typedef struct B *PB; +typedef TB *PTB; +typedef int X[3][3][3]; + +int +f1 (void *x, int z) +{ + struct A a, *pa1 = &a; + TA *pa2 = &a; + PA pa3 = &a; + PTA pa4 = &a; + memset (&a, 0, sizeof (&a)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memset (pa1, 0, sizeof (pa1)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memset (pa2, 0, sizeof pa2); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memset (pa3, 0, sizeof (pa3)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memset (pa4, 0, sizeof pa4); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memset (pa1, 0, sizeof (struct A *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memset (pa2, 0, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memset (pa3, 0, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memset (pa4, 0, sizeof (__typeof (pa4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + + memcpy (&a, x, sizeof (&a)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memcpy (pa1, x, sizeof (pa1)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memcpy (pa2, x, sizeof pa2); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memcpy (pa3, x, sizeof (pa3)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memcpy (pa4, x, sizeof pa4); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memcpy (pa1, x, sizeof (struct A *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memcpy (pa2, x, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memcpy (pa3, x, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memcpy (pa4, x, sizeof (__typeof (pa4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + + memcpy (x, &a, sizeof (&a)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + memcpy (x, pa1, sizeof (pa1)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memcpy (x, pa2, sizeof pa2); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memcpy (x, pa3, sizeof (pa3)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memcpy (x, pa4, sizeof pa4); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memcpy (x, pa1, sizeof (struct A *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memcpy (x, pa2, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memcpy (x, pa3, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memcpy (x, pa4, sizeof (__typeof (pa4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + + memmove (&a, x, sizeof (&a)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memmove (pa1, x, sizeof (pa1)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memmove (pa2, x, sizeof pa2); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memmove (pa3, x, sizeof (pa3)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memmove (pa4, x, sizeof pa4); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memmove (pa1, x, sizeof (struct A *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memmove (pa2, x, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memmove (pa3, x, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memmove (pa4, x, sizeof (__typeof (pa4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + + memmove (x, &a, sizeof (&a)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + memmove (x, pa1, sizeof (pa1)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memmove (x, pa2, sizeof pa2); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memmove (x, pa3, sizeof (pa3)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memmove (x, pa4, sizeof pa4); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memmove (x, pa1, sizeof (struct A *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memmove (x, pa2, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memmove (x, pa3, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memmove (x, pa4, sizeof (__typeof (pa4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + + z += memcmp (&a, x, sizeof (&a)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + z += memcmp (pa1, x, sizeof (pa1)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + z += memcmp (pa2, x, sizeof pa2); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + z += memcmp (pa3, x, sizeof (pa3)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + z += memcmp (pa4, x, sizeof pa4); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + z += memcmp (pa1, x, sizeof (struct A *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + z += memcmp (pa2, x, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + z += memcmp (pa3, x, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + + z += memcmp (x, &a, sizeof (&a)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + z += memcmp (x, pa1, sizeof (pa1)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + z += memcmp (x, pa2, sizeof pa2); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + z += memcmp (x, pa3, sizeof (pa3)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + z += memcmp (x, pa4, sizeof pa4); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + z += memcmp (x, pa1, sizeof (struct A *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + z += memcmp (x, pa2, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + z += memcmp (x, pa3, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + + /* These are correct, no warning. */ + memset (&a, 0, sizeof a); + memset (&a, 0, sizeof (a)); + memset (&a, 0, sizeof (struct A)); + memset (&a, 0, sizeof (const struct A)); + memset (&a, 0, sizeof (volatile struct A)); + memset (&a, 0, sizeof (volatile const struct A)); + memset (&a, 0, sizeof (TA)); + memset (&a, 0, sizeof (__typeof (*&a))); + memset (pa1, 0, sizeof (*pa1)); + memset (pa2, 0, sizeof (*pa3)); + memset (pa3, 0, sizeof (__typeof (*pa3))); + /* These are probably broken, but obfuscated, no warning. */ + memset ((void *) &a, 0, sizeof (&a)); + memset ((char *) &a, 0, sizeof (&a)); + memset (&a, 0, sizeof (&a) + 0); + memset (&a, 0, 0 + sizeof (&a)); + + /* These are correct, no warning. */ + memcpy (&a, x, sizeof a); + memcpy (&a, x, sizeof (a)); + memcpy (&a, x, sizeof (struct A)); + memcpy (&a, x, sizeof (const struct A)); + memcpy (&a, x, sizeof (volatile struct A)); + memcpy (&a, x, sizeof (volatile const struct A)); + memcpy (&a, x, sizeof (TA)); + memcpy (&a, x, sizeof (__typeof (*&a))); + memcpy (pa1, x, sizeof (*pa1)); + memcpy (pa2, x, sizeof (*pa3)); + memcpy (pa3, x, sizeof (__typeof (*pa3))); + /* These are probably broken, but obfuscated, no warning. */ + memcpy ((void *) &a, x, sizeof (&a)); + memcpy ((char *) &a, x, sizeof (&a)); + memcpy (&a, x, sizeof (&a) + 0); + memcpy (&a, x, 0 + sizeof (&a)); + + /* These are correct, no warning. */ + memcpy (x, &a, sizeof a); + memcpy (x, &a, sizeof (a)); + memcpy (x, &a, sizeof (struct A)); + memcpy (x, &a, sizeof (const struct A)); + memcpy (x, &a, sizeof (volatile struct A)); + memcpy (x, &a, sizeof (volatile const struct A)); + memcpy (x, &a, sizeof (TA)); + memcpy (x, &a, sizeof (__typeof (*&a))); + memcpy (x, pa1, sizeof (*pa1)); + memcpy (x, pa2, sizeof (*pa3)); + memcpy (x, pa3, sizeof (__typeof (*pa3))); + /* These are probably broken, but obfuscated, no warning. */ + memcpy (x, (void *) &a, sizeof (&a)); + memcpy (x, (char *) &a, sizeof (&a)); + memcpy (x, &a, sizeof (&a) + 0); + memcpy (x, &a, 0 + sizeof (&a)); + + /* These are correct, no warning. */ + memmove (&a, x, sizeof a); + memmove (&a, x, sizeof (a)); + memmove (&a, x, sizeof (struct A)); + memmove (&a, x, sizeof (const struct A)); + memmove (&a, x, sizeof (volatile struct A)); + memmove (&a, x, sizeof (volatile const struct A)); + memmove (&a, x, sizeof (TA)); + memmove (&a, x, sizeof (__typeof (*&a))); + memmove (pa1, x, sizeof (*pa1)); + memmove (pa2, x, sizeof (*pa3)); + memmove (pa3, x, sizeof (__typeof (*pa3))); + /* These are probably broken, but obfuscated, no warning. */ + memmove ((void *) &a, x, sizeof (&a)); + memmove ((char *) &a, x, sizeof (&a)); + memmove (&a, x, sizeof (&a) + 0); + memmove (&a, x, 0 + sizeof (&a)); + + /* These are correct, no warning. */ + memmove (x, &a, sizeof a); + memmove (x, &a, sizeof (a)); + memmove (x, &a, sizeof (struct A)); + memmove (x, &a, sizeof (const struct A)); + memmove (x, &a, sizeof (volatile struct A)); + memmove (x, &a, sizeof (volatile const struct A)); + memmove (x, &a, sizeof (TA)); + memmove (x, &a, sizeof (__typeof (*&a))); + memmove (x, pa1, sizeof (*pa1)); + memmove (x, pa2, sizeof (*pa3)); + memmove (x, pa3, sizeof (__typeof (*pa3))); + /* These are probably broken, but obfuscated, no warning. */ + memmove (x, (void *) &a, sizeof (&a)); + memmove (x, (char *) &a, sizeof (&a)); + memmove (x, &a, sizeof (&a) + 0); + memmove (x, &a, 0 + sizeof (&a)); + + /* These are correct, no warning. */ + z += memcmp (&a, x, sizeof a); + z += memcmp (&a, x, sizeof (a)); + z += memcmp (&a, x, sizeof (struct A)); + z += memcmp (&a, x, sizeof (const struct A)); + z += memcmp (&a, x, sizeof (volatile struct A)); + z += memcmp (&a, x, sizeof (volatile const struct A)); + z += memcmp (&a, x, sizeof (TA)); + z += memcmp (&a, x, sizeof (__typeof (*&a))); + z += memcmp (pa1, x, sizeof (*pa1)); + z += memcmp (pa2, x, sizeof (*pa3)); + z += memcmp (pa3, x, sizeof (__typeof (*pa3))); + /* These are probably broken, but obfuscated, no warning. */ + z += memcmp ((void *) &a, x, sizeof (&a)); + z += memcmp ((char *) &a, x, sizeof (&a)); + z += memcmp (&a, x, sizeof (&a) + 0); + z += memcmp (&a, x, 0 + sizeof (&a)); + + /* These are correct, no warning. */ + z += memcmp (x, &a, sizeof a); + z += memcmp (x, &a, sizeof (a)); + z += memcmp (x, &a, sizeof (struct A)); + z += memcmp (x, &a, sizeof (const struct A)); + z += memcmp (x, &a, sizeof (volatile struct A)); + z += memcmp (x, &a, sizeof (volatile const struct A)); + z += memcmp (x, &a, sizeof (TA)); + z += memcmp (x, &a, sizeof (__typeof (*&a))); + z += memcmp (x, pa1, sizeof (*pa1)); + z += memcmp (x, pa2, sizeof (*pa3)); + z += memcmp (x, pa3, sizeof (__typeof (*pa3))); + /* These are probably broken, but obfuscated, no warning. */ + z += memcmp (x, (void *) &a, sizeof (&a)); + z += memcmp (x, (char *) &a, sizeof (&a)); + z += memcmp (x, &a, sizeof (&a) + 0); + z += memcmp (x, &a, 0 + sizeof (&a)); + + return z; +} + +int +f2 (void *x, int z) +{ + struct B b, *pb1 = &b; + TB *pb2 = &b; + PB pb3 = &b; + PTB pb4 = &b; + memset (&b, 0, sizeof (&b)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memset (pb1, 0, sizeof (pb1)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memset (pb2, 0, sizeof pb2); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memset (pb3, 0, sizeof (pb3)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memset (pb4, 0, sizeof pb4); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memset (pb1, 0, sizeof (struct B *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memset (pb2, 0, sizeof (PTB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memset (pb3, 0, sizeof (PB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memset (pb4, 0, sizeof (__typeof (pb4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + + memcpy (&b, x, sizeof (&b)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memcpy (pb1, x, sizeof (pb1)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memcpy (pb2, x, sizeof pb2); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memcpy (pb3, x, sizeof (pb3)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memcpy (pb4, x, sizeof pb4); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memcpy (pb1, x, sizeof (struct B *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memcpy (pb2, x, sizeof (PTB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memcpy (pb3, x, sizeof (PB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memcpy (pb4, x, sizeof (__typeof (pb4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + + memcpy (x, &b, sizeof (&b)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + memcpy (x, pb1, sizeof (pb1)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memcpy (x, pb2, sizeof pb2); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memcpy (x, pb3, sizeof (pb3)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memcpy (x, pb4, sizeof pb4); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memcpy (x, pb1, sizeof (struct B *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memcpy (x, pb2, sizeof (PTB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memcpy (x, pb3, sizeof (PB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memcpy (x, pb4, sizeof (__typeof (pb4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + + memmove (&b, x, sizeof (&b)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memmove (pb1, x, sizeof (pb1)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memmove (pb2, x, sizeof pb2); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memmove (pb3, x, sizeof (pb3)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memmove (pb4, x, sizeof pb4); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + memmove (pb1, x, sizeof (struct B *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memmove (pb2, x, sizeof (PTB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memmove (pb3, x, sizeof (PB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + memmove (pb4, x, sizeof (__typeof (pb4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + + memmove (x, &b, sizeof (&b)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + memmove (x, pb1, sizeof (pb1)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memmove (x, pb2, sizeof pb2); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memmove (x, pb3, sizeof (pb3)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memmove (x, pb4, sizeof pb4); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + memmove (x, pb1, sizeof (struct B *)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memmove (x, pb2, sizeof (PTB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memmove (x, pb3, sizeof (PB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + memmove (x, pb4, sizeof (__typeof (pb4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + + z += memcmp (&b, x, sizeof (&b)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + z += memcmp (pb1, x, sizeof (pb1)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + z += memcmp (pb2, x, sizeof pb2); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + z += memcmp (pb3, x, sizeof (pb3)); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + z += memcmp (pb4, x, sizeof pb4); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + z += memcmp (pb1, x, sizeof (struct B *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + z += memcmp (pb2, x, sizeof (PTB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + z += memcmp (pb3, x, sizeof (PB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */ + + z += memcmp (x, &b, sizeof (&b)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + z += memcmp (x, pb1, sizeof (pb1)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + z += memcmp (x, pb2, sizeof pb2); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + z += memcmp (x, pb3, sizeof (pb3)); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + z += memcmp (x, pb4, sizeof pb4); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + z += memcmp (x, pb1, sizeof (struct B *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + z += memcmp (x, pb2, sizeof (PTB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + z += memcmp (x, pb3, sizeof (PB)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */ + + /* These are correct, no warning. */ + memset (&b, 0, sizeof b); + memset (&b, 0, sizeof (b)); + memset (&b, 0, sizeof (struct B)); + memset (&b, 0, sizeof (const struct B)); + memset (&b, 0, sizeof (volatile struct B)); + memset (&b, 0, sizeof (volatile const struct B)); + memset (&b, 0, sizeof (TB)); + memset (&b, 0, sizeof (__typeof (*&b))); + memset (pb1, 0, sizeof (*pb1)); + memset (pb2, 0, sizeof (*pb3)); + memset (pb3, 0, sizeof (__typeof (*pb3))); + /* These are probably broken, but obfuscated, no warning. */ + memset ((void *) &b, 0, sizeof (&b)); + memset ((char *) &b, 0, sizeof (&b)); + memset (&b, 0, sizeof (&b) + 0); + memset (&b, 0, 0 + sizeof (&b)); + + /* These are correct, no warning. */ + memcpy (&b, x, sizeof b); + memcpy (&b, x, sizeof (b)); + memcpy (&b, x, sizeof (struct B)); + memcpy (&b, x, sizeof (const struct B)); + memcpy (&b, x, sizeof (volatile struct B)); + memcpy (&b, x, sizeof (volatile const struct B)); + memcpy (&b, x, sizeof (TB)); + memcpy (&b, x, sizeof (__typeof (*&b))); + memcpy (pb1, x, sizeof (*pb1)); + memcpy (pb2, x, sizeof (*pb3)); + memcpy (pb3, x, sizeof (__typeof (*pb3))); + /* These are probably broken, but obfuscated, no warning. */ + memcpy ((void *) &b, x, sizeof (&b)); + memcpy ((char *) &b, x, sizeof (&b)); + memcpy (&b, x, sizeof (&b) + 0); + memcpy (&b, x, 0 + sizeof (&b)); + + /* These are correct, no warning. */ + memcpy (x, &b, sizeof b); + memcpy (x, &b, sizeof (b)); + memcpy (x, &b, sizeof (struct B)); + memcpy (x, &b, sizeof (const struct B)); + memcpy (x, &b, sizeof (volatile struct B)); + memcpy (x, &b, sizeof (volatile const struct B)); + memcpy (x, &b, sizeof (TB)); + memcpy (x, &b, sizeof (__typeof (*&b))); + memcpy (x, pb1, sizeof (*pb1)); + memcpy (x, pb2, sizeof (*pb3)); + memcpy (x, pb3, sizeof (__typeof (*pb3))); + /* These are probably broken, but obfuscated, no warning. */ + memcpy (x, (void *) &b, sizeof (&b)); + memcpy (x, (char *) &b, sizeof (&b)); + memcpy (x, &b, sizeof (&b) + 0); + memcpy (x, &b, 0 + sizeof (&b)); + + /* These are correct, no warning. */ + memmove (&b, x, sizeof b); + memmove (&b, x, sizeof (b)); + memmove (&b, x, sizeof (struct B)); + memmove (&b, x, sizeof (const struct B)); + memmove (&b, x, sizeof (volatile struct B)); + memmove (&b, x, sizeof (volatile const struct B)); + memmove (&b, x, sizeof (TB)); + memmove (&b, x, sizeof (__typeof (*&b))); + memmove (pb1, x, sizeof (*pb1)); + memmove (pb2, x, sizeof (*pb3)); + memmove (pb3, x, sizeof (__typeof (*pb3))); + /* These are probably broken, but obfuscated, no warning. */ + memmove ((void *) &b, x, sizeof (&b)); + memmove ((char *) &b, x, sizeof (&b)); + memmove (&b, x, sizeof (&b) + 0); + memmove (&b, x, 0 + sizeof (&b)); + + /* These are correct, no warning. */ + memmove (x, &b, sizeof b); + memmove (x, &b, sizeof (b)); + memmove (x, &b, sizeof (struct B)); + memmove (x, &b, sizeof (const struct B)); + memmove (x, &b, sizeof (volatile struct B)); + memmove (x, &b, sizeof (volatile const struct B)); + memmove (x, &b, sizeof (TB)); + memmove (x, &b, sizeof (__typeof (*&b))); + memmove (x, pb1, sizeof (*pb1)); + memmove (x, pb2, sizeof (*pb3)); + memmove (x, pb3, sizeof (__typeof (*pb3))); + /* These are probably broken, but obfuscated, no warning. */ + memmove (x, (void *) &b, sizeof (&b)); + memmove (x, (char *) &b, sizeof (&b)); + memmove (x, &b, sizeof (&b) + 0); + memmove (x, &b, 0 + sizeof (&b)); + + /* These are correct, no warning. */ + z += memcmp (&b, x, sizeof b); + z += memcmp (&b, x, sizeof (b)); + z += memcmp (&b, x, sizeof (struct B)); + z += memcmp (&b, x, sizeof (const struct B)); + z += memcmp (&b, x, sizeof (volatile struct B)); + z += memcmp (&b, x, sizeof (volatile const struct B)); + z += memcmp (&b, x, sizeof (TB)); + z += memcmp (&b, x, sizeof (__typeof (*&b))); + z += memcmp (pb1, x, sizeof (*pb1)); + z += memcmp (pb2, x, sizeof (*pb3)); + z += memcmp (pb3, x, sizeof (__typeof (*pb3))); + /* These are probably broken, but obfuscated, no warning. */ + z += memcmp ((void *) &b, x, sizeof (&b)); + z += memcmp ((char *) &b, x, sizeof (&b)); + z += memcmp (&b, x, sizeof (&b) + 0); + z += memcmp (&b, x, 0 + sizeof (&b)); + + /* These are correct, no warning. */ + z += memcmp (x, &b, sizeof b); + z += memcmp (x, &b, sizeof (b)); + z += memcmp (x, &b, sizeof (struct B)); + z += memcmp (x, &b, sizeof (const struct B)); + z += memcmp (x, &b, sizeof (volatile struct B)); + z += memcmp (x, &b, sizeof (volatile const struct B)); + z += memcmp (x, &b, sizeof (TB)); + z += memcmp (x, &b, sizeof (__typeof (*&b))); + z += memcmp (x, pb1, sizeof (*pb1)); + z += memcmp (x, pb2, sizeof (*pb3)); + z += memcmp (x, pb3, sizeof (__typeof (*pb3))); + /* These are probably broken, but obfuscated, no warning. */ + z += memcmp (x, (void *) &b, sizeof (&b)); + z += memcmp (x, (char *) &b, sizeof (&b)); + z += memcmp (x, &b, sizeof (&b) + 0); + z += memcmp (x, &b, 0 + sizeof (&b)); + + return z; +} + +int +f3 (void *x, char *y, int z, X w) +{ + unsigned char *y1 = (unsigned char *) __builtin_alloca (z + 16); + char buf1[7]; + signed char buf2[z + 32]; + long buf3[17]; + int *buf4[9]; + signed char *y2 = buf2; + char c; + char *y3; + memset (y, 0, sizeof (y)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memset (y1, 0, sizeof (y1)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memset (y2, 0, sizeof (y2)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memset (&c, 0, sizeof (&c)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memset (w, 0, sizeof w); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + + memcpy (y, x, sizeof (y)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memcpy (y1, x, sizeof (y1)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memcpy (y2, x, sizeof (y2)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memcpy (&c, x, sizeof (&c)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memcpy (w, x, sizeof w); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + + memcpy (x, y, sizeof (y)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + memcpy (x, y1, sizeof (y1)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + memcpy (x, y2, sizeof (y2)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + memcpy (x, &c, sizeof (&c)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + memcpy (x, w, sizeof w); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + + memmove (y, x, sizeof (y)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memmove (y1, x, sizeof (y1)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memmove (y2, x, sizeof (y2)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + memmove (&c, x, sizeof (&c)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + memmove (w, x, sizeof w); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + + memmove (x, y, sizeof (y)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + memmove (x, y1, sizeof (y1)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + memmove (x, y2, sizeof (y2)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + memmove (x, &c, sizeof (&c)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + memmove (x, w, sizeof w); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + + z += memcmp (y, x, sizeof (y)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + z += memcmp (y1, x, sizeof (y1)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + z += memcmp (y2, x, sizeof (y2)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + z += memcmp (&c, x, sizeof (&c)); /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */ + z += memcmp (w, x, sizeof w); /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */ + + z += memcmp (x, y, sizeof (y)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + z += memcmp (x, y1, sizeof (y1)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + z += memcmp (x, y2, sizeof (y2)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + z += memcmp (x, &c, sizeof (&c)); /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */ + z += memcmp (x, w, sizeof w); /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */ + + /* These are correct, no warning. */ + memset (y, 0, sizeof (*y)); + memset (y1, 0, sizeof (*y2)); + memset (buf1, 0, sizeof buf1); + memset (buf3, 0, sizeof (buf3)); + memset (&buf3[0], 0, sizeof (buf3)); + memset (&buf4[0], 0, sizeof (buf4)); + memset (w, 0, sizeof (X)); + /* These are probably broken, but obfuscated, no warning. */ + memset ((void *) y, 0, sizeof (y)); + memset ((char *) y1, 0, sizeof (y2)); + memset (y, 0, sizeof (y) + 0); + memset (y1, 0, 0 + sizeof (y2)); + memset ((void *) &c, 0, sizeof (&c)); + memset ((signed char *) &c, 0, sizeof (&c)); + memset (&c, 0, sizeof (&c) + 0); + memset (&c, 0, 0 + sizeof (&c)); + + /* These are correct, no warning. */ + memcpy (y, x, sizeof (*y)); + memcpy (y1, x, sizeof (*y2)); + memcpy (buf1, x, sizeof buf1); + memcpy (buf3, x, sizeof (buf3)); + memcpy (&buf3[0], x, sizeof (buf3)); + memcpy (&buf4[0], x, sizeof (buf4)); + memcpy (&y3, y, sizeof (y3)); + memcpy ((char *) &y3, y, sizeof (y3)); + memcpy (w, x, sizeof (X)); + /* These are probably broken, but obfuscated, no warning. */ + memcpy ((void *) y, x, sizeof (y)); + memcpy ((char *) y1, x, sizeof (y2)); + memcpy (y, x, sizeof (y) + 0); + memcpy (y1, x, 0 + sizeof (y2)); + memcpy ((void *) &c, x, sizeof (&c)); + memcpy ((signed char *) &c, x, sizeof (&c)); + memcpy (&c, x, sizeof (&c) + 0); + memcpy (&c, x, 0 + sizeof (&c)); + + /* These are correct, no warning. */ + memcpy (x, y, sizeof (*y)); + memcpy (x, y1, sizeof (*y2)); + memcpy (x, buf1, sizeof buf1); + memcpy (x, buf3, sizeof (buf3)); + memcpy (x, &buf3[0], sizeof (buf3)); + memcpy (x, &buf4[0], sizeof (buf4)); + memcpy (y, &y3, sizeof (y3)); + memcpy (y, (char *) &y3, sizeof (y3)); + memcpy (x, w, sizeof (X)); + /* These are probably broken, but obfuscated, no warning. */ + memcpy (x, (void *) y, sizeof (y)); + memcpy (x, (char *) y1, sizeof (y2)); + memcpy (x, y, sizeof (y) + 0); + memcpy (x, y1, 0 + sizeof (y2)); + memcpy (x, (void *) &c, sizeof (&c)); + memcpy (x, (signed char *) &c, sizeof (&c)); + memcpy (x, &c, sizeof (&c) + 0); + memcpy (x, &c, 0 + sizeof (&c)); + + /* These are correct, no warning. */ + memmove (y, x, sizeof (*y)); + memmove (y1, x, sizeof (*y2)); + memmove (buf1, x, sizeof buf1); + memmove (buf3, x, sizeof (buf3)); + memmove (&buf3[0], x, sizeof (buf3)); + memmove (&buf4[0], x, sizeof (buf4)); + memmove (&y3, y, sizeof (y3)); + memmove ((char *) &y3, y, sizeof (y3)); + memmove (w, x, sizeof (X)); + /* These are probably broken, but obfuscated, no warning. */ + memmove ((void *) y, x, sizeof (y)); + memmove ((char *) y1, x, sizeof (y2)); + memmove (y, x, sizeof (y) + 0); + memmove (y1, x, 0 + sizeof (y2)); + memmove ((void *) &c, x, sizeof (&c)); + memmove ((signed char *) &c, x, sizeof (&c)); + memmove (&c, x, sizeof (&c) + 0); + memmove (&c, x, 0 + sizeof (&c)); + + /* These are correct, no warning. */ + memmove (x, y, sizeof (*y)); + memmove (x, y1, sizeof (*y2)); + memmove (x, buf1, sizeof buf1); + memmove (x, buf3, sizeof (buf3)); + memmove (x, &buf3[0], sizeof (buf3)); + memmove (x, &buf4[0], sizeof (buf4)); + memmove (y, &y3, sizeof (y3)); + memmove (y, (char *) &y3, sizeof (y3)); + memmove (x, w, sizeof (X)); + /* These are probably broken, but obfuscated, no warning. */ + memmove (x, (void *) y, sizeof (y)); + memmove (x, (char *) y1, sizeof (y2)); + memmove (x, y, sizeof (y) + 0); + memmove (x, y1, 0 + sizeof (y2)); + memmove (x, (void *) &c, sizeof (&c)); + memmove (x, (signed char *) &c, sizeof (&c)); + memmove (x, &c, sizeof (&c) + 0); + memmove (x, &c, 0 + sizeof (&c)); + + /* These are correct, no warning. */ + z += memcmp (y, x, sizeof (*y)); + z += memcmp (y1, x, sizeof (*y2)); + z += memcmp (buf1, x, sizeof buf1); + z += memcmp (buf3, x, sizeof (buf3)); + z += memcmp (&buf3[0], x, sizeof (buf3)); + z += memcmp (&buf4[0], x, sizeof (buf4)); + z += memcmp (&y3, y, sizeof (y3)); + z += memcmp ((char *) &y3, y, sizeof (y3)); + z += memcmp (w, x, sizeof (X)); + /* These are probably broken, but obfuscated, no warning. */ + z += memcmp ((void *) y, x, sizeof (y)); + z += memcmp ((char *) y1, x, sizeof (y2)); + z += memcmp (y, x, sizeof (y) + 0); + z += memcmp (y1, x, 0 + sizeof (y2)); + z += memcmp ((void *) &c, x, sizeof (&c)); + z += memcmp ((signed char *) &c, x, sizeof (&c)); + z += memcmp (&c, x, sizeof (&c) + 0); + z += memcmp (&c, x, 0 + sizeof (&c)); + + /* These are correct, no warning. */ + z += memcmp (x, y, sizeof (*y)); + z += memcmp (x, y1, sizeof (*y2)); + z += memcmp (x, buf1, sizeof buf1); + z += memcmp (x, buf3, sizeof (buf3)); + z += memcmp (x, &buf3[0], sizeof (buf3)); + z += memcmp (x, &buf4[0], sizeof (buf4)); + z += memcmp (y, &y3, sizeof (y3)); + z += memcmp (y, (char *) &y3, sizeof (y3)); + z += memcmp (x, w, sizeof (X)); + /* These are probably broken, but obfuscated, no warning. */ + z += memcmp (x, (void *) y, sizeof (y)); + z += memcmp (x, (char *) y1, sizeof (y2)); + z += memcmp (x, y, sizeof (y) + 0); + z += memcmp (x, y1, 0 + sizeof (y2)); + z += memcmp (x, (void *) &c, sizeof (&c)); + z += memcmp (x, (signed char *) &c, sizeof (&c)); + z += memcmp (x, &c, sizeof (&c) + 0); + z += memcmp (x, &c, 0 + sizeof (&c)); + + return z; +} + +int +f4 (char *x, char **y, int z) +{ + const char *s1 = "foobarbaz"; + const char *s2 = "abcde12345678"; + strncpy (x, s1, sizeof (s1)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + strncat (x, s2, sizeof (s2)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + y[0] = strndup (s1, sizeof (s1)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + z += strncmp (s1, s2, sizeof (s1)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + z += strncmp (s1, s2, sizeof (s2)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + z += strncasecmp (s1, s2, sizeof (s1)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ + z += strncasecmp (s1, s2, sizeof (s2)); /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */ + + /* These are correct, no warning. */ + const char s3[] = "foobarbaz"; + const char s4[] = "abcde12345678"; + strncpy (x, s3, sizeof (s3)); + strncat (x, s4, sizeof (s4)); + y[1] = strndup (s3, sizeof (s3)); + z += strncmp (s3, s4, sizeof (s3)); + z += strncmp (s3, s4, sizeof (s4)); + z += strncasecmp (s3, s4, sizeof (s3)); + z += strncasecmp (s3, s4, sizeof (s4)); + + return z; +} + +/* { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" } */