From 23db6ced33c245c38c147c31011bbafa392e4328 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Mon, 14 Jan 2019 18:44:00 +0000 Subject: [PATCH] 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. From-SVN: r267922 --- gcc/ChangeLog | 5 +++ gcc/c-family/ChangeLog | 11 ++++++ gcc/c-family/c-attribs.c | 31 +++++++++++------ gcc/c-family/c-common.h | 3 ++ gcc/c-family/c-format.c | 20 +++++++---- gcc/doc/extend.texi | 12 ++++--- gcc/testsuite/ChangeLog | 9 +++++ .../gcc.dg/darwin-cfstring-format-1.c | 4 +-- gcc/testsuite/gcc.dg/format/attr-3.c | 12 +++---- gcc/testsuite/gcc.dg/format/attr-8.c | 34 +++++++++++++++++++ .../obj-c++.dg/fsf-nsstring-format-1.mm | 4 +-- gcc/testsuite/objc.dg/fsf-nsstring-format-1.m | 4 +-- 12 files changed, 117 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/format/attr-8.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bf6e319ca97..869ab248d9f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-01-14 Martin Sebor + + PR target/88638 + * doc/extend.texi (Darwin Format Checks): Clarify. + 2019-01-14 Richard Biener * genmatch.c (dt_simplify::gen_1): Change dumping dependent on diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index d1b4d25483d..fe4c81f9da4 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,14 @@ +2019-01-14 Martin Sebor + + 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 * c-warn.c (warn_for_address_or_pointer_of_packed_member): diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index c893baa48e3..20584593c6a 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -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 " diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index db16ae94b64..9f790bc6a14 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -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. */ diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c index 327fa29937d..9b48ee3e3f4 100644 --- a/gcc/c-family/c-format.c +++ b/gcc/c-family/c-format.c @@ -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)) { diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index f0130571d58..c81092dfe0c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 093c362f13d..8c6f9e419ba 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2019-01-14 Martin Sebor + + 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 PR gcov-profile/88263 diff --git a/gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c b/gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c index c1b44a337dd..a1513ee233a 100644 --- a/gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c +++ b/gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c @@ -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) diff --git a/gcc/testsuite/gcc.dg/format/attr-3.c b/gcc/testsuite/gcc.dg/format/attr-3.c index 31cc05ec527..1b275c5aba8 100644 --- a/gcc/testsuite/gcc.dg/format/attr-3.c +++ b/gcc/testsuite/gcc.dg/format/attr-3.c @@ -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 index 00000000000..7fba35a56c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/format/attr-8.c @@ -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 \\\*." } */ diff --git a/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm b/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm index a5eaf3431f5..18f5960a489 100644 --- a/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm +++ b/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm @@ -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 */ diff --git a/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m b/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m index ecbad439acc..e29358cafd4 100644 --- a/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m +++ b/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m @@ -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 */ -- 2.30.2