public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC PATCH] -Wsizeof-pointer-memaccess warning
@ 2012-07-18 12:40 Jakub Jelinek
  2012-07-19 10:47 ` Paolo Carlini
  2012-08-15 15:39 ` Joseph S. Myers
  0 siblings, 2 replies; 13+ messages in thread
From: Jakub Jelinek @ 2012-07-18 12:40 UTC (permalink / raw)
  To: gcc-patches; +Cc: Joseph S. Myers, Jason Merrill, Paolo Carlini

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  <jakub@redhat.com>

	* 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.

--- 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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\]*" } */

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] -Wsizeof-pointer-memaccess warning
  2012-07-18 12:40 [RFC PATCH] -Wsizeof-pointer-memaccess warning Jakub Jelinek
@ 2012-07-19 10:47 ` Paolo Carlini
  2012-07-19 13:17   ` Jakub Jelinek
  2012-08-15 15:39 ` Joseph S. Myers
  1 sibling, 1 reply; 13+ messages in thread
From: Paolo Carlini @ 2012-07-19 10:47 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Joseph S. Myers, Jason Merrill

Hi,

On 07/18/2012 02:40 PM, Jakub Jelinek wrote:
> 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.
I have a couple of random comments. About the folding, I'm wondering if 
our current behavior is causing actual bugs (similarly to, eg, all the 
issues we have with arrays decaying to pointers too early). Otherwise, 
the implementation of the warning itself seems to me a little ad hoc 
indeed, but simple enough.

Unrelated, but I can't resist, it would be great if for 4.8 we could 
also eliminate the duplicate diagnostics noticed in 28656, does that 
look doable?!? If you have hints I could also do it, in practice.

Thanks!
Paolo.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] -Wsizeof-pointer-memaccess warning
  2012-07-19 10:47 ` Paolo Carlini
@ 2012-07-19 13:17   ` Jakub Jelinek
  2012-07-19 14:59     ` Paolo Carlini
  0 siblings, 1 reply; 13+ messages in thread
From: Jakub Jelinek @ 2012-07-19 13:17 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches, Joseph S. Myers, Jason Merrill

On Thu, Jul 19, 2012 at 12:47:21PM +0200, Paolo Carlini wrote:
> On 07/18/2012 02:40 PM, Jakub Jelinek wrote:
> >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.
> I have a couple of random comments. About the folding, I'm wondering
> if our current behavior is causing actual bugs (similarly to, eg,
> all the issues we have with arrays decaying to pointers too early).

I don't think it causes any issues appart from making it harder to do static
analysis.  On the C FE side I can still imagine emitting SIZEOF_EXPR always
and only folding that during c_fully_fold_internal, but I don't see anything
similar on the C++ FE side, and there we often rely on the folding of
various things say for template parameters and what not else.
For processing_template_decl I believe it is fairly easily implementable,
but for !processing_template_decl I currently don't see an easy way to avoid
the hack I wrote for the C FE.  Jason?

> Otherwise, the implementation of the warning itself seems to me a
> little ad hoc indeed, but simple enough.

Also the c-family/ part of it, or just the c/ part?  The latter I admit is
not very nice (another ugliness is that we want the parameters before doing
standard argument promotions on them).

> Unrelated, but I can't resist, it would be great if for 4.8 we could
> also eliminate the duplicate diagnostics noticed in 28656, does that
> look doable?!? If you have hints I could also do it, in practice.

The problem there is that memcpy (and I guess many others) ends up with more
than one nonnull attribute.  Untested patch in the PR now.

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] -Wsizeof-pointer-memaccess warning
  2012-07-19 13:17   ` Jakub Jelinek
@ 2012-07-19 14:59     ` Paolo Carlini
  0 siblings, 0 replies; 13+ messages in thread
From: Paolo Carlini @ 2012-07-19 14:59 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Joseph S. Myers, Jason Merrill

Hi,

On 07/19/2012 03:16 PM, Jakub Jelinek wrote:
> Also the c-family/ part of it, or just the c/ part? The latter I admit 
> is not very nice (another ugliness is that we want the parameters 
> before doing standard argument promotions on them). 
The latter, the latter.
>> Unrelated, but I can't resist, it would be great if for 4.8 we could
>> also eliminate the duplicate diagnostics noticed in 28656, does that
>> look doable?!? If you have hints I could also do it, in practice.
> The problem there is that memcpy (and I guess many others) ends up with more
> than one nonnull attribute.  Untested patch in the PR now.
Thanks!

Paolo.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] -Wsizeof-pointer-memaccess warning
  2012-07-18 12:40 [RFC PATCH] -Wsizeof-pointer-memaccess warning Jakub Jelinek
  2012-07-19 10:47 ` Paolo Carlini
@ 2012-08-15 15:39 ` Joseph S. Myers
  2012-08-15 15:54   ` Jakub Jelinek
  1 sibling, 1 reply; 13+ messages in thread
From: Joseph S. Myers @ 2012-08-15 15:39 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Jason Merrill, Paolo Carlini

On Wed, 18 Jul 2012, Jakub Jelinek wrote:

> +	  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);

Why do you pass a local variable sizeof_arg but a global 
c_last_sizeof_arg_loc here?  I'd have expected the same approach to apply 
for both arguments (e.g. passing down a pointer to a location alongside 
&sizeof_arg).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-15 15:39 ` Joseph S. Myers
@ 2012-08-15 15:54   ` Jakub Jelinek
  2012-08-15 16:30     ` Joseph S. Myers
  0 siblings, 1 reply; 13+ messages in thread
From: Jakub Jelinek @ 2012-08-15 15:54 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches, Jason Merrill, Paolo Carlini

On Wed, Aug 15, 2012 at 03:39:29PM +0000, Joseph S. Myers wrote:
> On Wed, 18 Jul 2012, Jakub Jelinek wrote:
> 
> > +	  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);
> 
> Why do you pass a local variable sizeof_arg but a global 
> c_last_sizeof_arg_loc here?  I'd have expected the same approach to apply 
> for both arguments (e.g. passing down a pointer to a location alongside 
> &sizeof_arg).

I guess I could pass it the same way as sizeof_arg or stick the location_t
into sizeof_arg (surround the value into NOP_EXPR with the location_t).

I was mainly interested in whether such an approach is acceptable, or
whether I need to stop evaluating sizeof right away, create SIZEOF_EXPR
and only fold it during fully_fold*.  I've briefly looked at that today,
and see several problems with that though: 1) fully_fold* is in c-family/,
so can't use e.g. c_vla_type_p (at least not easily, it could use a
langhook) 2) c_expr_sizeof_{expr,type} currently calls pop_maybe_used,
I don't see how that could be easily deferred till later when the expression
is fully folded.  So, we might need to do what c_expr_sizeof_{expr,type}
does right now (including fully folding), to call pop_maybe_used with the
right argument, and then either create SIZEOF_EXPR with the original
argument and fully fold it again during fully folding of the SIZEOF_EXPR,
or add an argument to SIZEOF_EXPR which would contain the folded expression
(i.e. have two arguments, the original expression and the value of the
sizeof).

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-15 15:54   ` Jakub Jelinek
@ 2012-08-15 16:30     ` Joseph S. Myers
  2012-08-16 19:14       ` [C " Jakub Jelinek
  0 siblings, 1 reply; 13+ messages in thread
From: Joseph S. Myers @ 2012-08-15 16:30 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Jason Merrill, Paolo Carlini

On Wed, 15 Aug 2012, Jakub Jelinek wrote:

> I was mainly interested in whether such an approach is acceptable, or
> whether I need to stop evaluating sizeof right away, create SIZEOF_EXPR
> and only fold it during fully_fold*.  I've briefly looked at that today,

The approach is fine.  Delaying evaluating sizeof is hard simply because 
of the expectation that integer constant expressions in general are 
evaluated early.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-15 16:30     ` Joseph S. Myers
@ 2012-08-16 19:14       ` Jakub Jelinek
  2012-08-16 21:32         ` Joseph S. Myers
  2012-08-17 12:53         ` Florian Weimer
  0 siblings, 2 replies; 13+ messages in thread
From: Jakub Jelinek @ 2012-08-16 19:14 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches, Jason Merrill, Paolo Carlini

Hi!

On Wed, Aug 15, 2012 at 04:29:55PM +0000, Joseph S. Myers wrote:
> On Wed, 15 Aug 2012, Jakub Jelinek wrote:
> 
> > I was mainly interested in whether such an approach is acceptable, or
> > whether I need to stop evaluating sizeof right away, create SIZEOF_EXPR
> > and only fold it during fully_fold*.  I've briefly looked at that today,
> 
> The approach is fine.  Delaying evaluating sizeof is hard simply because 
> of the expectation that integer constant expressions in general are 
> evaluated early.

Ok, thanks.  Here is an updated patch, which gets away just with one global
variable (location_t computed from token after sizeof keyword in the
caller).  Bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk?

The fortran/ change is a bug that the patch discovered in the gcc
sources (well, as we now bootstrap with C++ it was actually the C++ patch
I'm going to post momentarily).

2012-08-16  Jakub Jelinek  <jakub@redhat.com>

	* doc/invoke.texi (-Wsizeof-pointer-memaccess): Document.
c/
	* c-tree.h (c_last_sizeof_arg): Declare.
	* c-parser.c (struct c_tree_loc_pair): New type.
	(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): New global variable.
	(c_expr_sizeof_expr, c_expr_sizeof_type): Initialize it.
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.
fortran/
	* array.c (gfc_match_array_ref): Fix up memset arguments.
testsuite/
	* gcc.dg/torture/Wsizeof-pointer-memaccess1.c: New test.

--- gcc/c/c-tree.h.jj	2012-08-15 11:30:33.045649950 +0200
+++ gcc/c/c-tree.h	2012-08-16 10:28:05.423879815 +0200
@@ -573,6 +573,8 @@ extern int in_alignof;
 extern int in_sizeof;
 extern int in_typeof;
 
+extern tree c_last_sizeof_arg;
+
 extern struct c_switch *c_switch_stack;
 
 extern tree c_objc_common_truthvalue_conversion (location_t, tree);
--- gcc/c/c-parser.c.jj	2012-08-15 11:30:32.987650235 +0200
+++ gcc/c/c-parser.c	2012-08-16 10:41:10.820017698 +0200
@@ -1111,6 +1111,12 @@ enum c_parser_prec {
   NUM_PRECS
 };
 
+/* Expression and its location.  */
+struct c_tree_loc_pair {
+  tree expr;
+  location_t loc;
+};
+
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
@@ -1179,7 +1185,8 @@ 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) **,
+					 struct c_tree_loc_pair *);
 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 +3585,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 +3598,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 +6854,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.
 
@@ -6857,6 +6875,7 @@ c_parser_postfix_expression_after_primar
 {
   struct c_expr orig_expr;
   tree ident, idx;
+  struct c_tree_loc_pair sizeof_arg;
   VEC(tree,gc) *exprlist;
   VEC(tree,gc) *origtypes;
   while (true)
@@ -6877,14 +6896,22 @@ c_parser_postfix_expression_after_primar
 	case CPP_OPEN_PAREN:
 	  /* Function call.  */
 	  c_parser_consume_token (parser);
+	  sizeof_arg.expr = 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.expr != NULL_TREE)
+	    sizeof_pointer_memaccess_warning (sizeof_arg.loc,
+					      expr.value, exprlist,
+					      sizeof_arg.expr,
+					      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,12 +7072,14 @@ 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,
+		    struct c_tree_loc_pair *sizeof_arg)
 {
   VEC(tree,gc) *ret;
   VEC(tree,gc) *orig_types;
   struct c_expr expr;
   location_t loc = c_parser_peek_token (parser)->location;
+  location_t sizeof_arg_loc = UNKNOWN_LOCATION;
 
   ret = make_tree_vector ();
   if (p_orig_types == NULL)
@@ -7058,6 +7087,9 @@ c_parser_expr_list (c_parser *parser, bo
   else
     orig_types = make_tree_vector ();
 
+  if (sizeof_arg != NULL
+      && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
+    sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
   expr = c_parser_expr_no_commas (parser, NULL);
   if (convert_p)
     expr = default_function_array_read_conversion (loc, expr);
@@ -7070,6 +7102,11 @@ c_parser_expr_list (c_parser *parser, bo
     {
       c_parser_consume_token (parser);
       loc = c_parser_peek_token (parser)->location;
+      if (sizeof_arg != NULL
+	  && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
+	sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
+      else
+	sizeof_arg_loc = UNKNOWN_LOCATION;
       expr = c_parser_expr_no_commas (parser, NULL);
       if (convert_p)
 	expr = default_function_array_read_conversion (loc, expr);
@@ -7079,6 +7116,20 @@ c_parser_expr_list (c_parser *parser, bo
       if (orig_types != NULL)
 	VEC_safe_push (tree, gc, orig_types, expr.original_type);
     }
+  if (sizeof_arg != NULL)
+    {
+      if (sizeof_arg_loc != UNKNOWN_LOCATION
+	  && expr.original_code == SIZEOF_EXPR)
+	{
+	  sizeof_arg->expr = c_last_sizeof_arg;
+	  sizeof_arg->loc = sizeof_arg_loc;
+	}
+      else
+	{
+	  sizeof_arg->expr = NULL_TREE;
+	  sizeof_arg->loc = UNKNOWN_LOCATION;
+	}
+    }
   if (orig_types != NULL)
     *p_orig_types = orig_types;
   return ret;
@@ -8157,7 +8208,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-08-15 11:30:33.002650161 +0200
+++ gcc/c/c-typeck.c	2012-08-16 10:28:21.134802412 +0200
@@ -67,6 +67,10 @@ 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;
+
 /* Nonzero if we've already printed a "missing braces around initializer"
    message within this initializer.  */
 static int missing_braces_mentioned;
@@ -2603,7 +2607,8 @@ 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;
+      ret.original_code = SIZEOF_EXPR;
       ret.original_type = NULL;
       if (c_vla_type_p (TREE_TYPE (folded_expr)))
 	{
@@ -2631,7 +2636,8 @@ 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;
+  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	2012-08-15 11:30:32.241653899 +0200
+++ gcc/cp/cp-tree.def	2012-08-16 10:16:11.064380908 +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-08-16 10:15:36.297550048 +0200
+++ gcc/doc/invoke.texi	2012-08-16 10:16:11.070380880 +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
@@ -4327,6 +4327,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-08-15 11:30:31.961655279 +0200
+++ gcc/c-family/c-common.c	2012-08-16 10:16:11.074380858 +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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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 %<sizeof%> 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-08-15 11:30:32.079654704 +0200
+++ gcc/c-family/c.opt	2012-08-16 10:16:11.076380847 +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-08-15 11:30:31.923655462 +0200
+++ gcc/c-family/c-opts.c	2012-08-16 10:16:11.076380847 +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-08-15 11:30:31.986655156 +0200
+++ gcc/c-family/c-common.h	2012-08-16 10:16:11.077380843 +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	2012-08-15 11:30:32.033654924 +0200
+++ gcc/c-family/c-common.def	2012-08-16 10:16:11.077380843 +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/fortran/array.c.jj	2012-08-10 15:49:17.000000000 +0200
+++ gcc/fortran/array.c	2012-08-16 17:59:38.941821058 +0200
@@ -159,7 +159,7 @@ gfc_match_array_ref (gfc_array_ref *ar,
   match m;
   bool matched_bracket = false;
 
-  memset (ar, '\0', sizeof (ar));
+  memset (ar, '\0', sizeof (*ar));
 
   ar->where = gfc_current_locus;
   ar->as = as;
--- gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c.jj	2012-08-16 10:16:11.078380839 +0200
+++ gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c	2012-08-16 10:16:11.078380839 +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\]*" } */


	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-16 19:14       ` [C " Jakub Jelinek
@ 2012-08-16 21:32         ` Joseph S. Myers
  2012-08-17 12:53         ` Florian Weimer
  1 sibling, 0 replies; 13+ messages in thread
From: Joseph S. Myers @ 2012-08-16 21:32 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Jason Merrill, Paolo Carlini

On Thu, 16 Aug 2012, Jakub Jelinek wrote:

> Hi!
> 
> On Wed, Aug 15, 2012 at 04:29:55PM +0000, Joseph S. Myers wrote:
> > On Wed, 15 Aug 2012, Jakub Jelinek wrote:
> > 
> > > I was mainly interested in whether such an approach is acceptable, or
> > > whether I need to stop evaluating sizeof right away, create SIZEOF_EXPR
> > > and only fold it during fully_fold*.  I've briefly looked at that today,
> > 
> > The approach is fine.  Delaying evaluating sizeof is hard simply because 
> > of the expectation that integer constant expressions in general are 
> > evaluated early.
> 
> Ok, thanks.  Here is an updated patch, which gets away just with one global
> variable (location_t computed from token after sizeof keyword in the
> caller).  Bootstrapped/regtested on x86_64-linux and i686-linux, ok for
> trunk?

This version is OK.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-16 19:14       ` [C " Jakub Jelinek
  2012-08-16 21:32         ` Joseph S. Myers
@ 2012-08-17 12:53         ` Florian Weimer
  2012-08-17 13:14           ` Jakub Jelinek
  1 sibling, 1 reply; 13+ messages in thread
From: Florian Weimer @ 2012-08-17 12:53 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Joseph S. Myers, gcc-patches, Jason Merrill, Paolo Carlini

On 08/16/2012 09:10 PM, Jakub Jelinek wrote:

> +  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;
> +    }

I think this would apply to memchr, snprintf, vsnprintf, stpncopy, 
bzero, bcopy, bcmp as well.  Or are some of them already lowered at this 
point?

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-17 12:53         ` Florian Weimer
@ 2012-08-17 13:14           ` Jakub Jelinek
  2012-08-17 13:27             ` Florian Weimer
  0 siblings, 1 reply; 13+ messages in thread
From: Jakub Jelinek @ 2012-08-17 13:14 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Joseph S. Myers, gcc-patches, Jason Merrill, Paolo Carlini

On Fri, Aug 17, 2012 at 02:52:34PM +0200, Florian Weimer wrote:
> >+    {
> >+    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;
> >+    }
> 
> I think this would apply to memchr, snprintf, vsnprintf, stpncopy,
> bzero, bcopy, bcmp as well.  Or are some of them already lowered at
> this point?

s/stpncopy/stpncpy/, yeah, I guess, we could do that for those too,
but 1) I'd prefer to wait for the C++ FE change to go in first
2) {,v}snprintf would be much harder than the rest, as the size
argument then isn't the last argument to the function, and the FEs
only provide the last one right now.  The parser routine which parses
arguments doesn't know which fn it will be for, recording sizeof_arg
(including location_t) for all arguments would be an overkill,
perhaps we could record instead the first sizeof argument + its position in
the argument list.  That would not catch say
memset (ptr, sizeof (int), sizeof (ptr));
(as it would record 2nd argument, expr int and locus), but perhaps it is so
rare to use sizeof on second argument of memset that it doesn't matter.
On the other side it would help if somebody calls __builtin___memset_chk
and similar explicitly (sizeof in that case isn't the last argument, but
3rd), the above switch then could handle also BUILT_IN_*CHK.
That said, usually -D_FORTIFY_SOURCE is done through the string.h
wrapper inlines and that is handled already (and tested in the testcases).

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-17 13:14           ` Jakub Jelinek
@ 2012-08-17 13:27             ` Florian Weimer
  2012-08-17 13:34               ` Jakub Jelinek
  0 siblings, 1 reply; 13+ messages in thread
From: Florian Weimer @ 2012-08-17 13:27 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Joseph S. Myers, gcc-patches, Jason Merrill, Paolo Carlini

On 08/17/2012 03:09 PM, Jakub Jelinek wrote:

> s/stpncopy/stpncpy/, yeah, I guess, we could do that for those too,
> but 1) I'd prefer to wait for the C++ FE change to go in first
> 2) {,v}snprintf would be much harder than the rest, as the size
> argument then isn't the last argument to the function, and the FEs
> only provide the last one right now.

Could you pick the second argument for varargs functions?  Incredibly 
hacky, but would do the trick for those two.  Or does the FE not know at 
this point it is processing a varargs function?

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-17 13:27             ` Florian Weimer
@ 2012-08-17 13:34               ` Jakub Jelinek
  0 siblings, 0 replies; 13+ messages in thread
From: Jakub Jelinek @ 2012-08-17 13:34 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Joseph S. Myers, gcc-patches, Jason Merrill, Paolo Carlini

On Fri, Aug 17, 2012 at 03:26:34PM +0200, Florian Weimer wrote:
> On 08/17/2012 03:09 PM, Jakub Jelinek wrote:
> 
> >s/stpncopy/stpncpy/, yeah, I guess, we could do that for those too,
> >but 1) I'd prefer to wait for the C++ FE change to go in first
> >2) {,v}snprintf would be much harder than the rest, as the size
> >argument then isn't the last argument to the function, and the FEs
> >only provide the last one right now.
> 
> Could you pick the second argument for varargs functions?
> Incredibly hacky, but would do the trick for those two.  Or does the
> FE not know at this point it is processing a varargs function?

Yeah, it doesn't know that.
What could perhaps work for all the builtins that makes sense to warn for is
to record the third argument if it is a sizeof, or, if that one isn't a
sizeof, record the second argument if it is a sizeof.

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2012-08-17 13:34 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-18 12:40 [RFC PATCH] -Wsizeof-pointer-memaccess warning Jakub Jelinek
2012-07-19 10:47 ` Paolo Carlini
2012-07-19 13:17   ` Jakub Jelinek
2012-07-19 14:59     ` Paolo Carlini
2012-08-15 15:39 ` Joseph S. Myers
2012-08-15 15:54   ` Jakub Jelinek
2012-08-15 16:30     ` Joseph S. Myers
2012-08-16 19:14       ` [C " Jakub Jelinek
2012-08-16 21:32         ` Joseph S. Myers
2012-08-17 12:53         ` Florian Weimer
2012-08-17 13:14           ` Jakub Jelinek
2012-08-17 13:27             ` Florian Weimer
2012-08-17 13:34               ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).