PR target/88638 - FAIL: fsf-nsstring-format-1.s on darwin
authorMartin Sebor <msebor@redhat.com>
Mon, 14 Jan 2019 18:44:00 +0000 (18:44 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Mon, 14 Jan 2019 18:44:00 +0000 (11:44 -0700)
gcc/c-family/ChangeLog:

PR target/88638
* c-attribs.c (positional_argument): Call valid_format_string_type_p
and issue errors if it fails.
* c-common.h (valid_format_string_type_p): Declare.
* c-format.c (valid_stringptr_type_p): Rename...
(valid_format_string_type_p): ...to this and make extern.
(handle_format_arg_attribute): Adjust to new name.
(check_format_string): Same.

gcc/testsuite/ChangeLog:

PR target/88638
* gcc.dg/format/attr-8.c: New test.
* gcc.dg/darwin-cfstring-format-1.c: Adjust diagnostics.
* gcc.dg/format/attr-3.c: Same.
* obj-c++.dg/fsf-nsstring-format-1.mm: Same.
* objc.dg/fsf-nsstring-format-1.m: Same.

gcc/ChangeLog:

PR target/88638
* doc/extend.texi (Darwin Format Checks): Clarify.

From-SVN: r267922

12 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/c-family/c-common.h
gcc/c-family/c-format.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c
gcc/testsuite/gcc.dg/format/attr-3.c
gcc/testsuite/gcc.dg/format/attr-8.c [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm
gcc/testsuite/objc.dg/fsf-nsstring-format-1.m

index bf6e319ca97cfd027446add907dc6789d9dc3439..869ab248d9fa1cf48a9aa51f746abc8329457603 100644 (file)
@@ -1,3 +1,8 @@
+2019-01-14  Martin Sebor  <msebor@redhat.com>
+
+       PR target/88638
+       * doc/extend.texi (Darwin Format Checks): Clarify.
+
 2019-01-14  Richard Biener  <rguenther@suse.de>
 
        * genmatch.c (dt_simplify::gen_1): Change dumping dependent on
index d1b4d25483d019767cf6337b5fa5e38ae0153c56..fe4c81f9da49322124b17eee9423a78a2f9ee18c 100644 (file)
@@ -1,3 +1,14 @@
+2019-01-14  Martin Sebor  <msebor@redhat.com>
+
+       PR target/88638
+       * c-attribs.c (positional_argument): Call valid_format_string_type_p
+       and issue errors if it fails.
+       * c-common.h (valid_format_string_type_p): Declare.
+       * c-format.c (valid_stringptr_type_p): Rename...
+       (valid_format_string_type_p): ...to this and make extern.
+       (handle_format_arg_attribute): Adjust to new name.
+       (check_format_string): Same.
+
 2019-01-13  H.J. Lu  <hongjiu.lu@intel.com>
 
        * c-warn.c (warn_for_address_or_pointer_of_packed_member):
index c893baa48e3dc470fdf2409b2106f5f5ff079467..20584593c6a9085e4deec05a61a05b9cbe5fe922 100644 (file)
@@ -631,17 +631,13 @@ positional_argument (const_tree fntype, const_tree atname, tree pos,
          return NULL_TREE;
        }
 
+      /* Where the expected code is STRING_CST accept any pointer
+        expected by attribute format (this includes possibly qualified
+        char pointers and, for targets like Darwin, also pointers to
+        struct CFString).  */
       bool type_match;
-      if (code == STRING_CST && POINTER_TYPE_P (argtype))
-       {
-         /* Where the expected code is STRING_CST accept any pointer
-            to a narrow character type, qualified or otherwise.  */
-         tree type = TREE_TYPE (argtype);
-         type = TYPE_MAIN_VARIANT (type);
-         type_match = (type == char_type_node
-                       || type == signed_char_type_node
-                       || type == unsigned_char_type_node);
-       }
+      if (code == STRING_CST)
+       type_match = valid_format_string_type_p (argtype);
       else if (code == INTEGER_TYPE)
        /* For integers, accept enums, wide characters and other types
           that match INTEGRAL_TYPE_P except for bool.  */
@@ -652,6 +648,21 @@ positional_argument (const_tree fntype, const_tree atname, tree pos,
 
       if (!type_match)
        {
+         if (code == STRING_CST)
+           {
+             /* Reject invalid format strings with an error.  */
+             if (argno < 1)
+               error ("%qE attribute argument value %qE refers to "
+                      "parameter type %qT",
+                      atname, pos, argtype);
+             else
+               error ("%qE attribute argument %i value %qE refers to "
+                      "parameter type %qT",
+                      atname, argno, pos, argtype);
+
+             return NULL_TREE;
+           }
+
          if (argno < 1)
            warning (OPT_Wattributes,
                     "%qE attribute argument value %qE refers to "
index db16ae94b64c97fdceef1087f03c4e96b749d473..9f790bc6a1485e45f3b5f2a9a36a6991fa75f75f 100644 (file)
@@ -1336,6 +1336,9 @@ extern tree tm_mask_to_attr (int);
 extern tree find_tm_attribute (tree);
 extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[];
 
+/* In c-format.c.  */
+extern bool valid_format_string_type_p (tree);
+
 /* A bitmap of flags to positional_argument.  */
 enum posargflags {
   /* Consider positional attribute argument value zero valid.  */
index 327fa29937d2a7e0a58438e5468b64e91f10c83f..9b48ee3e3f4fba4f39fe9ab71d547b4c743d6f68 100644 (file)
@@ -122,8 +122,8 @@ format_warning_at_char (location_t fmt_string_loc, tree format_string_cst,
    The function returns true if strref points to any string type valid for the 
    language dialect and target.  */
 
-static bool
-valid_stringptr_type_p (tree strref)
+bool
+valid_format_string_type_p (tree strref)
 {
   return (strref != NULL
          && TREE_CODE (strref) == POINTER_TYPE
@@ -160,7 +160,7 @@ handle_format_arg_attribute (tree *node, tree atname,
        return NULL_TREE;
     }
 
-  if (!valid_stringptr_type_p (TREE_TYPE (type)))
+  if (!valid_format_string_type_p (TREE_TYPE (type)))
     {
       if (!(flags & (int) ATTR_FLAG_BUILT_IN))
        error ("function does not return string type");
@@ -194,7 +194,7 @@ check_format_string (const_tree fntype, unsigned HOST_WIDE_INT format_num,
     }
 
   if (!ref
-      || !valid_stringptr_type_p (ref))
+      || !valid_format_string_type_p (ref))
     {
       if (!(flags & (int) ATTR_FLAG_BUILT_IN))
        error ("format string argument is not a string type");
@@ -267,13 +267,21 @@ check_format_string (const_tree fntype, unsigned HOST_WIDE_INT format_num,
   gcc_unreachable ();
 }
 
-/* Verify EXPR is a constant, and store its value.
-   If validated_p is true there should be no errors.
+/* Under the control of FLAGS, verify EXPR is a valid constant that
+   refers to a positional argument ARGNO having a string type (char*
+   or, for targets like Darwin, a pointer to struct CFString) to
+   a function type FNTYPE declared with attribute ATNAME.
+   If valid, store the constant's integer value in *VALUE and return
+   the value.
+   If VALIDATED_P is true assert the validation is successful.
    Returns the converted constant value on success, null otherwise.  */
+
 static tree
 get_constant (const_tree fntype, const_tree atname, tree expr, int argno,
              unsigned HOST_WIDE_INT *value, int flags, bool validated_p)
 {
+  /* Require the referenced argument to have a string type.  For targets
+     like Darwin, also accept pointers to struct CFString.  */
   if (tree val = positional_argument (fntype, atname, expr, STRING_CST,
                                      argno, flags))
     {
index f0130571d580434ab99c28e37980ef88eefe8958..c81092dfe0c25c2e0580f29bb1ca790e961f20e2 100644 (file)
@@ -22397,10 +22397,14 @@ bit-fields.  See the Solaris man page for @code{cmn_err} for more information.
 @node Darwin Format Checks
 @subsection Darwin Format Checks
 
-Darwin targets support the @code{CFString} (or @code{__CFString__}) in the format
-attribute context.  Declarations made with such attribution are parsed for correct syntax
-and format argument types.  However, parsing of the format string itself is currently undefined
-and is not carried out by this version of the compiler.
+In addition to the full set of format archetypes (attribute format style
+arguments such as @code{printf}, @code{scanf}, @code{strftime}, and
+@code{strfmon}), Darwin targets also support the @code{CFString} (or
+@code{__CFString__}) archetype in the @code{format} attribute.
+Declarations with this archetype are parsed for correct syntax
+and argument types.  However, parsing of the format string itself and
+validating arguments against it in calls to such functions is currently
+not performed.
 
 Additionally, @code{CFStringRefs} (defined by the @code{CoreFoundation} headers) may
 also be used as format arguments.  Note that the relevant headers are only likely to be
index 093c362f13dc390e9fed1385275c4b4e980fd793..8c6f9e419baf7f69b1f0887d45068f520a9a87e5 100644 (file)
@@ -1,3 +1,12 @@
+2019-01-14  Martin Sebor  <msebor@redhat.com>
+
+       PR target/88638
+       * gcc.dg/format/attr-8.c: New test.
+       * gcc.dg/darwin-cfstring-format-1.c: Adjust diagnostics.
+       * gcc.dg/format/attr-3.c: Same.
+       * obj-c++.dg/fsf-nsstring-format-1.mm: Same.
+       * objc.dg/fsf-nsstring-format-1.m: Same.
+
 2019-01-14  Martin Liska  <mliska@suse.cz>
 
        PR gcov-profile/88263
index c1b44a337dd13d63cd431eb767acb13fd47331b5..a1513ee233af55a30ebc2f833b56bf780a67541a 100644 (file)
@@ -15,7 +15,7 @@ typedef const struct __CFString * CFStringRef;
 int s1 (CFStringRef fmt, ...) __attribute__((format(CFString, 1, 2))) ; /* OK */
 int s2 (int a, CFStringRef fmt, ... ) __attribute__((format(__CFString__, 2, 3))) ; /* OK */
 
-int s2a (int a, CFStringRef fmt, ... ) __attribute__((format(CFString, 2, 2))) ; /* { dg-error "format string argument follows the args to be formatted" } */
+int s2a (int a, CFStringRef fmt, ... ) __attribute__((format(CFString, 2, 2))) ; /* { dg-error ".format. attribute argument 3 value .2. does not refer to a variable argument list" } */
 
 int s3 (const char *fmt, ... ) __attribute__((format(__CFString__, 1, 2))) ; /* { dg-error "format argument should be a .CFString. reference but a string was found" } */
 int s4 (CFStringRef fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-error "found a .CFStringRef.* but the format argument should be a string" } */
@@ -23,7 +23,7 @@ int s4 (CFStringRef fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-e
 char *s5 (char dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
 CFStringRef s6 (CFStringRef dum, CFStringRef fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
 
-char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "format string argument is not a string type" } */
+char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error ".format_arg. attribute argument value .2. refers to parameter type .void \\\*." } */
 int s8 (CFStringRef dum, CFStringRef fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "function does not return string type" } */
 
 void foo (void)
index 31cc05ec5270a609f36e239459d216806e3bcedf..1b275c5aba81e26bf8ee538990ec77a01c324b7a 100644 (file)
@@ -56,16 +56,16 @@ extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-warning ".format. attribute argument 2 value .1. refers to parameter type .int." "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error ".format. attribute argument 2 value .1. refers to parameter type .int." "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error ".format. attribute argument 2 value .1. refers to parameter type .signed char \\\*." "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error ".format. attribute argument 2 value .1. refers to parameter type .unsigned char \\\*." "unsigned char string" } */
 extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
 extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error ".format. attribute argument 3 value .2. does not refer to a variable argument list" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
-extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-warning ".format_arg. attribute argument value .1. refers to parameter type .int." } */
-extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
-extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error ".format_arg. attribute argument value .1. refers to parameter type .int." } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error ".format_arg. attribute argument value .1. refers to parameter type .signed char \\\*." "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error ".format_arg. attribute argument value .1. refers to parameter type .unsigned char \\\*." "format_arg unsigned char string" } */
 extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
 extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
 extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
diff --git a/gcc/testsuite/gcc.dg/format/attr-8.c b/gcc/testsuite/gcc.dg/format/attr-8.c
new file mode 100644 (file)
index 0000000..7fba35a
--- /dev/null
@@ -0,0 +1,34 @@
+/* Test to verify that parameters of qualified narrow char pointer type
+   are accepted for attribute format printf, but others are rejected.
+   { dg-do compile }
+   { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+#define FORMAT(archetype, arg1, arg2)   \
+  __attribute__  ((format (archetype, arg1, arg2)))
+
+FORMAT (gnu_attr_printf, 1, 2)
+  void fpc_1_2 (char *, ...);
+
+FORMAT (gnu_attr_printf, 1, 2)
+  void fpcc_1_2 (const char *, ...);
+
+FORMAT (gnu_attr_printf, 1, 2)
+  void frpc_1_2 (char * restrict, ...);
+
+FORMAT (gnu_attr_printf, 1, 2)
+  void fpvc_1_2 (volatile char *, ...);
+
+FORMAT (gnu_attr_printf, 1, 2)
+  void fpcvc_1_2 (const volatile char *, ...);
+
+FORMAT (gnu_attr_printf, 1, 2)
+  void fpv_1_2 (void *, ...);       /* { dg-error ".format. attribute argument 2 value .1. refers to parameter type .void \\\*." } */
+
+FORMAT (gnu_attr_printf, 1, 2)
+  void fppc_1_2 (char **, ...);     /* { dg-error ".format. attribute argument 2 value .1. refers to parameter type .char \\\*\\\*." } */
+
+FORMAT (gnu_attr_printf, 1, 2)
+  void fpwc_1_2 (wchar_t *, ...);   /* { dg-error ".format. attribute argument 2 value .1. refers to parameter type .wchar_t \\\*." } */
index a5eaf3431f56bc532d7a6dd8bb8230995249a1bc..18f5960a489b643b656f7f8bf042be3a34685142 100644 (file)
@@ -28,7 +28,7 @@ int s1b (NSString *fmt, ...) __attribute__((format(CFString, 1, 2))) ; /* { dg-e
 
 int s2 (int a, NSString *fmt, ... ) __attribute__((format(__NSString__, 2, 3))) ; /* OK */
 
-int s2a (int a, NSString *fmt, ... ) __attribute__((format(NSString, 2, 2))) ; /* { dg-error "format string argument follows the args to be formatted" } */
+int s2a (int a, NSString *fmt, ... ) __attribute__((format(NSString, 2, 2))) ; /* { dg-error ".format. attribute argument 3 value .2. does not refer to a variable argument list" } */
 
 int s3 (const char *fmt, ... ) __attribute__((format(__NSString__, 1, 2))) ; /* { dg-error "format argument should be a .NSString. reference but a string was found" } */
 int s4 (NSString *fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-error "found a .NSString. reference but the format argument should be a string" } */
@@ -36,7 +36,7 @@ int s4 (NSString *fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-err
 char *s5 (char dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
 NSString *s6 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
 
-char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "format string argument is not a string type" } */
+char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error ".format_arg. attribute argument value .2. refers to parameter type .void\\\*." } */
 int s8 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "function does not return string type" } */
 
 char *s9 (int dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
index ecbad439acc8b01c50036eb54def0dfd05269924..e29358cafd41f9951d29ccf7ce8a6adce9443674 100644 (file)
@@ -21,7 +21,7 @@ int s1b (NSString *fmt, ...) __attribute__((format(CFString, 1, 2))) ; /* { dg-e
 
 int s2 (int a, NSString *fmt, ... ) __attribute__((format(__NSString__, 2, 3))) ; /* OK */
 
-int s2a (int a, NSString *fmt, ... ) __attribute__((format(NSString, 2, 2))) ; /* { dg-error "format string argument follows the args to be formatted" } */
+int s2a (int a, NSString *fmt, ... ) __attribute__((format(NSString, 2, 2))) ; /* { dg-error ".format. attribute argument 3 value .2. does not refer to a variable argument list" } */
 
 int s3 (const char *fmt, ... ) __attribute__((format(__NSString__, 1, 2))) ; /* { dg-error "format argument should be a .NSString. reference but a string was found" } */
 int s4 (NSString *fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-error "found a .NSString. reference but the format argument should be a string" } */
@@ -29,7 +29,7 @@ int s4 (NSString *fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-err
 char *s5 (char dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
 NSString *s6 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
 
-char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "format string argument is not a string type" } */
+char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error ".format_arg. attribute argument value .2. refers to parameter type .void \\\*." } */
 int s8 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "function does not return string type" } */
 
 char *s9 (int dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */