public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] restore CFString handling in attribute format (PR 88638)
@ 2019-01-04 22:03 Martin Sebor
  2019-01-04 22:30 ` Mike Stump
  0 siblings, 1 reply; 10+ messages in thread
From: Martin Sebor @ 2019-01-04 22:03 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 929 bytes --]

The improved handling of attribute positional arguments added
in r266195 introduced a regression on Darwin where attribute
format with the CFString archetype accepts CFString* parameter
types in positions where only char* would otherwise be allowed.
This is specific to Darwin so it didn't show up in tests.
The attached patch restores the feature.

r266195 also replaced an error issued for an invalid attribute
format parameter with just a warning.  On reflection I think
that was a mistake and an error is more appropriate.  The patch
also restores the error.

Finally, I've adjusted the Darwin Format Checks documentation
to better match the effects of the archetype (i.e., no checking
at call sites but no undefined behavior).

Besides testing natively on x86_64-linux I have also manually
run the affected tests with an x86_64-apple-darwin18 cross to
verify the changes (they are UNSUPPORTED under the test suite).

Martin

[-- Attachment #2: gcc-88638.diff --]
[-- Type: text/x-patch, Size: 16790 bytes --]

PR target/88638 - FAIL: fsf-nsstring-format-1.s on darwin

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.

Index: gcc/c-family/c-attribs.c
===================================================================
--- gcc/c-family/c-attribs.c	(revision 267580)
+++ gcc/c-family/c-attribs.c	(working copy)
@@ -631,21 +631,32 @@ positional_argument (const_tree fntype, const_tree
 	}
 
       /* Where the expected code is STRING_CST accept any pointer
-	 to a narrow character type, qualified or otherwise.  */
+	 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))
-	{
-	  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
 	type_match = TREE_CODE (argtype) == code;
 
       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: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 267580)
+++ gcc/c-family/c-common.h	(working copy)
@@ -1335,6 +1335,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: gcc/c-family/c-format.c
===================================================================
--- gcc/c-family/c-format.c	(revision 267580)
+++ gcc/c-family/c-format.c	(working copy)
@@ -122,8 +122,8 @@ format_warning_at_char (location_t fmt_string_loc,
    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 atna
 	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 H
     }
 
   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 H
   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: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 267580)
+++ gcc/doc/extend.texi	(working copy)
@@ -22368,10 +22368,12 @@ bit-fields.  See the Solaris man page for @code{cm
 @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 archetypes, 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: gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c
===================================================================
--- gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c	(revision 267580)
+++ gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c	(working copy)
@@ -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__((form
 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: gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc/testsuite/gcc.dg/format/attr-3.c	(revision 267580)
+++ gcc/testsuite/gcc.dg/format/attr-3.c	(working copy)
@@ -56,16 +56,16 @@ extern void fg3 () __attribute__((format(gnu_attr_
 
 /* 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" } */
Index: gcc/testsuite/gcc.dg/format/attr-8.c
===================================================================
--- gcc/testsuite/gcc.dg/format/attr-8.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/format/attr-8.c	(working copy)
@@ -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: gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm	(revision 267580)
+++ gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm	(working copy)
@@ -28,7 +28,7 @@ int s1b (NSString *fmt, ...) __attribute__((format
 
 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
 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: gcc/testsuite/objc.dg/fsf-nsstring-format-1.m
===================================================================
--- gcc/testsuite/objc.dg/fsf-nsstring-format-1.m	(revision 267580)
+++ gcc/testsuite/objc.dg/fsf-nsstring-format-1.m	(working copy)
@@ -21,7 +21,7 @@ int s1b (NSString *fmt, ...) __attribute__((format
 
 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
 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 */

^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [PATCH] restore CFString handling in attribute format (PR 88638)
@ 2019-01-05 21:41 Dominique d'Humières
  2019-01-14 18:55 ` Martin Sebor
  0 siblings, 1 reply; 10+ messages in thread
From: Dominique d'Humières @ 2019-01-05 21:41 UTC (permalink / raw)
  To: msebor; +Cc: Iain Sandoe, gcc-patches

Hi Martin,

The patch on top of r267591 fixes pr88638 without regression.

Note

 FAIL: c-c++-common/attributes-4.c  -std=gnu++14 (test for excess errors)
 FAIL: c-c++-common/attributes-4.c  -std=gnu++17 (test for excess errors)
 FAIL: c-c++-common/attributes-4.c  -std=gnu++98 (test for excess errors)

Thanks for the fix.

Dominique

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

end of thread, other threads:[~2019-01-14 18:55 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-04 22:03 [PATCH] restore CFString handling in attribute format (PR 88638) Martin Sebor
2019-01-04 22:30 ` Mike Stump
2019-01-05 10:31   ` Iain Sandoe
2019-01-05 17:39     ` Martin Sebor
2019-01-05 17:54       ` Iain Sandoe
2019-01-06 23:34         ` Martin Sebor
2019-01-07  9:26           ` Iain Sandoe
2019-01-11 22:05           ` Jeff Law
2019-01-05 21:41 Dominique d'Humières
2019-01-14 18:55 ` Martin Sebor

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