This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: gcc: Multiple checkers, to allow for warn() semantics


This is a cleaned-up patch to support __nonnull__ (mostly fixed-up comments
and minor formatting issues), so that you can
declare, e.g.,

size_t strlen(const char *) attribute((nonnull(1)));
or
int strcmp(const char *, const char *) attribute((nonnull(1), nonnull(2)));


First, I'd like to know whether this looks reasonable.


Second, I see two possible simple extensions of that nonnull attribute.
- being able to specify several argument positions to check in one sweep,
  e.g.,
int strcmp(const char *, const char *) attribute((nonnull(1, 2)));
this is easy to do. I just need a specific value of maxlength, say -1, 
to mean that attributes can take any number of arguments, and to tweak the 
internal representation of nonnull_info slightly.
- having an abbreviated form, e.g., in
int strcmp(const char *, const char *) attribute((nonnull));
would mean that all pointer arguments in the prototype would get the
non-null checking... Obviously such an attribute only works with a full
prototype, and will abort if it's specified otherwise.

Think this would be worth it ?  

I will write the corresponding extend.texi changes once we decide on that
second point.

ChangeLog entry.
Wed Jan  5 18:08:39 CET 2000	Marc Espie	<espie@cvs.openbsd.org>

	* c-common.c:  Update copyright.
	(A_NONNULL):  New attribute.
	(init_attribute):  Record A_NONNULL.
	(record_function_format, record_international_format):  Remove.
	(insert_function_attribute):  New, replacement for record_xxx.
	(function_attribute_info, function_attributes_info):  New types.
	(new_function_format, new_international_format, new_nonnull_info):
	Corresponding constructors.
	(decl_attributes):  Handle A_NONNULL, modify A_FORMAT and
	A_FORMAT_ARG for new framework.
	(function_format_info, international_format_info):  Fit with
	function_attribute(s)_info.
	(function_attribute_list):  New variable, replaces...
	(function_format_list, international_format_list):  Remove.
	(add_function_format):  New, helper for init_format_info.
	(init_format_info):  Adjust format attributes.
	(check_function_format):  Handle A_FORMAT and A_NONNULL attributes.
	(find_function_attribute, reduce_pointer):  New.
	(check_nonnull_info):  New, check A_NONNULL.
	(check_format_info):  Use helper functions, remove non-null pointer
	checks.

*** gcc/c-common.c.orig	Tue Jan  4 17:15:12 2000
--- gcc/c-common.c	Wed Jan  5 17:57:43 2000
***************
*** 1,5 ****
  /* Subroutines shared by all languages that are variants of C.
!    Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc.
  
  This file is part of GNU CC.
  
--- 1,5 ----
  /* Subroutines shared by all languages that are variants of C.
!    Copyright (C) 1992, 93-99, 2000 Free Software Foundation, Inc.
  
  This file is part of GNU CC.
  
*************** int skip_evaluation;
*** 54,60 ****
  enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
  	    A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
  	    A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
! 	    A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS};
  
  enum format_type { printf_format_type, scanf_format_type,
  		   strftime_format_type };
--- 54,60 ----
  enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
  	    A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
  	    A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
! 	    A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_NONNULL};
  
  enum format_type { printf_format_type, scanf_format_type,
  		   strftime_format_type };
*************** static void declare_hidden_char_array	PR
*** 63,71 ****
  static void add_attribute		PROTO((enum attrs, const char *,
  					       int, int, int));
  static void init_attributes		PROTO((void));
- static void record_function_format	PROTO((tree, tree, enum format_type,
- 					       int, int));
- static void record_international_format	PROTO((tree, tree, int));
  static tree c_find_base_decl            PROTO((tree));
  static int default_valid_lang_attribute PROTO ((tree, tree, tree, tree));
  
--- 63,68 ----
*************** init_attributes ()
*** 391,396 ****
--- 388,394 ----
    add_attribute (A_ALIGNED, "aligned", 0, 1, 0);
    add_attribute (A_FORMAT, "format", 3, 3, 1);
    add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
+   add_attribute (A_NONNULL, "nonnull", 1, 1, 1);
    add_attribute (A_WEAK, "weak", 0, 0, 1);
    add_attribute (A_ALIAS, "alias", 1, 1, 1);
    add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
*************** default_valid_lang_attribute (attr_name,
*** 416,421 ****
--- 414,441 ----
  int (*valid_lang_attribute) PROTO ((tree, tree, tree, tree))
       = default_valid_lang_attribute;
  
+ typedef struct function_attribute_info
+ {
+   struct function_attribute_info *next;
+   enum attrs type;
+   /* data added there */
+ } function_attribute_info;
+ 
+ typedef struct function_attributes_info
+ {
+   struct function_attributes_info *next;  /* next structure on the list */
+   tree name;			/* identifier such as "printf" */
+   tree assembler_name;		/* optional mangled identifier (for C++) */
+   function_attribute_info *first;
+ } function_attributes_info;
+ 
+ static function_attribute_info *new_function_format 
+   PROTO((enum format_type, int, int));
+ static function_attribute_info *new_international_format PROTO((int));
+ static function_attribute_info *new_nonnull_info PROTO((int));
+ static function_attributes_info *insert_function_attribute
+   PROTO((function_attributes_info *, tree, tree, function_attribute_info *));
+ 
  /* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES
     and install them in NODE, which is either a DECL (including a TYPE_DECL)
     or a TYPE.  PREFIX_ATTRIBUTES can appear after the declaration specifiers
*************** decl_attributes (node, attributes, prefi
*** 428,433 ****
--- 448,454 ----
    tree decl = 0, type = 0;
    int is_type = 0;
    tree a;
+   function_attributes_info *list = NULL;
  
    if (attrtab_idx == 0)
      init_attributes ();
*************** decl_attributes (node, attributes, prefi
*** 810,818 ****
  		  }
  	      }
  
! 	    record_function_format (DECL_NAME (decl),
! 				    DECL_ASSEMBLER_NAME (decl),
! 				    format_type, format_num, first_arg_num);
  	    break;
  	  }
  
--- 831,839 ----
  		  }
  	      }
  
! 	    list = insert_function_attribute (list, DECL_NAME (decl),
! 	      DECL_ASSEMBLER_NAME (decl),
! 	      new_function_format (format_type, format_num, first_arg_num));
  	    break;
  	  }
  
*************** decl_attributes (node, attributes, prefi
*** 874,882 ****
  		continue;
  	      }
  
! 	    record_international_format (DECL_NAME (decl),
! 					 DECL_ASSEMBLER_NAME (decl),
! 					 format_num);
  	    break;
  	  }
  
--- 895,957 ----
  		continue;
  	      }
  
! 	    list = insert_function_attribute (list, DECL_NAME (decl),
! 	      DECL_ASSEMBLER_NAME (decl),
! 	      new_international_format (format_num));
! 	    break;
! 	  }
! 
! 	case A_NONNULL:
! 	  {
! 	    tree argument;
! 	    tree arg_num_expr = TREE_VALUE (args);
! 	    int arg_num, ck_num;
! 
! 	    if (TREE_CODE (decl) != FUNCTION_DECL)
! 	      {
! 		error_with_decl (decl,
! 			 "argument format specified for non-function `%s'");
! 		continue;
! 	      }
! 	
! 	    /* Strip any conversions from the arg number
! 	       and verify they are constants.  */
! 	    while (TREE_CODE (arg_num_expr) == NOP_EXPR
! 		   || TREE_CODE (arg_num_expr) == CONVERT_EXPR
! 		   || TREE_CODE (arg_num_expr) == NON_LVALUE_EXPR)
! 	      arg_num_expr = TREE_OPERAND (arg_num_expr, 0);
! 
! 
! 	    if (TREE_CODE (arg_num_expr) != INTEGER_CST)
! 	      {
! 		error ("format string has non-constant operand number");
! 		continue;
! 	      }
! 
! 	    arg_num = TREE_INT_CST_LOW (arg_num_expr);
! 
! 	    /* If a parameter list is specified, verify that the arg_num
! 	       argument is actually a pointer, in case the attribute
! 	       is in error.  */
! 	    argument = TYPE_ARG_TYPES (type);
! 	    if (argument)
! 	      {
! 		for (ck_num = 1; ; ++ck_num)
! 		  {
! 		    if (argument == 0 || ck_num == arg_num)
! 		      break;
! 		    argument = TREE_CHAIN (argument);
! 		  }
! 		if (! argument
! 		    || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
! 		  {
! 		    error ("non-null argument not a pointer type");
! 		    continue;
! 		  }
! 	      }
! 
! 	    list = insert_function_attribute (list, DECL_NAME (decl),
! 	      DECL_ASSEMBLER_NAME (decl), new_nonnull_info (arg_num));
  	    break;
  	  }
  
*************** static format_char_info time_char_table[
*** 1144,1172 ****
    { NULL,		0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
  };
  
  typedef struct function_format_info
  {
!   struct function_format_info *next;  /* next structure on the list */
!   tree name;			/* identifier such as "printf" */
!   tree assembler_name;		/* optional mangled identifier (for C++) */
    enum format_type format_type;	/* type of format (printf, scanf, etc.) */
    int format_num;		/* number of format argument */
    int first_arg_num;		/* number of first arg (zero for varargs) */
  } function_format_info;
  
- static function_format_info *function_format_list = NULL;
- 
  typedef struct international_format_info
  {
!   struct international_format_info *next;  /* next structure on the list */
!   tree name;			/* identifier such as "gettext" */
!   tree assembler_name;		/* optional mangled identifier (for C++) */
    int format_num;		/* number of format argument */
  } international_format_info;
  
! static international_format_info *international_format_list = NULL;
  
  static void check_format_info		PROTO((function_format_info *, tree));
  
  /* Initialize the table of functions to perform format checking on.
     The ANSI functions are always checked (whether <stdio.h> is
--- 1219,1276 ----
    { NULL,		0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
  };
  
+ 
+ static function_attributes_info *function_attributes_list = NULL;
+ 
+ /* Specialized flavors of function_attribute_info.  */
+ 
  typedef struct function_format_info
  {
!   struct function_attribute_info *next;
!   enum attrs type;
    enum format_type format_type;	/* type of format (printf, scanf, etc.) */
    int format_num;		/* number of format argument */
    int first_arg_num;		/* number of first arg (zero for varargs) */
  } function_format_info;
  
  typedef struct international_format_info
  {
!   struct function_attribute_info *next;
!   enum attrs type;
    int format_num;		/* number of format argument */
  } international_format_info;
  
! typedef struct nonnull_info
! {
!   struct function_attribute_info *next;
!   enum attrs type;
!   int argument_num;		/* number of non-null argument */
! } nonnull_info;
! 
! static function_attribute_info *find_function_attribute
!   PROTO((tree, tree, enum attrs));
  
  static void check_format_info		PROTO((function_format_info *, tree));
+ static void check_nonnull_info 		PROTO((nonnull_info *, tree));
+ 
+ /* Helper function for setting up initial attribute for printf-like
+    functions, since the format argument is also non-null checked for
+    those.  */
+ 
+ static void
+ add_function_format (name, type, arg1, arg2)
+      const char *name;
+      enum format_type type;
+      int arg1;
+      int arg2;
+ {
+   tree t = get_identifier (name);
+   insert_function_attribute (insert_function_attribute (NULL, t, NULL_TREE,
+                                new_function_format(type, arg1, arg2)),
+ 			     t,
+ 			     NULL_TREE,
+ 			     new_nonnull_info (arg1));
+ }
  
  /* Initialize the table of functions to perform format checking on.
     The ANSI functions are always checked (whether <stdio.h> is
*************** static void check_format_info		PROTO((fu
*** 1181,1289 ****
  void
  init_function_format_info ()
  {
!   record_function_format (get_identifier ("printf"), NULL_TREE,
! 			  printf_format_type, 1, 2);
!   record_function_format (get_identifier ("fprintf"), NULL_TREE,
! 			  printf_format_type, 2, 3);
!   record_function_format (get_identifier ("sprintf"), NULL_TREE,
! 			  printf_format_type, 2, 3);
!   record_function_format (get_identifier ("scanf"), NULL_TREE,
! 			  scanf_format_type, 1, 2);
!   record_function_format (get_identifier ("fscanf"), NULL_TREE,
! 			  scanf_format_type, 2, 3);
!   record_function_format (get_identifier ("sscanf"), NULL_TREE,
! 			  scanf_format_type, 2, 3);
!   record_function_format (get_identifier ("vprintf"), NULL_TREE,
! 			  printf_format_type, 1, 0);
!   record_function_format (get_identifier ("vfprintf"), NULL_TREE,
! 			  printf_format_type, 2, 0);
!   record_function_format (get_identifier ("vsprintf"), NULL_TREE,
! 			  printf_format_type, 2, 0);
!   record_function_format (get_identifier ("strftime"), NULL_TREE,
! 			  strftime_format_type, 3, 0);
! 
!   record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
!   record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
!   record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
! }
! 
! /* Record information for argument format checking.  FUNCTION_IDENT is
!    the identifier node for the name of the function to check (its decl
!    need not exist yet).
!    FORMAT_TYPE specifies the type of format checking.  FORMAT_NUM is the number
     of the argument which is the format control string (starting from 1).
     FIRST_ARG_NUM is the number of the first actual argument to check
     against the format string, or zero if no checking is not be done
     (e.g. for varargs such as vfprintf).  */
  
! static void
! record_function_format (name, assembler_name, format_type,
  			format_num, first_arg_num)
-       tree name;
-       tree assembler_name;
        enum format_type format_type;
        int format_num;
        int first_arg_num;
  {
    function_format_info *info;
  
!   /* Re-use existing structure if it's there.  */
! 
!   for (info = function_format_list; info; info = info->next)
!     {
!       if (info->name == name && info->assembler_name == assembler_name)
! 	break;
!     }
!   if (! info)
!     {
!       info = (function_format_info *) xmalloc (sizeof (function_format_info));
!       info->next = function_format_list;
!       function_format_list = info;
! 
!       info->name = name;
!       info->assembler_name = assembler_name;
!     }
! 
    info->format_type = format_type;
    info->format_num = format_num;
    info->first_arg_num = first_arg_num;
  }
  
! /* Record information for the names of function that modify the format
     argument to format functions.  FUNCTION_IDENT is the identifier node for
     the name of the function (its decl need not exist yet) and FORMAT_NUM is
     the number of the argument which is the format control string (starting
     from 1).  */
  
! static void
! record_international_format (name, assembler_name, format_num)
!       tree name;
!       tree assembler_name;
        int format_num;
  {
    international_format_info *info;
  
!   /* Re-use existing structure if it's there.  */
  
!   for (info = international_format_list; info; info = info->next)
!     {
!       if (info->name == name && info->assembler_name == assembler_name)
! 	break;
!     }
  
!   if (! info)
      {
!       info
! 	= (international_format_info *)
! 	  xmalloc (sizeof (international_format_info));
!       info->next = international_format_list;
!       international_format_list = info;
  
!       info->name = name;
!       info->assembler_name = assembler_name;
      }
! 
!   info->format_num = format_num;
  }
  
  static void
--- 1285,1420 ----
  void
  init_function_format_info ()
  {
!   add_function_format ("printf", printf_format_type, 1, 2);
!   add_function_format ("fprintf", printf_format_type, 2, 3);
!   add_function_format ("sprintf", printf_format_type, 2, 3);
!   add_function_format ("scanf", scanf_format_type, 1, 2);
!   add_function_format ("fscanf", scanf_format_type, 2, 3);
!   add_function_format ("sscanf", scanf_format_type, 2, 3);
!   add_function_format ("vprintf", printf_format_type, 1, 0);
!   add_function_format ("vfprintf", printf_format_type, 2, 0);
!   add_function_format ("vsprintf", printf_format_type, 2, 0);
!   add_function_format ("strftime", strftime_format_type, 3, 0);
!   insert_function_attribute (NULL, get_identifier ("gettext"), NULL_TREE,
!     new_international_format (1));
!   insert_function_attribute (NULL, get_identifier ("dgettext"), NULL_TREE,
!     new_international_format (2));
!   insert_function_attribute (NULL, get_identifier ("dcgettext"), NULL_TREE, 
!     new_international_format (2));
! }
! 
! /* Create information record for argument format checking.  FORMAT_TYPE 
!    specifies the type of format checking.  FORMAT_NUM is the number
     of the argument which is the format control string (starting from 1).
     FIRST_ARG_NUM is the number of the first actual argument to check
     against the format string, or zero if no checking is not be done
     (e.g. for varargs such as vfprintf).  */
  
! static function_attribute_info *
! new_function_format (format_type,
  			format_num, first_arg_num)
        enum format_type format_type;
        int format_num;
        int first_arg_num;
  {
    function_format_info *info;
  
!   info = (function_format_info *) xmalloc (sizeof (function_format_info));
!   info->next = NULL;
!   info->type = A_FORMAT;
    info->format_type = format_type;
    info->format_num = format_num;
    info->first_arg_num = first_arg_num;
+   return (function_attribute_info *) (info);
  }
  
! /* Create information record for functions that modify the format
     argument to format functions.  FUNCTION_IDENT is the identifier node for
     the name of the function (its decl need not exist yet) and FORMAT_NUM is
     the number of the argument which is the format control string (starting
     from 1).  */
  
! static function_attribute_info *
! new_international_format (format_num)
        int format_num;
  {
    international_format_info *info;
  
!   info = (international_format_info *)
! 	  xmalloc (sizeof (international_format_info));
!   info->next = NULL;
!   info->type = A_FORMAT_ARG;
!   info->format_num = format_num;
!   return (function_attribute_info *) (info);
! }
  
! /* Create information record for functions with non-null parameters.
!    ARGUMENT_NUM is the number of the argument to check.  */
  
! static function_attribute_info *
! new_nonnull_info (argument_num)
!       int argument_num;
! {
!   nonnull_info *info;
! 
!   info = (nonnull_info *)
! 	  xmalloc (sizeof (nonnull_info));
!   info->next = NULL;
!   info->type = A_NONNULL;
!   info->argument_num = argument_num;
!   return (function_attribute_info *) (info);
! }
! 
! /* Record attribute information for the names of function.  Used as:
!  * newlist = insert_function_attribute (old, name, asm, new_xxx (...) );
!  * In reality, newlist == old if old != NULL, but clients don't need to
!  * depend on that.
!  */
! 
! static function_attributes_info *
! insert_function_attribute (list, name, assembler_name, info)
! 	function_attributes_info *list;
! 	tree name;
! 	tree assembler_name;
! 	function_attribute_info *info;
! {
!   if (! list)
!   /* Re-use existing structure if it's there.  */
      {
!       for (list = function_attributes_list; list; list = list->next)
! 	{
! 	  if (list->name == name && list->assembler_name == assembler_name)
! 	    {
! 	      function_attribute_info *i, *j;
  
! 	      /* Remove existing attributes.  Maybe we should have a flag
! 	       * to mark compiler built-in attributes ?  Or always warn if 
! 	       * we override existing attributes ?
! 	       */
! 	      for (i = list->first; i; i = j)
! 	        {
! 		  j = i->next;
! 		  free (i);
! 		}
! 	      list->first = NULL;
! 	      break;
! 	    }
! 	}
      }
!   if (! list)
!     {
!       list = (function_attributes_info *) 
!              xmalloc (sizeof (function_format_info));
!       list->next = function_attributes_list;
!       function_attributes_list = list;
! 
!       list->name = name;
!       list->assembler_name = assembler_name;
!       list->first = NULL;
!     }
!   info->next = list->first;
!   list->first = info;
!   return list;
  }
  
  static void
*************** check_function_format (name, assembler_n
*** 1304,1322 ****
       tree assembler_name;
       tree params;
  {
!   function_format_info *info;
  
!   /* See if this function is a format function.  */
!   for (info = function_format_list; info; info = info->next)
      {
        if (info->assembler_name
  	  ? (info->assembler_name == assembler_name)
  	  : (info->name == name))
  	{
! 	  /* Yup; check it.  */
! 	  check_format_info (info, params);
  	  break;
  	}
      }
  }
  
--- 1435,1573 ----
       tree assembler_name;
       tree params;
  {
!   function_attributes_info *info;
!   function_attribute_info *ck;
  
!   /* See if this function has attributes.  */
!   for (info = function_attributes_list; info; info = info->next)
      {
        if (info->assembler_name
  	  ? (info->assembler_name == assembler_name)
  	  : (info->name == name))
  	{
! 	  /* Yup; check those attributes.  */
! 	  for (ck = info->first; ck; ck = ck->next)
! 	    {
! 	      switch (ck->type)
! 	        {
! 		  case A_FORMAT:
! 		    check_format_info ((function_format_info *)ck, params);
! 		    break;
! 		  case A_NONNULL:
! 		    check_nonnull_info ((nonnull_info *)ck, params);
! 		    break;
! 		}
! 	    }
! 	  break;
! 	}
!     }
! }
! 
! /* Find a function attribute corresponding to given function names, and a
!    given attribute TYPE.  */
!  
! static function_attribute_info *
! find_function_attribute(name, assembler_name, type)
! 	tree name;
! 	tree assembler_name;
! 	enum attrs type;
! {
!    function_attributes_info *info;
!    function_attribute_info *ck;
! 
!    ck = NULL;
! 
!    for (info = function_attributes_list; info; info = info->next)
!       if (info->assembler_name
! 	  ? (info->assembler_name == assembler_name)
! 	  : (info->name == name))
!         {
! 	  for (ck = info->first; ck; ck = ck->next)
! 	    {
! 	      if (ck->type == type)
! 		break;
! 	    }
  	  break;
  	}
+     return ck;
+ }
+ 
+ /* Reduce an argument pointer to handle some non-trivial common cases.  */
+ 
+ static tree
+ reduce_pointer (arg)
+ 	tree arg;
+ {
+   /* We can only check the argument if it's a string constant.  */
+   while (TREE_CODE (arg) == NOP_EXPR)
+     arg = TREE_OPERAND (arg, 0); /* strip coercion */
+ 
+   if (TREE_CODE (arg) == CALL_EXPR
+       && TREE_CODE (TREE_OPERAND (arg, 0)) == ADDR_EXPR
+       && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0))
+ 	  == FUNCTION_DECL))
+     {
+       tree function = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+ 
+       /* See if this is a call to a known internationalization function
+ 	 that modifies the format arg.  */
+       international_format_info *info;
+ 
+       info = (international_format_info *) 
+         find_function_attribute (DECL_NAME (function),
+ 	                         DECL_ASSEMBLER_NAME (function),
+ 				 A_FORMAT_ARG);
+       if (info)
+ 	  {
+ 	    tree inner_args;
+ 	    int i;
+ 
+ 	    for (inner_args = TREE_OPERAND (arg, 1), i = 1;
+ 		 inner_args != 0;
+ 		 inner_args = TREE_CHAIN (inner_args), i++)
+ 	      if (i == info->format_num)
+ 		{
+ 		  arg = TREE_VALUE (inner_args);
+ 
+ 		  while (TREE_CODE (arg) == NOP_EXPR)
+ 		    arg = TREE_OPERAND (arg, 0);
+ 		}
+ 	  }
+     }
+ }
+ 
+ /* Check the argument list for non-null pointers.
+    INFO points to the nonnull_info structure.
+    PARAMS is the list of argument values.  */
+ 
+ static void
+ check_nonnull_info (info, params)
+      nonnull_info *info;
+      tree params;
+ {
+   tree arg;
+   int arg_num;
+ 
+   /* Skip to checked argument.  If the argument isn't available, there's
+      no work for us to do; prototype checking will catch the problem.  */
+   for (arg_num = 1; ; ++arg_num)
+     {
+       if (params == 0)
+ 	return;
+       if (arg_num == info->argument_num)
+ 	break;
+       params = TREE_CHAIN (params);
+     }
+   arg = TREE_VALUE (params);
+   if (arg == 0)
+     return;
+ 
+   arg = reduce_pointer (arg);
+ 
+   if (integer_zerop (arg))
+     {
+       warning ("null argument string");
+       return;
      }
  }
  
*************** check_format_info (info, params)
*** 1360,1406 ****
    if (format_tree == 0)
      return;
  
!   /* We can only check the format if it's a string constant.  */
!   while (TREE_CODE (format_tree) == NOP_EXPR)
!     format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
! 
!   if (TREE_CODE (format_tree) == CALL_EXPR
!       && TREE_CODE (TREE_OPERAND (format_tree, 0)) == ADDR_EXPR
!       && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0))
! 	  == FUNCTION_DECL))
!     {
!       tree function = TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0);
! 
!       /* See if this is a call to a known internationalization function
! 	 that modifies the format arg.  */
!       international_format_info *info;
  
-       for (info = international_format_list; info; info = info->next)
- 	if (info->assembler_name
- 	    ? (info->assembler_name == DECL_ASSEMBLER_NAME (function))
- 	    : (info->name == DECL_NAME (function)))
- 	  {
- 	    tree inner_args;
- 	    int i;
- 
- 	    for (inner_args = TREE_OPERAND (format_tree, 1), i = 1;
- 		 inner_args != 0;
- 		 inner_args = TREE_CHAIN (inner_args), i++)
- 	      if (i == info->format_num)
- 		{
- 		  format_tree = TREE_VALUE (inner_args);
- 
- 		  while (TREE_CODE (format_tree) == NOP_EXPR)
- 		    format_tree = TREE_OPERAND (format_tree, 0);
- 		}
- 	  }
-     }
- 
-   if (integer_zerop (format_tree))
-     {
-       warning ("null format string");
-       return;
-     }
    if (TREE_CODE (format_tree) != ADDR_EXPR)
      return;
    format_tree = TREE_OPERAND (format_tree, 0);
--- 1611,1618 ----
    if (format_tree == 0)
      return;
  
!   format_tree = reduce_pointer (format_tree);
  
    if (TREE_CODE (format_tree) != ADDR_EXPR)
      return;
    format_tree = TREE_OPERAND (format_tree, 0);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]