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
This commit is contained in:
Martin Sebor 2019-01-14 18:44:00 +00:00 committed by Martin Sebor
parent 15f4e33db7
commit 23db6ced33
12 changed files with 117 additions and 32 deletions

View 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

View 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):

View 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 "

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

View 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))
{

View 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

View 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

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

View 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" } */

View file

@ -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 \\\*." } */

View 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 */

View 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 */