00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023 #include "system.h"
00024 #include "coretypes.h"
00025 #include "tm.h"
00026 #include "tree.h"
00027 #include "flags.h"
00028 #include "toplev.h"
00029 #include "c-common.h"
00030 #include "intl.h"
00031 #include "diagnostic.h"
00032 #include "langhooks.h"
00033 #include "c-format.h"
00034
00035
00036
00037 void
00038 set_Wformat (int setting)
00039 {
00040 warn_format = setting;
00041 warn_format_extra_args = setting;
00042 warn_format_zero_length = setting;
00043 if (setting != 1)
00044 {
00045 warn_format_nonliteral = setting;
00046 warn_format_security = setting;
00047 warn_format_y2k = setting;
00048 }
00049
00050 if (setting)
00051 warn_nonnull = setting;
00052 }
00053
00054
00055
00056
00057
00058
00059
00060 enum format_type { printf_format_type, asm_fprintf_format_type,
00061 gcc_diag_format_type, gcc_cdiag_format_type,
00062 gcc_cxxdiag_format_type,
00063 scanf_format_type, strftime_format_type,
00064 strfmon_format_type, format_type_error = -1};
00065
00066 typedef struct function_format_info
00067 {
00068 int format_type;
00069 unsigned HOST_WIDE_INT format_num;
00070 unsigned HOST_WIDE_INT first_arg_num;
00071 } function_format_info;
00072
00073 static bool decode_format_attr (tree, function_format_info *, int);
00074 static int decode_format_type (const char *);
00075
00076 static bool check_format_string (tree argument,
00077 unsigned HOST_WIDE_INT format_num,
00078 int flags, bool *no_add_attrs);
00079 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
00080 int validated_p);
00081
00082
00083
00084
00085 tree
00086 handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
00087 tree args, int flags, bool *no_add_attrs)
00088 {
00089 tree type = *node;
00090 tree format_num_expr = TREE_VALUE (args);
00091 unsigned HOST_WIDE_INT format_num = 0;
00092 tree argument;
00093
00094 if (!get_constant (format_num_expr, &format_num, 0))
00095 {
00096 error ("format string has invalid operand number");
00097 *no_add_attrs = true;
00098 return NULL_TREE;
00099 }
00100
00101 argument = TYPE_ARG_TYPES (type);
00102 if (argument)
00103 {
00104 if (!check_format_string (argument, format_num, flags, no_add_attrs))
00105 return NULL_TREE;
00106 }
00107
00108 if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
00109 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
00110 != char_type_node))
00111 {
00112 if (!(flags & (int) ATTR_FLAG_BUILT_IN))
00113 error ("function does not return string type");
00114 *no_add_attrs = true;
00115 return NULL_TREE;
00116 }
00117
00118 return NULL_TREE;
00119 }
00120
00121
00122
00123 static bool
00124 check_format_string (tree argument, unsigned HOST_WIDE_INT format_num,
00125 int flags, bool *no_add_attrs)
00126 {
00127 unsigned HOST_WIDE_INT i;
00128
00129 for (i = 1; i != format_num; i++)
00130 {
00131 if (argument == 0)
00132 break;
00133 argument = TREE_CHAIN (argument);
00134 }
00135
00136 if (!argument
00137 || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
00138 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
00139 != char_type_node))
00140 {
00141 if (!(flags & (int) ATTR_FLAG_BUILT_IN))
00142 error ("format string argument not a string type");
00143 *no_add_attrs = true;
00144 return false;
00145 }
00146
00147 return true;
00148 }
00149
00150
00151
00152
00153 static bool
00154 get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p)
00155 {
00156 while (TREE_CODE (expr) == NOP_EXPR
00157 || TREE_CODE (expr) == CONVERT_EXPR
00158 || TREE_CODE (expr) == NON_LVALUE_EXPR)
00159 expr = TREE_OPERAND (expr, 0);
00160
00161 if (TREE_CODE (expr) != INTEGER_CST || TREE_INT_CST_HIGH (expr) != 0)
00162 {
00163 gcc_assert (!validated_p);
00164 return false;
00165 }
00166
00167 *value = TREE_INT_CST_LOW (expr);
00168
00169 return true;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179 static bool
00180 decode_format_attr (tree args, function_format_info *info, int validated_p)
00181 {
00182 tree format_type_id = TREE_VALUE (args);
00183 tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
00184 tree first_arg_num_expr
00185 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
00186
00187 if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
00188 {
00189 gcc_assert (!validated_p);
00190 error ("unrecognized format specifier");
00191 return false;
00192 }
00193 else
00194 {
00195 const char *p = IDENTIFIER_POINTER (format_type_id);
00196
00197 info->format_type = decode_format_type (p);
00198
00199 if (info->format_type == format_type_error)
00200 {
00201 gcc_assert (!validated_p);
00202 warning ("%qs is an unrecognized format function type", p);
00203 return false;
00204 }
00205 }
00206
00207 if (!get_constant (format_num_expr, &info->format_num, validated_p))
00208 {
00209 error ("format string has invalid operand number");
00210 return false;
00211 }
00212
00213 if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p))
00214 {
00215 error ("%<...%> has invalid operand number");
00216 return false;
00217 }
00218
00219 if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
00220 {
00221 gcc_assert (!validated_p);
00222 error ("format string argument follows the args to be formatted");
00223 return false;
00224 }
00225
00226 return true;
00227 }
00228
00229
00230
00231
00232
00233 #define CPLUSPLUS_STD_VER STD_C94
00234
00235 #define C_STD_VER ((int) (c_dialect_cxx () \
00236 ? CPLUSPLUS_STD_VER \
00237 : (flag_isoc99 \
00238 ? STD_C99 \
00239 : (flag_isoc94 ? STD_C94 : STD_C89))))
00240
00241
00242
00243 #define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \
00244 ? "ISO C++" \
00245 : ((FEATURE_VER) == STD_EXT \
00246 ? "ISO C" \
00247 : "ISO C90"))
00248
00249
00250 #define ADJ_STD(VER) ((int) ((VER) == STD_C9L \
00251 ? (warn_long_long ? STD_C99 : STD_C89) \
00252 : (VER)))
00253
00254
00255
00256 typedef struct format_wanted_type
00257 {
00258
00259 tree wanted_type;
00260
00261 const char *wanted_type_name;
00262
00263 int pointer_count;
00264
00265
00266 int char_lenient_flag;
00267
00268
00269 int writing_in_flag;
00270
00271
00272 int reading_from_flag;
00273
00274
00275
00276
00277 const char *name;
00278
00279 tree param;
00280
00281 int arg_num;
00282
00283 struct format_wanted_type *next;
00284 } format_wanted_type;
00285
00286
00287 static const format_length_info printf_length_specs[] =
00288 {
00289 { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
00290 { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
00291 { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
00292 { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
00293 { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
00294 { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 },
00295 { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
00296 { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 },
00297 { NULL, 0, 0, NULL, 0, 0 }
00298 };
00299
00300
00301 static const format_length_info asm_fprintf_length_specs[] =
00302 {
00303 { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 },
00304 { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 },
00305 { NULL, 0, 0, NULL, 0, 0 }
00306 };
00307
00308
00309 static const format_length_info gcc_diag_length_specs[] =
00310 {
00311 { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 },
00312 { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 },
00313 { NULL, 0, 0, NULL, 0, 0 }
00314 };
00315
00316
00317 #define gcc_cdiag_length_specs gcc_diag_length_specs
00318 #define gcc_cxxdiag_length_specs gcc_diag_length_specs
00319
00320
00321 static const format_length_info scanf_length_specs[] =
00322 {
00323 { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
00324 { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
00325 { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
00326 { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
00327 { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
00328 { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
00329 { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 },
00330 { NULL, 0, 0, NULL, 0, 0 }
00331 };
00332
00333
00334
00335
00336 static const format_length_info strfmon_length_specs[] =
00337 {
00338
00339 { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
00340 { NULL, 0, 0, NULL, 0, 0 }
00341 };
00342
00343 static const format_flag_spec printf_flag_specs[] =
00344 {
00345 { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
00346 { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
00347 { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
00348 { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
00349 { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
00350 { '\'', 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT },
00351 { 'I', 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT },
00352 { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
00353 { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
00354 { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
00355 { 0, 0, 0, NULL, NULL, 0 }
00356 };
00357
00358
00359 static const format_flag_pair printf_flag_pairs[] =
00360 {
00361 { ' ', '+', 1, 0 },
00362 { '0', '-', 1, 0 },
00363 { '0', 'p', 1, 'i' },
00364 { 0, 0, 0, 0 }
00365 };
00366
00367 static const format_flag_spec asm_fprintf_flag_specs[] =
00368 {
00369 { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
00370 { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
00371 { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
00372 { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
00373 { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
00374 { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
00375 { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
00376 { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
00377 { 0, 0, 0, NULL, NULL, 0 }
00378 };
00379
00380 static const format_flag_pair asm_fprintf_flag_pairs[] =
00381 {
00382 { ' ', '+', 1, 0 },
00383 { '0', '-', 1, 0 },
00384 { '0', 'p', 1, 'i' },
00385 { 0, 0, 0, 0 }
00386 };
00387
00388 static const format_flag_pair gcc_diag_flag_pairs[] =
00389 {
00390 { 0, 0, 0, 0 }
00391 };
00392
00393 #define gcc_cdiag_flag_pairs gcc_diag_flag_pairs
00394 #define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs
00395
00396 static const format_flag_spec gcc_diag_flag_specs[] =
00397 {
00398 { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 },
00399 { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
00400 { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
00401 { 0, 0, 0, NULL, NULL, 0 }
00402 };
00403
00404 #define gcc_cdiag_flag_specs gcc_diag_flag_specs
00405
00406 static const format_flag_spec gcc_cxxdiag_flag_specs[] =
00407 {
00408 { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
00409 { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
00410 { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 },
00411 { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
00412 { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
00413 { 0, 0, 0, NULL, NULL, 0 }
00414 };
00415
00416 static const format_flag_spec scanf_flag_specs[] =
00417 {
00418 { '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
00419 { 'a', 0, 0, N_("'a' flag"), N_("the 'a' scanf flag"), STD_EXT },
00420 { 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 },
00421 { 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 },
00422 { '\'', 0, 0, N_("''' flag"), N_("the ''' scanf flag"), STD_EXT },
00423 { 'I', 0, 0, N_("'I' flag"), N_("the 'I' scanf flag"), STD_EXT },
00424 { 0, 0, 0, NULL, NULL, 0 }
00425 };
00426
00427
00428 static const format_flag_pair scanf_flag_pairs[] =
00429 {
00430 { '*', 'L', 0, 0 },
00431 { 0, 0, 0, 0 }
00432 };
00433
00434
00435 static const format_flag_spec strftime_flag_specs[] =
00436 {
00437 { '_', 0, 0, N_("'_' flag"), N_("the '_' strftime flag"), STD_EXT },
00438 { '-', 0, 0, N_("'-' flag"), N_("the '-' strftime flag"), STD_EXT },
00439 { '0', 0, 0, N_("'0' flag"), N_("the '0' strftime flag"), STD_EXT },
00440 { '^', 0, 0, N_("'^' flag"), N_("the '^' strftime flag"), STD_EXT },
00441 { '#', 0, 0, N_("'#' flag"), N_("the '#' strftime flag"), STD_EXT },
00442 { 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT },
00443 { 'E', 0, 0, N_("'E' modifier"), N_("the 'E' strftime modifier"), STD_C99 },
00444 { 'O', 0, 0, N_("'O' modifier"), N_("the 'O' strftime modifier"), STD_C99 },
00445 { 'O', 'o', 0, NULL, N_("the 'O' modifier"), STD_EXT },
00446 { 0, 0, 0, NULL, NULL, 0 }
00447 };
00448
00449
00450 static const format_flag_pair strftime_flag_pairs[] =
00451 {
00452 { 'E', 'O', 0, 0 },
00453 { '_', '-', 0, 0 },
00454 { '_', '0', 0, 0 },
00455 { '-', '0', 0, 0 },
00456 { '^', '#', 0, 0 },
00457 { 0, 0, 0, 0 }
00458 };
00459
00460
00461 static const format_flag_spec strfmon_flag_specs[] =
00462 {
00463 { '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 },
00464 { '^', 0, 0, N_("'^' flag"), N_("the '^' strfmon flag"), STD_C89 },
00465 { '+', 0, 0, N_("'+' flag"), N_("the '+' strfmon flag"), STD_C89 },
00466 { '(', 0, 0, N_("'(' flag"), N_("the '(' strfmon flag"), STD_C89 },
00467 { '!', 0, 0, N_("'!' flag"), N_("the '!' strfmon flag"), STD_C89 },
00468 { '-', 0, 0, N_("'-' flag"), N_("the '-' strfmon flag"), STD_C89 },
00469 { 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 },
00470 { '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 },
00471 { 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 },
00472 { 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 },
00473 { 0, 0, 0, NULL, NULL, 0 }
00474 };
00475
00476 static const format_flag_pair strfmon_flag_pairs[] =
00477 {
00478 { '+', '(', 0, 0 },
00479 { 0, 0, 0, 0 }
00480 };
00481
00482
00483 static const format_char_info print_char_table[] =
00484 {
00485
00486 { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "-wp0 +'I", "i", NULL },
00487 { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0#", "i", NULL },
00488 { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0'I", "i", NULL },
00489 { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "", NULL },
00490 { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#I", "", NULL },
00491 { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL },
00492 { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL },
00493 { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c", NULL },
00494 { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W", NULL },
00495
00496 { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "", NULL },
00497 { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL },
00498
00499 { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL },
00500 { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL },
00501
00502 { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL },
00503 { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
00504 };
00505
00506 static const format_char_info asm_fprintf_char_table[] =
00507 {
00508
00509 { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i", NULL },
00510 { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL },
00511 { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i", NULL },
00512 { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL },
00513 { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL },
00514
00515
00516 { "O", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00517 { "R", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00518 { "I", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00519 { "L", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00520 { "U", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00521 { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL },
00522 { "@", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00523 { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
00524 };
00525
00526 static const format_char_info gcc_diag_char_table[] =
00527 {
00528
00529 { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00530 { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00531 { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00532 { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00533 { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL },
00534 { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL },
00535
00536
00537
00538
00539 { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00540
00541
00542 { "J", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00543
00544 { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00545 { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
00546 { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
00547 };
00548
00549 static const format_char_info gcc_cdiag_char_table[] =
00550 {
00551
00552 { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00553 { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00554 { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00555 { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00556 { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL },
00557 { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL },
00558
00559
00560
00561
00562 { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00563
00564
00565 { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00566
00567 { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00568 { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
00569 { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
00570 };
00571
00572 static const format_char_info gcc_cxxdiag_char_table[] =
00573 {
00574
00575 { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00576 { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00577 { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00578 { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00579 { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL },
00580 { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL },
00581
00582
00583
00584
00585 { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00586
00587
00588 { "ADEFJTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL },
00589
00590
00591 { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
00592
00593 { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL },
00594 { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
00595 { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
00596 };
00597
00598 static const format_char_info scan_char_table[] =
00599 {
00600
00601 { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "*w'I", "W", NULL },
00602 { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w'I", "W", NULL },
00603 { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w", "W", NULL },
00604 { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL },
00605 { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW", NULL },
00606 { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW", NULL },
00607 { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[", NULL },
00608 { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL },
00609 { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W", NULL },
00610
00611 { "FaA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL },
00612
00613 { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL },
00614 { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "W", NULL },
00615 { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
00616 };
00617
00618 static const format_char_info time_char_table[] =
00619 {
00620
00621 { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "", NULL },
00622 { "cx", 0, STD_C89, NOLENGTHS, "E", "3", NULL },
00623 { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "", NULL },
00624 { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o", NULL },
00625 { "p", 0, STD_C89, NOLENGTHS, "#", "", NULL },
00626 { "X", 0, STD_C89, NOLENGTHS, "E", "", NULL },
00627 { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4", NULL },
00628 { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o", NULL },
00629 { "%", 0, STD_C89, NOLENGTHS, "", "", NULL },
00630
00631 { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o", NULL },
00632 { "D", 0, STD_C99, NOLENGTHS, "", "2", NULL },
00633 { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "", NULL },
00634 { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "", NULL },
00635 { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o", NULL },
00636 { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o", NULL },
00637 { "h", 0, STD_C99, NOLENGTHS, "^#", "", NULL },
00638 { "z", 0, STD_C99, NOLENGTHS, "O", "o", NULL },
00639
00640 { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "", NULL },
00641 { "P", 0, STD_EXT, NOLENGTHS, "", "", NULL },
00642 { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
00643 };
00644
00645 static const format_char_info monetary_char_table[] =
00646 {
00647 { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL },
00648 { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
00649 };
00650
00651
00652 static const format_kind_info format_types_orig[] =
00653 {
00654 { "printf", printf_length_specs, print_char_table, " +#0-'I", NULL,
00655 printf_flag_specs, printf_flag_pairs,
00656 FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
00657 'w', 0, 'p', 0, 'L',
00658 &integer_type_node, &integer_type_node
00659 },
00660 { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL,
00661 asm_fprintf_flag_specs, asm_fprintf_flag_pairs,
00662 FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK,
00663 'w', 0, 'p', 0, 'L',
00664 NULL, NULL
00665 },
00666 { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q", NULL,
00667 gcc_diag_flag_specs, gcc_diag_flag_pairs,
00668 FMT_FLAG_ARG_CONVERT,
00669 0, 0, 'p', 0, 'L',
00670 NULL, &integer_type_node
00671 },
00672 { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q", NULL,
00673 gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs,
00674 FMT_FLAG_ARG_CONVERT,
00675 0, 0, 'p', 0, 'L',
00676 NULL, &integer_type_node
00677 },
00678 { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "q+#", NULL,
00679 gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs,
00680 FMT_FLAG_ARG_CONVERT,
00681 0, 0, 'p', 0, 'L',
00682 NULL, &integer_type_node
00683 },
00684 { "scanf", scanf_length_specs, scan_char_table, "*'I", NULL,
00685 scanf_flag_specs, scanf_flag_pairs,
00686 FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
00687 'w', 0, 0, '*', 'L',
00688 NULL, NULL
00689 },
00690 { "strftime", NULL, time_char_table, "_-0^#", "EO",
00691 strftime_flag_specs, strftime_flag_pairs,
00692 FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0,
00693 NULL, NULL
00694 },
00695 { "strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
00696 strfmon_flag_specs, strfmon_flag_pairs,
00697 FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L',
00698 NULL, NULL
00699 }
00700 };
00701
00702
00703
00704
00705 static const format_kind_info *format_types = format_types_orig;
00706
00707
00708 static format_kind_info *dynamic_format_types;
00709
00710 static int n_format_types = ARRAY_SIZE (format_types_orig);
00711
00712
00713
00714
00715 typedef struct
00716 {
00717
00718
00719 int number_non_literal;
00720
00721
00722 int number_extra_args;
00723
00724
00725
00726 int number_dollar_extra_args;
00727
00728
00729 int number_wide;
00730
00731 int number_empty;
00732
00733
00734 int number_unterminated;
00735
00736 int number_other;
00737 } format_check_results;
00738
00739 typedef struct
00740 {
00741 format_check_results *res;
00742 function_format_info *info;
00743 tree params;
00744 } format_check_context;
00745
00746 static void check_format_info (function_format_info *, tree);
00747 static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT);
00748 static void check_format_info_main (format_check_results *,
00749 function_format_info *,
00750 const char *, int, tree,
00751 unsigned HOST_WIDE_INT);
00752
00753 static void init_dollar_format_checking (int, tree);
00754 static int maybe_read_dollar_number (const char **, int,
00755 tree, tree *, const format_kind_info *);
00756 static bool avoid_dollar_number (const char *);
00757 static void finish_dollar_format_checking (format_check_results *, int);
00758
00759 static const format_flag_spec *get_flag_spec (const format_flag_spec *,
00760 int, const char *);
00761
00762 static void check_format_types (format_wanted_type *, const char *, int);
00763 static void format_type_warning (const char *, const char *, int, tree,
00764 int, const char *, tree, int);
00765
00766
00767
00768
00769 static int
00770 decode_format_type (const char *s)
00771 {
00772 int i;
00773 int slen;
00774 slen = strlen (s);
00775 for (i = 0; i < n_format_types; i++)
00776 {
00777 int alen;
00778 if (!strcmp (s, format_types[i].name))
00779 return i;
00780 alen = strlen (format_types[i].name);
00781 if (slen == alen + 4 && s[0] == '_' && s[1] == '_'
00782 && s[slen - 1] == '_' && s[slen - 2] == '_'
00783 && !strncmp (s + 2, format_types[i].name, alen))
00784 return i;
00785 }
00786 return format_type_error;
00787 }
00788
00789
00790
00791
00792
00793
00794
00795
00796 void
00797 check_function_format (tree attrs, tree params)
00798 {
00799 tree a;
00800
00801
00802 for (a = attrs; a; a = TREE_CHAIN (a))
00803 {
00804 if (is_attribute_p ("format", TREE_PURPOSE (a)))
00805 {
00806
00807 function_format_info info;
00808 decode_format_attr (TREE_VALUE (a), &info, 1);
00809 check_format_info (&info, params);
00810 if (warn_missing_format_attribute && info.first_arg_num == 0
00811 && (format_types[info.format_type].flags
00812 & (int) FMT_FLAG_ARG_CONVERT))
00813 {
00814 tree c;
00815 for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00816 c;
00817 c = TREE_CHAIN (c))
00818 if (is_attribute_p ("format", TREE_PURPOSE (c))
00819 && (decode_format_type (IDENTIFIER_POINTER
00820 (TREE_VALUE (TREE_VALUE (c))))
00821 == info.format_type))
00822 break;
00823 if (c == NULL_TREE)
00824 {
00825
00826
00827
00828
00829 tree args;
00830 for (args = DECL_ARGUMENTS (current_function_decl);
00831 args != 0;
00832 args = TREE_CHAIN (args))
00833 {
00834 if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE
00835 && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args)))
00836 == char_type_node))
00837 break;
00838 }
00839 if (args != 0)
00840 warning ("function might be possible candidate for %qs format attribute",
00841 format_types[info.format_type].name);
00842 }
00843 }
00844 }
00845 }
00846 }
00847
00848
00849
00850 static char *dollar_arguments_used = NULL;
00851 static char *dollar_arguments_pointer_p = NULL;
00852 static int dollar_arguments_alloc = 0;
00853 static int dollar_arguments_count;
00854 static int dollar_first_arg_num;
00855 static int dollar_max_arg_used;
00856 static int dollar_format_warned;
00857
00858
00859
00860
00861
00862
00863
00864 static void
00865 init_dollar_format_checking (int first_arg_num, tree params)
00866 {
00867 tree oparams = params;
00868
00869 dollar_first_arg_num = first_arg_num;
00870 dollar_arguments_count = 0;
00871 dollar_max_arg_used = 0;
00872 dollar_format_warned = 0;
00873 if (first_arg_num > 0)
00874 {
00875 while (params)
00876 {
00877 dollar_arguments_count++;
00878 params = TREE_CHAIN (params);
00879 }
00880 }
00881 if (dollar_arguments_alloc < dollar_arguments_count)
00882 {
00883 if (dollar_arguments_used)
00884 free (dollar_arguments_used);
00885 if (dollar_arguments_pointer_p)
00886 free (dollar_arguments_pointer_p);
00887 dollar_arguments_alloc = dollar_arguments_count;
00888 dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc);
00889 dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc);
00890 }
00891 if (dollar_arguments_alloc)
00892 {
00893 memset (dollar_arguments_used, 0, dollar_arguments_alloc);
00894 if (first_arg_num > 0)
00895 {
00896 int i = 0;
00897 params = oparams;
00898 while (params)
00899 {
00900 dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params)))
00901 == POINTER_TYPE);
00902 params = TREE_CHAIN (params);
00903 i++;
00904 }
00905 }
00906 }
00907 }
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919 static int
00920 maybe_read_dollar_number (const char **format,
00921 int dollar_needed, tree params, tree *param_ptr,
00922 const format_kind_info *fki)
00923 {
00924 int argnum;
00925 int overflow_flag;
00926 const char *fcp = *format;
00927 if (!ISDIGIT (*fcp))
00928 {
00929 if (dollar_needed)
00930 {
00931 warning ("missing $ operand number in format");
00932 return -1;
00933 }
00934 else
00935 return 0;
00936 }
00937 argnum = 0;
00938 overflow_flag = 0;
00939 while (ISDIGIT (*fcp))
00940 {
00941 int nargnum;
00942 nargnum = 10 * argnum + (*fcp - '0');
00943 if (nargnum < 0 || nargnum / 10 != argnum)
00944 overflow_flag = 1;
00945 argnum = nargnum;
00946 fcp++;
00947 }
00948 if (*fcp != '$')
00949 {
00950 if (dollar_needed)
00951 {
00952 warning ("missing $ operand number in format");
00953 return -1;
00954 }
00955 else
00956 return 0;
00957 }
00958 *format = fcp + 1;
00959 if (pedantic && !dollar_format_warned)
00960 {
00961 warning ("%s does not support %%n$ operand number formats",
00962 C_STD_NAME (STD_EXT));
00963 dollar_format_warned = 1;
00964 }
00965 if (overflow_flag || argnum == 0
00966 || (dollar_first_arg_num && argnum > dollar_arguments_count))
00967 {
00968 warning ("operand number out of range in format");
00969 return -1;
00970 }
00971 if (argnum > dollar_max_arg_used)
00972 dollar_max_arg_used = argnum;
00973
00974
00975 while (dollar_arguments_alloc < dollar_max_arg_used)
00976 {
00977 int nalloc;
00978 nalloc = 2 * dollar_arguments_alloc + 16;
00979 dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used,
00980 nalloc);
00981 dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p,
00982 nalloc);
00983 memset (dollar_arguments_used + dollar_arguments_alloc, 0,
00984 nalloc - dollar_arguments_alloc);
00985 dollar_arguments_alloc = nalloc;
00986 }
00987 if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE)
00988 && dollar_arguments_used[argnum - 1] == 1)
00989 {
00990 dollar_arguments_used[argnum - 1] = 2;
00991 warning ("format argument %d used more than once in %s format",
00992 argnum, fki->name);
00993 }
00994 else
00995 dollar_arguments_used[argnum - 1] = 1;
00996 if (dollar_first_arg_num)
00997 {
00998 int i;
00999 *param_ptr = params;
01000 for (i = 1; i < argnum && *param_ptr != 0; i++)
01001 *param_ptr = TREE_CHAIN (*param_ptr);
01002
01003
01004 gcc_assert (*param_ptr);
01005 }
01006 else
01007 *param_ptr = 0;
01008 return argnum;
01009 }
01010
01011
01012
01013
01014 static bool
01015 avoid_dollar_number (const char *format)
01016 {
01017 if (!ISDIGIT (*format))
01018 return false;
01019 while (ISDIGIT (*format))
01020 format++;
01021 if (*format == '$')
01022 {
01023 warning ("$ operand number used after format without operand number");
01024 return true;
01025 }
01026 return false;
01027 }
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 static void
01041 finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok)
01042 {
01043 int i;
01044 bool found_pointer_gap = false;
01045 for (i = 0; i < dollar_max_arg_used; i++)
01046 {
01047 if (!dollar_arguments_used[i])
01048 {
01049 if (pointer_gap_ok && (dollar_first_arg_num == 0
01050 || dollar_arguments_pointer_p[i]))
01051 found_pointer_gap = true;
01052 else
01053 warning ("format argument %d unused before used argument %d in $-style format",
01054 i + 1, dollar_max_arg_used);
01055 }
01056 }
01057 if (found_pointer_gap
01058 || (dollar_first_arg_num
01059 && dollar_max_arg_used < dollar_arguments_count))
01060 {
01061 res->number_other--;
01062 res->number_dollar_extra_args++;
01063 }
01064 }
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075 static const format_flag_spec *
01076 get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates)
01077 {
01078 int i;
01079 for (i = 0; spec[i].flag_char != 0; i++)
01080 {
01081 if (spec[i].flag_char != flag)
01082 continue;
01083 if (predicates != NULL)
01084 {
01085 if (spec[i].predicate != 0
01086 && strchr (predicates, spec[i].predicate) != 0)
01087 return &spec[i];
01088 }
01089 else if (spec[i].predicate == 0)
01090 return &spec[i];
01091 }
01092 gcc_assert (predicates);
01093 return NULL;
01094 }
01095
01096
01097
01098
01099
01100
01101 static void
01102 check_format_info (function_format_info *info, tree params)
01103 {
01104 format_check_context format_ctx;
01105 unsigned HOST_WIDE_INT arg_num;
01106 tree format_tree;
01107 format_check_results res;
01108
01109
01110 for (arg_num = 1; ; ++arg_num)
01111 {
01112 if (params == 0)
01113 return;
01114 if (arg_num == info->format_num)
01115 break;
01116 params = TREE_CHAIN (params);
01117 }
01118 format_tree = TREE_VALUE (params);
01119 params = TREE_CHAIN (params);
01120 if (format_tree == 0)
01121 return;
01122
01123 res.number_non_literal = 0;
01124 res.number_extra_args = 0;
01125 res.number_dollar_extra_args = 0;
01126 res.number_wide = 0;
01127 res.number_empty = 0;
01128 res.number_unterminated = 0;
01129 res.number_other = 0;
01130
01131 format_ctx.res = &res;
01132 format_ctx.info = info;
01133 format_ctx.params = params;
01134
01135 check_function_arguments_recurse (check_format_arg, &format_ctx,
01136 format_tree, arg_num);
01137
01138 if (res.number_non_literal > 0)
01139 {
01140
01141
01142
01143 if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT))
01144 {
01145
01146
01147 if (warn_format_nonliteral)
01148 warning ("format not a string literal, format string not checked");
01149 }
01150 else if (info->first_arg_num != 0)
01151 {
01152
01153
01154 while (arg_num + 1 < info->first_arg_num)
01155 {
01156 if (params == 0)
01157 break;
01158 params = TREE_CHAIN (params);
01159 ++arg_num;
01160 }
01161 if (params == 0 && (warn_format_nonliteral || warn_format_security))
01162 warning ("format not a string literal and no format arguments");
01163 else if (warn_format_nonliteral)
01164 warning ("format not a string literal, argument types not checked");
01165 }
01166 }
01167
01168
01169
01170
01171
01172
01173
01174
01175 if (res.number_extra_args > 0 && res.number_non_literal == 0
01176 && res.number_other == 0 && warn_format_extra_args)
01177 warning ("too many arguments for format");
01178 if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
01179 && res.number_other == 0 && warn_format_extra_args)
01180 warning ("unused arguments in $-style format");
01181 if (res.number_empty > 0 && res.number_non_literal == 0
01182 && res.number_other == 0 && warn_format_zero_length)
01183 warning ("zero-length %s format string",
01184 format_types[info->format_type].name);
01185
01186 if (res.number_wide > 0)
01187 warning ("format is a wide character string");
01188
01189 if (res.number_unterminated > 0)
01190 warning ("unterminated format string");
01191 }
01192
01193
01194
01195
01196
01197
01198 static void
01199 check_format_arg (void *ctx, tree format_tree,
01200 unsigned HOST_WIDE_INT arg_num)
01201 {
01202 format_check_context *format_ctx = (format_check_context *) ctx;
01203 format_check_results *res = format_ctx->res;
01204 function_format_info *info = format_ctx->info;
01205 tree params = format_ctx->params;
01206
01207 int format_length;
01208 HOST_WIDE_INT offset;
01209 const char *format_chars;
01210 tree array_size = 0;
01211 tree array_init;
01212
01213 if (integer_zerop (format_tree))
01214 {
01215
01216
01217 while (arg_num + 1 < info->first_arg_num)
01218 {
01219 if (params == 0)
01220 return;
01221 params = TREE_CHAIN (params);
01222 ++arg_num;
01223 }
01224
01225 if (params == 0)
01226 res->number_other++;
01227 else
01228 res->number_extra_args++;
01229
01230 return;
01231 }
01232
01233 offset = 0;
01234 if (TREE_CODE (format_tree) == PLUS_EXPR)
01235 {
01236 tree arg0, arg1;
01237
01238 arg0 = TREE_OPERAND (format_tree, 0);
01239 arg1 = TREE_OPERAND (format_tree, 1);
01240 STRIP_NOPS (arg0);
01241 STRIP_NOPS (arg1);
01242 if (TREE_CODE (arg1) == INTEGER_CST)
01243 format_tree = arg0;
01244 else if (TREE_CODE (arg0) == INTEGER_CST)
01245 {
01246 format_tree = arg1;
01247 arg1 = arg0;
01248 }
01249 else
01250 {
01251 res->number_non_literal++;
01252 return;
01253 }
01254 if (!host_integerp (arg1, 0)
01255 || (offset = tree_low_cst (arg1, 0)) < 0)
01256 {
01257 res->number_non_literal++;
01258 return;
01259 }
01260 }
01261 if (TREE_CODE (format_tree) != ADDR_EXPR)
01262 {
01263 res->number_non_literal++;
01264 return;
01265 }
01266 format_tree = TREE_OPERAND (format_tree, 0);
01267 if (TREE_CODE (format_tree) == VAR_DECL
01268 && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
01269 && (array_init = decl_constant_value (format_tree)) != format_tree
01270 && TREE_CODE (array_init) == STRING_CST)
01271 {
01272
01273
01274
01275 array_size = DECL_SIZE_UNIT (format_tree);
01276 format_tree = array_init;
01277 }
01278 if (TREE_CODE (format_tree) != STRING_CST)
01279 {
01280 res->number_non_literal++;
01281 return;
01282 }
01283 if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node)
01284 {
01285 res->number_wide++;
01286 return;
01287 }
01288 format_chars = TREE_STRING_POINTER (format_tree);
01289 format_length = TREE_STRING_LENGTH (format_tree);
01290 if (array_size != 0)
01291 {
01292
01293 gcc_assert (TREE_CODE (array_size) == INTEGER_CST);
01294
01295 if (host_integerp (array_size, 0))
01296 {
01297 HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size);
01298 if (array_size_value > 0
01299 && array_size_value == (int) array_size_value
01300 && format_length > array_size_value)
01301 format_length = array_size_value;
01302 }
01303 }
01304 if (offset)
01305 {
01306 if (offset >= format_length)
01307 {
01308 res->number_non_literal++;
01309 return;
01310 }
01311 format_chars += offset;
01312 format_length -= offset;
01313 }
01314 if (format_length < 1)
01315 {
01316 res->number_unterminated++;
01317 return;
01318 }
01319 if (format_length == 1)
01320 {
01321 res->number_empty++;
01322 return;
01323 }
01324 if (format_chars[--format_length] != 0)
01325 {
01326 res->number_unterminated++;
01327 return;
01328 }
01329
01330
01331 while (arg_num + 1 < info->first_arg_num)
01332 {
01333 if (params == 0)
01334 return;
01335 params = TREE_CHAIN (params);
01336 ++arg_num;
01337 }
01338
01339
01340
01341 res->number_other++;
01342 check_format_info_main (res, info, format_chars, format_length,
01343 params, arg_num);
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354 static void
01355 check_format_info_main (format_check_results *res,
01356 function_format_info *info, const char *format_chars,
01357 int format_length, tree params,
01358 unsigned HOST_WIDE_INT arg_num)
01359 {
01360 const char *orig_format_chars = format_chars;
01361 tree first_fillin_param = params;
01362
01363 const format_kind_info *fki = &format_types[info->format_type];
01364 const format_flag_spec *flag_specs = fki->flag_specs;
01365 const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs;
01366
01367
01368
01369 int has_operand_number = -1;
01370
01371 init_dollar_format_checking (info->first_arg_num, first_fillin_param);
01372
01373 while (1)
01374 {
01375 int i;
01376 int suppressed = FALSE;
01377 const char *length_chars = NULL;
01378 enum format_lengths length_chars_val = FMT_LEN_none;
01379 enum format_std_version length_chars_std = STD_C89;
01380 int format_char;
01381 tree cur_param;
01382 tree wanted_type;
01383 int main_arg_num = 0;
01384 tree main_arg_params = 0;
01385 enum format_std_version wanted_type_std;
01386 const char *wanted_type_name;
01387 format_wanted_type width_wanted_type;
01388 format_wanted_type precision_wanted_type;
01389 format_wanted_type main_wanted_type;
01390 format_wanted_type *first_wanted_type = NULL;
01391 format_wanted_type *last_wanted_type = NULL;
01392 const format_length_info *fli = NULL;
01393 const format_char_info *fci = NULL;
01394 char flag_chars[256];
01395 int aflag = 0;
01396 const char *format_start = format_chars;
01397 if (*format_chars == 0)
01398 {
01399 if (format_chars - orig_format_chars != format_length)
01400 warning ("embedded %<\\0%> in format");
01401 if (info->first_arg_num != 0 && params != 0
01402 && has_operand_number <= 0)
01403 {
01404 res->number_other--;
01405 res->number_extra_args++;
01406 }
01407 if (has_operand_number > 0)
01408 finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
01409 return;
01410 }
01411 if (*format_chars++ != '%')
01412 continue;
01413 if (*format_chars == 0)
01414 {
01415 warning ("spurious trailing %<%%%> in format");
01416 continue;
01417 }
01418 if (*format_chars == '%')
01419 {
01420 ++format_chars;
01421 continue;
01422 }
01423 flag_chars[0] = 0;
01424
01425 if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
01426 {
01427
01428
01429
01430
01431 int opnum;
01432 opnum = maybe_read_dollar_number (&format_chars, 0,
01433 first_fillin_param,
01434 &main_arg_params, fki);
01435 if (opnum == -1)
01436 return;
01437 else if (opnum > 0)
01438 {
01439 has_operand_number = 1;
01440 main_arg_num = opnum + info->first_arg_num - 1;
01441 }
01442 }
01443 else if (fki->flags & FMT_FLAG_USE_DOLLAR)
01444 {
01445 if (avoid_dollar_number (format_chars))
01446 return;
01447 }
01448
01449
01450
01451
01452 while (*format_chars != 0
01453 && strchr (fki->flag_chars, *format_chars) != 0)
01454 {
01455 const format_flag_spec *s = get_flag_spec (flag_specs,
01456 *format_chars, NULL);
01457 if (strchr (flag_chars, *format_chars) != 0)
01458 {
01459 warning ("repeated %s in format", _(s->name));
01460 }
01461 else
01462 {
01463 i = strlen (flag_chars);
01464 flag_chars[i++] = *format_chars;
01465 flag_chars[i] = 0;
01466 }
01467 if (s->skip_next_char)
01468 {
01469 ++format_chars;
01470 if (*format_chars == 0)
01471 {
01472 warning ("missing fill character at end of strfmon format");
01473 return;
01474 }
01475 }
01476 ++format_chars;
01477 }
01478
01479
01480 if (fki->width_char != 0)
01481 {
01482 if (fki->width_type != NULL && *format_chars == '*')
01483 {
01484 i = strlen (flag_chars);
01485 flag_chars[i++] = fki->width_char;
01486 flag_chars[i] = 0;
01487
01488
01489 ++format_chars;
01490 if (has_operand_number != 0)
01491 {
01492 int opnum;
01493 opnum = maybe_read_dollar_number (&format_chars,
01494 has_operand_number == 1,
01495 first_fillin_param,
01496 ¶ms, fki);
01497 if (opnum == -1)
01498 return;
01499 else if (opnum > 0)
01500 {
01501 has_operand_number = 1;
01502 arg_num = opnum + info->first_arg_num - 1;
01503 }
01504 else
01505 has_operand_number = 0;
01506 }
01507 else
01508 {
01509 if (avoid_dollar_number (format_chars))
01510 return;
01511 }
01512 if (info->first_arg_num != 0)
01513 {
01514 if (params == 0)
01515 {
01516 warning ("too few arguments for format");
01517 return;
01518 }
01519 cur_param = TREE_VALUE (params);
01520 if (has_operand_number <= 0)
01521 {
01522 params = TREE_CHAIN (params);
01523 ++arg_num;
01524 }
01525 width_wanted_type.wanted_type = *fki->width_type;
01526 width_wanted_type.wanted_type_name = NULL;
01527 width_wanted_type.pointer_count = 0;
01528 width_wanted_type.char_lenient_flag = 0;
01529 width_wanted_type.writing_in_flag = 0;
01530 width_wanted_type.reading_from_flag = 0;
01531 width_wanted_type.name = _("field width");
01532 width_wanted_type.param = cur_param;
01533 width_wanted_type.arg_num = arg_num;
01534 width_wanted_type.next = NULL;
01535 if (last_wanted_type != 0)
01536 last_wanted_type->next = &width_wanted_type;
01537 if (first_wanted_type == 0)
01538 first_wanted_type = &width_wanted_type;
01539 last_wanted_type = &width_wanted_type;
01540 }
01541 }
01542 else
01543 {
01544
01545
01546 int non_zero_width_char = FALSE;
01547 int found_width = FALSE;
01548 while (ISDIGIT (*format_chars))
01549 {
01550 found_width = TRUE;
01551 if (*format_chars != '0')
01552 non_zero_width_char = TRUE;
01553 ++format_chars;
01554 }
01555 if (found_width && !non_zero_width_char &&
01556 (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
01557 warning ("zero width in %s format", fki->name);
01558 if (found_width)
01559 {
01560 i = strlen (flag_chars);
01561 flag_chars[i++] = fki->width_char;
01562 flag_chars[i] = 0;
01563 }
01564 }
01565 }
01566
01567
01568 if (fki->left_precision_char != 0 && *format_chars == '#')
01569 {
01570 ++format_chars;
01571 i = strlen (flag_chars);
01572 flag_chars[i++] = fki->left_precision_char;
01573 flag_chars[i] = 0;
01574 if (!ISDIGIT (*format_chars))
01575 warning ("empty left precision in %s format", fki->name);
01576 while (ISDIGIT (*format_chars))
01577 ++format_chars;
01578 }
01579
01580
01581 if (fki->precision_char != 0 && *format_chars == '.')
01582 {
01583 ++format_chars;
01584 i = strlen (flag_chars);
01585 flag_chars[i++] = fki->precision_char;
01586 flag_chars[i] = 0;
01587 if (fki->precision_type != NULL && *format_chars == '*')
01588 {
01589
01590
01591 ++format_chars;
01592 if (has_operand_number != 0)
01593 {
01594 int opnum;
01595 opnum = maybe_read_dollar_number (&format_chars,
01596 has_operand_number == 1,
01597 first_fillin_param,
01598 ¶ms, fki);
01599 if (opnum == -1)
01600 return;
01601 else if (opnum > 0)
01602 {
01603 has_operand_number = 1;
01604 arg_num = opnum + info->first_arg_num - 1;
01605 }
01606 else
01607 has_operand_number = 0;
01608 }
01609 else
01610 {
01611 if (avoid_dollar_number (format_chars))
01612 return;
01613 }
01614 if (info->first_arg_num != 0)
01615 {
01616 if (params == 0)
01617 {
01618 warning ("too few arguments for format");
01619 return;
01620 }
01621 cur_param = TREE_VALUE (params);
01622 if (has_operand_number <= 0)
01623 {
01624 params = TREE_CHAIN (params);
01625 ++arg_num;
01626 }
01627 precision_wanted_type.wanted_type = *fki->precision_type;
01628 precision_wanted_type.wanted_type_name = NULL;
01629 precision_wanted_type.pointer_count = 0;
01630 precision_wanted_type.char_lenient_flag = 0;
01631 precision_wanted_type.writing_in_flag = 0;
01632 precision_wanted_type.reading_from_flag = 0;
01633 precision_wanted_type.name = _("field precision");
01634 precision_wanted_type.param = cur_param;
01635 precision_wanted_type.arg_num = arg_num;
01636 precision_wanted_type.next = NULL;
01637 if (last_wanted_type != 0)
01638 last_wanted_type->next = &precision_wanted_type;
01639 if (first_wanted_type == 0)
01640 first_wanted_type = &precision_wanted_type;
01641 last_wanted_type = &precision_wanted_type;
01642 }
01643 }
01644 else
01645 {
01646 if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
01647 && !ISDIGIT (*format_chars))
01648 warning ("empty precision in %s format", fki->name);
01649 while (ISDIGIT (*format_chars))
01650 ++format_chars;
01651 }
01652 }
01653
01654
01655 fli = fki->length_char_specs;
01656 length_chars = NULL;
01657 length_chars_val = FMT_LEN_none;
01658 length_chars_std = STD_C89;
01659 if (fli)
01660 {
01661 while (fli->name != 0 && fli->name[0] != *format_chars)
01662 fli++;
01663 if (fli->name != 0)
01664 {
01665 format_chars++;
01666 if (fli->double_name != 0 && fli->name[0] == *format_chars)
01667 {
01668 format_chars++;
01669 length_chars = fli->double_name;
01670 length_chars_val = fli->double_index;
01671 length_chars_std = fli->double_std;
01672 }
01673 else
01674 {
01675 length_chars = fli->name;
01676 length_chars_val = fli->index;
01677 length_chars_std = fli->std;
01678 }
01679 i = strlen (flag_chars);
01680 flag_chars[i++] = fki->length_code_char;
01681 flag_chars[i] = 0;
01682 }
01683 if (pedantic)
01684 {
01685
01686 if (ADJ_STD (length_chars_std) > C_STD_VER)
01687 warning ("%s does not support the %qs %s length modifier",
01688 C_STD_NAME (length_chars_std), length_chars,
01689 fki->name);
01690 }
01691 }
01692
01693
01694 if (fki->modifier_chars != NULL)
01695 {
01696 while (*format_chars != 0
01697 && strchr (fki->modifier_chars, *format_chars) != 0)
01698 {
01699 if (strchr (flag_chars, *format_chars) != 0)
01700 {
01701 const format_flag_spec *s = get_flag_spec (flag_specs,
01702 *format_chars, NULL);
01703 warning ("repeated %s in format", _(s->name));
01704 }
01705 else
01706 {
01707 i = strlen (flag_chars);
01708 flag_chars[i++] = *format_chars;
01709 flag_chars[i] = 0;
01710 }
01711 ++format_chars;
01712 }
01713 }
01714
01715
01716 if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
01717 {
01718 if (*format_chars == 'a' && !flag_isoc99)
01719 {
01720 if (format_chars[1] == 's' || format_chars[1] == 'S'
01721 || format_chars[1] == '[')
01722 {
01723
01724 i = strlen (flag_chars);
01725 flag_chars[i++] = 'a';
01726 flag_chars[i] = 0;
01727 format_chars++;
01728 }
01729 }
01730 }
01731
01732 format_char = *format_chars;
01733 if (format_char == 0
01734 || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
01735 && format_char == '%'))
01736 {
01737 warning ("conversion lacks type at end of format");
01738 continue;
01739 }
01740 format_chars++;
01741 fci = fki->conversion_specs;
01742 while (fci->format_chars != 0
01743 && strchr (fci->format_chars, format_char) == 0)
01744 ++fci;
01745 if (fci->format_chars == 0)
01746 {
01747 if (ISGRAPH (format_char))
01748 warning ("unknown conversion type character %qc in format",
01749 format_char);
01750 else
01751 warning ("unknown conversion type character 0x%x in format",
01752 format_char);
01753 continue;
01754 }
01755 if (pedantic)
01756 {
01757 if (ADJ_STD (fci->std) > C_STD_VER)
01758 warning ("%s does not support the %<%%%c%> %s format",
01759 C_STD_NAME (fci->std), format_char, fki->name);
01760 }
01761
01762
01763 {
01764 int d = 0;
01765 for (i = 0; flag_chars[i] != 0; i++)
01766 {
01767 const format_flag_spec *s = get_flag_spec (flag_specs,
01768 flag_chars[i], NULL);
01769 flag_chars[i - d] = flag_chars[i];
01770 if (flag_chars[i] == fki->length_code_char)
01771 continue;
01772 if (strchr (fci->flag_chars, flag_chars[i]) == 0)
01773 {
01774 warning ("%s used with %<%%%c%> %s format",
01775 _(s->name), format_char, fki->name);
01776 d++;
01777 continue;
01778 }
01779 if (pedantic)
01780 {
01781 const format_flag_spec *t;
01782 if (ADJ_STD (s->std) > C_STD_VER)
01783 warning ("%s does not support %s",
01784 C_STD_NAME (s->std), _(s->long_name));
01785 t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2);
01786 if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
01787 {
01788 const char *long_name = (t->long_name != NULL
01789 ? t->long_name
01790 : s->long_name);
01791 if (ADJ_STD (t->std) > C_STD_VER)
01792 warning ("%s does not support %s with the %<%%%c%> %s format",
01793 C_STD_NAME (t->std), _(long_name),
01794 format_char, fki->name);
01795 }
01796 }
01797 }
01798 flag_chars[i - d] = 0;
01799 }
01800
01801 if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
01802 && strchr (flag_chars, 'a') != 0)
01803 aflag = 1;
01804
01805 if (fki->suppression_char
01806 && strchr (flag_chars, fki->suppression_char) != 0)
01807 suppressed = 1;
01808
01809
01810 for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
01811 {
01812 const format_flag_spec *s, *t;
01813 if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0)
01814 continue;
01815 if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0)
01816 continue;
01817 if (bad_flag_pairs[i].predicate != 0
01818 && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0)
01819 continue;
01820 s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
01821 t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
01822 if (bad_flag_pairs[i].ignored)
01823 {
01824 if (bad_flag_pairs[i].predicate != 0)
01825 warning ("%s ignored with %s and %<%%%c%> %s format",
01826 _(s->name), _(t->name), format_char,
01827 fki->name);
01828 else
01829 warning ("%s ignored with %s in %s format",
01830 _(s->name), _(t->name), fki->name);
01831 }
01832 else
01833 {
01834 if (bad_flag_pairs[i].predicate != 0)
01835 warning ("use of %s and %s together with %<%%%c%> %s format",
01836 _(s->name), _(t->name), format_char,
01837 fki->name);
01838 else
01839 warning ("use of %s and %s together in %s format",
01840 _(s->name), _(t->name), fki->name);
01841 }
01842 }
01843
01844
01845 if (warn_format_y2k)
01846 {
01847 int y2k_level = 0;
01848 if (strchr (fci->flags2, '4') != 0)
01849 if (strchr (flag_chars, 'E') != 0)
01850 y2k_level = 3;
01851 else
01852 y2k_level = 2;
01853 else if (strchr (fci->flags2, '3') != 0)
01854 y2k_level = 3;
01855 else if (strchr (fci->flags2, '2') != 0)
01856 y2k_level = 2;
01857 if (y2k_level == 3)
01858 warning ("%<%%%c%> yields only last 2 digits of year in some locales",
01859 format_char);
01860 else if (y2k_level == 2)
01861 warning ("%<%%%c%> yields only last 2 digits of year", format_char);
01862 }
01863
01864 if (strchr (fci->flags2, '[') != 0)
01865 {
01866
01867 if (*format_chars == '^')
01868 ++format_chars;
01869
01870
01871 if (*format_chars == ']')
01872 ++format_chars;
01873 while (*format_chars && *format_chars != ']')
01874 ++format_chars;
01875 if (*format_chars != ']')
01876
01877 warning ("no closing %<]%> for %<%%[%> format");
01878 }
01879
01880 wanted_type = 0;
01881 wanted_type_name = 0;
01882 if (fki->flags & (int) FMT_FLAG_ARG_CONVERT)
01883 {
01884 wanted_type = (fci->types[length_chars_val].type
01885 ? *fci->types[length_chars_val].type : 0);
01886 wanted_type_name = fci->types[length_chars_val].name;
01887 wanted_type_std = fci->types[length_chars_val].std;
01888 if (wanted_type == 0)
01889 {
01890 warning ("use of %qs length modifier with %qc type character",
01891 length_chars, format_char);
01892
01893
01894 arg_num++;
01895 if (params == 0)
01896 {
01897 warning ("too few arguments for format");
01898 return;
01899 }
01900 params = TREE_CHAIN (params);
01901 continue;
01902 }
01903 else if (pedantic
01904
01905
01906
01907 && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std)
01908 && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
01909 {
01910 if (ADJ_STD (wanted_type_std) > C_STD_VER)
01911 warning ("%s does not support the %<%%%s%c%> %s format",
01912 C_STD_NAME (wanted_type_std), length_chars,
01913 format_char, fki->name);
01914 }
01915 }
01916
01917 main_wanted_type.next = NULL;
01918
01919
01920 if (info->first_arg_num == 0)
01921 continue;
01922 if ((fci->pointer_count == 0 && wanted_type == void_type_node)
01923 || suppressed)
01924 {
01925 if (main_arg_num != 0)
01926 {
01927 if (suppressed)
01928 warning ("operand number specified with suppressed assignment");
01929 else
01930 warning ("operand number specified for format taking no argument");
01931 }
01932 }
01933 else
01934 {
01935 format_wanted_type *wanted_type_ptr;
01936
01937 if (main_arg_num != 0)
01938 {
01939 arg_num = main_arg_num;
01940 params = main_arg_params;
01941 }
01942 else
01943 {
01944 ++arg_num;
01945 if (has_operand_number > 0)
01946 {
01947 warning ("missing $ operand number in format");
01948 return;
01949 }
01950 else
01951 has_operand_number = 0;
01952 }
01953
01954 wanted_type_ptr = &main_wanted_type;
01955 while (fci)
01956 {
01957 if (params == 0)
01958 {
01959 warning ("too few arguments for format");
01960 return;
01961 }
01962
01963 cur_param = TREE_VALUE (params);
01964 params = TREE_CHAIN (params);
01965
01966 wanted_type_ptr->wanted_type = wanted_type;
01967 wanted_type_ptr->wanted_type_name = wanted_type_name;
01968 wanted_type_ptr->pointer_count = fci->pointer_count + aflag;
01969 wanted_type_ptr->char_lenient_flag = 0;
01970 if (strchr (fci->flags2, 'c') != 0)
01971 wanted_type_ptr->char_lenient_flag = 1;
01972 wanted_type_ptr->writing_in_flag = 0;
01973 wanted_type_ptr->reading_from_flag = 0;
01974 if (aflag)
01975 wanted_type_ptr->writing_in_flag = 1;
01976 else
01977 {
01978 if (strchr (fci->flags2, 'W') != 0)
01979 wanted_type_ptr->writing_in_flag = 1;
01980 if (strchr (fci->flags2, 'R') != 0)
01981 wanted_type_ptr->reading_from_flag = 1;
01982 }
01983 wanted_type_ptr->name = NULL;
01984 wanted_type_ptr->param = cur_param;
01985 wanted_type_ptr->arg_num = arg_num;
01986 wanted_type_ptr->next = NULL;
01987 if (last_wanted_type != 0)
01988 last_wanted_type->next = wanted_type_ptr;
01989 if (first_wanted_type == 0)
01990 first_wanted_type = wanted_type_ptr;
01991 last_wanted_type = wanted_type_ptr;
01992
01993 fci = fci->chain;
01994 if (fci)
01995 {
01996 wanted_type_ptr = ggc_alloc (sizeof (main_wanted_type));
01997 arg_num++;
01998 wanted_type = *fci->types[length_chars_val].type;
01999 wanted_type_name = fci->types[length_chars_val].name;
02000 }
02001 }
02002 }
02003
02004 if (first_wanted_type != 0)
02005 check_format_types (first_wanted_type, format_start,
02006 format_chars - format_start);
02007
02008 if (main_wanted_type.next != NULL)
02009 {
02010 format_wanted_type *wanted_type_ptr = main_wanted_type.next;
02011 while (wanted_type_ptr)
02012 {
02013 format_wanted_type *next = wanted_type_ptr->next;
02014 ggc_free (wanted_type_ptr);
02015 wanted_type_ptr = next;
02016 }
02017 }
02018 }
02019 }
02020
02021
02022
02023
02024 static void
02025 check_format_types (format_wanted_type *types, const char *format_start,
02026 int format_length)
02027 {
02028 for (; types != 0; types = types->next)
02029 {
02030 tree cur_param;
02031 tree cur_type;
02032 tree orig_cur_type;
02033 tree wanted_type;
02034 int arg_num;
02035 int i;
02036 int char_type_flag;
02037 cur_param = types->param;
02038 cur_type = TREE_TYPE (cur_param);
02039 if (cur_type == error_mark_node)
02040 continue;
02041 orig_cur_type = cur_type;
02042 char_type_flag = 0;
02043 wanted_type = types->wanted_type;
02044 arg_num = types->arg_num;
02045
02046
02047 gcc_assert (wanted_type);
02048 gcc_assert (wanted_type != void_type_node || types->pointer_count);
02049
02050 if (types->pointer_count == 0)
02051 wanted_type = lang_hooks.types.type_promotes_to (wanted_type);
02052
02053 wanted_type = TYPE_MAIN_VARIANT (wanted_type);
02054
02055 STRIP_NOPS (cur_param);
02056
02057
02058
02059 for (i = 0; i < types->pointer_count; ++i)
02060 {
02061 if (TREE_CODE (cur_type) == POINTER_TYPE)
02062 {
02063 cur_type = TREE_TYPE (cur_type);
02064 if (cur_type == error_mark_node)
02065 break;
02066
02067
02068 if (types->writing_in_flag
02069 && i == 0
02070 && cur_param != 0
02071 && integer_zerop (cur_param))
02072 warning ("writing through null pointer (argument %d)",
02073 arg_num);
02074
02075
02076 if (types->reading_from_flag
02077 && i == 0
02078 && cur_param != 0
02079 && integer_zerop (cur_param))
02080 warning ("reading through null pointer (argument %d)",
02081 arg_num);
02082
02083 if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
02084 cur_param = TREE_OPERAND (cur_param, 0);
02085 else
02086 cur_param = 0;
02087
02088
02089
02090
02091
02092
02093 if (types->writing_in_flag
02094 && i == 0
02095 && (TYPE_READONLY (cur_type)
02096 || (cur_param != 0
02097 && (CONSTANT_CLASS_P (cur_param)
02098 || (DECL_P (cur_param)
02099 && TREE_READONLY (cur_param))))))
02100 warning ("writing into constant object (argument %d)",
02101 arg_num);
02102
02103
02104
02105
02106 if (i > 0
02107 && pedantic
02108 && (TYPE_READONLY (cur_type)
02109 || TYPE_VOLATILE (cur_type)
02110 || TYPE_RESTRICT (cur_type)))
02111 warning ("extra type qualifiers in format argument "
02112 "(argument %d)",
02113 arg_num);
02114
02115 }
02116 else
02117 {
02118 format_type_warning (types->name, format_start, format_length,
02119 wanted_type, types->pointer_count,
02120 types->wanted_type_name, orig_cur_type,
02121 arg_num);
02122 break;
02123 }
02124 }
02125
02126 if (i < types->pointer_count)
02127 continue;
02128
02129 cur_type = TYPE_MAIN_VARIANT (cur_type);
02130
02131
02132
02133
02134 if (types->char_lenient_flag)
02135 char_type_flag = (cur_type == char_type_node
02136 || cur_type == signed_char_type_node
02137 || cur_type == unsigned_char_type_node);
02138
02139
02140 if (wanted_type == cur_type)
02141 continue;
02142
02143
02144
02145
02146 if (wanted_type == void_type_node
02147 && (!pedantic || (i == 1 && char_type_flag)))
02148 continue;
02149
02150
02151
02152
02153 if (TREE_CODE (wanted_type) == INTEGER_TYPE
02154 && TREE_CODE (cur_type) == INTEGER_TYPE
02155 && (!pedantic || i == 0 || (i == 1 && char_type_flag))
02156 && (TYPE_UNSIGNED (wanted_type)
02157 ? wanted_type == c_common_unsigned_type (cur_type)
02158 : wanted_type == c_common_signed_type (cur_type)))
02159 continue;
02160
02161
02162 if (wanted_type == char_type_node
02163 && (!pedantic || i < 2)
02164 && char_type_flag)
02165 continue;
02166
02167 format_type_warning (types->name, format_start, format_length,
02168 wanted_type, types->pointer_count,
02169 types->wanted_type_name, orig_cur_type, arg_num);
02170 }
02171 }
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182
02183
02184 static void
02185 format_type_warning (const char *descr, const char *format_start,
02186 int format_length, tree wanted_type, int pointer_count,
02187 const char *wanted_type_name, tree arg_type, int arg_num)
02188 {
02189 char *p;
02190
02191
02192
02193 if (wanted_type_name
02194 && TYPE_NAME (arg_type)
02195 && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL
02196 && DECL_NAME (TYPE_NAME (arg_type))
02197 && !strcmp (wanted_type_name,
02198 lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2)))
02199 arg_type = TYPE_MAIN_VARIANT (arg_type);
02200
02201
02202
02203
02204
02205 p = alloca (pointer_count + 2);
02206 if (pointer_count == 0)
02207 p[0] = 0;
02208 else if (c_dialect_cxx ())
02209 {
02210 memset (p, '*', pointer_count);
02211 p[pointer_count] = 0;
02212 }
02213 else
02214 {
02215 p[0] = ' ';
02216 memset (p + 1, '*', pointer_count);
02217 p[pointer_count + 1] = 0;
02218 }
02219 if (wanted_type_name)
02220 {
02221 if (descr)
02222 warning ("%s should have type %<%s%s%>, but argument %d has type %qT",
02223 descr, wanted_type_name, p, arg_num, arg_type);
02224 else
02225 warning ("format %q.*s expects type %<%s%s%>, but argument %d has type %qT",
02226 format_length, format_start, wanted_type_name, p,
02227 arg_num, arg_type);
02228 }
02229 else
02230 {
02231 if (descr)
02232 warning ("%s should have type %<%T%s%>, but argument %d has type %qT",
02233 descr, wanted_type, p, arg_num, arg_type);
02234 else
02235 warning ("format %q.*s expects type %<%T%s%>, but argument %d has type %qT",
02236 format_length, format_start, wanted_type, p, arg_num, arg_type);
02237 }
02238 }
02239
02240
02241
02242
02243
02244 static unsigned int
02245 find_char_info_specifier_index (const format_char_info *fci, int c)
02246 {
02247 unsigned i;
02248
02249 for (i = 0; fci->format_chars; i++, fci++)
02250 if (strchr (fci->format_chars, c))
02251 return i;
02252
02253
02254 gcc_unreachable ();
02255 }
02256
02257
02258
02259
02260
02261 static unsigned int
02262 find_length_info_modifier_index (const format_length_info *fli, int c)
02263 {
02264 unsigned i;
02265
02266 for (i = 0; fli->name; i++, fli++)
02267 if (strchr (fli->name, c))
02268 return i;
02269
02270
02271 gcc_unreachable ();
02272 }
02273
02274
02275
02276
02277 static void
02278 init_dynamic_asm_fprintf_info (void)
02279 {
02280 static tree hwi;
02281
02282 if (!hwi)
02283 {
02284 format_length_info *new_asm_fprintf_length_specs;
02285 unsigned int i;
02286
02287
02288
02289
02290
02291 hwi = maybe_get_identifier ("__gcc_host_wide_int__");
02292 if (!hwi)
02293 {
02294 error ("%<__gcc_host_wide_int__%> is not defined as a type");
02295 return;
02296 }
02297 hwi = identifier_global_value (hwi);
02298 if (!hwi || TREE_CODE (hwi) != TYPE_DECL)
02299 {
02300 error ("%<__gcc_host_wide_int__%> is not defined as a type");
02301 return;
02302 }
02303 hwi = DECL_ORIGINAL_TYPE (hwi);
02304 gcc_assert (hwi);
02305 if (hwi != long_integer_type_node && hwi != long_long_integer_type_node)
02306 {
02307 error ("%<__gcc_host_wide_int__%> is not defined as %<long%>"
02308 " or %<long long%>");
02309 return;
02310 }
02311
02312
02313 new_asm_fprintf_length_specs = (format_length_info *)
02314 xmemdup (asm_fprintf_length_specs,
02315 sizeof (asm_fprintf_length_specs),
02316 sizeof (asm_fprintf_length_specs));
02317
02318
02319 i = find_length_info_modifier_index (new_asm_fprintf_length_specs, 'w');
02320 if (hwi == long_integer_type_node)
02321 new_asm_fprintf_length_specs[i].index = FMT_LEN_l;
02322 else if (hwi == long_long_integer_type_node)
02323 new_asm_fprintf_length_specs[i].index = FMT_LEN_ll;
02324 else
02325 gcc_unreachable ();
02326
02327
02328 dynamic_format_types[asm_fprintf_format_type].length_char_specs =
02329 new_asm_fprintf_length_specs;
02330 }
02331 }
02332
02333
02334
02335
02336 static void
02337 init_dynamic_diag_info (void)
02338 {
02339 static tree t, loc, hwi;
02340
02341 if (!loc || !t || !hwi)
02342 {
02343 static format_char_info *diag_fci, *cdiag_fci, *cxxdiag_fci;
02344 static format_length_info *diag_ls;
02345 unsigned int i;
02346
02347
02348
02349
02350
02351
02352
02353 if ((loc = maybe_get_identifier ("location_t")))
02354 {
02355 loc = identifier_global_value (loc);
02356 if (loc)
02357 {
02358 if (TREE_CODE (loc) != TYPE_DECL)
02359 {
02360 error ("%<location_t%> is not defined as a type");
02361 loc = 0;
02362 }
02363 else
02364 loc = TREE_TYPE (loc);
02365 }
02366 }
02367
02368
02369
02370 if ((t = maybe_get_identifier ("tree")))
02371 {
02372 t = identifier_global_value (t);
02373 if (t)
02374 {
02375 if (TREE_CODE (t) != TYPE_DECL)
02376 {
02377 error ("%<tree%> is not defined as a type");
02378 t = 0;
02379 }
02380 else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
02381 {
02382 error ("%<tree%> is not defined as a pointer type");
02383 t = 0;
02384 }
02385 else
02386 t = TREE_TYPE (TREE_TYPE (t));
02387 }
02388 }
02389
02390
02391
02392
02393
02394 if ((hwi = maybe_get_identifier ("__gcc_host_wide_int__")))
02395 {
02396 hwi = identifier_global_value (hwi);
02397 if (hwi)
02398 {
02399 if (TREE_CODE (hwi) != TYPE_DECL)
02400 {
02401 error ("%<__gcc_host_wide_int__%> is not defined as a type");
02402 hwi = 0;
02403 }
02404 else
02405 {
02406 hwi = DECL_ORIGINAL_TYPE (hwi);
02407 gcc_assert (hwi);
02408 if (hwi != long_integer_type_node
02409 && hwi != long_long_integer_type_node)
02410 {
02411 error ("%<__gcc_host_wide_int__%> is not defined"
02412 " as %<long%> or %<long long%>");
02413 hwi = 0;
02414 }
02415 }
02416 }
02417 }
02418
02419
02420
02421
02422 if (!diag_ls)
02423 dynamic_format_types[gcc_diag_format_type].length_char_specs =
02424 dynamic_format_types[gcc_cdiag_format_type].length_char_specs =
02425 dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs =
02426 diag_ls = (format_length_info *)
02427 xmemdup (gcc_diag_length_specs,
02428 sizeof (gcc_diag_length_specs),
02429 sizeof (gcc_diag_length_specs));
02430 if (hwi)
02431 {
02432
02433 i = find_length_info_modifier_index (diag_ls, 'w');
02434 if (hwi == long_integer_type_node)
02435 diag_ls[i].index = FMT_LEN_l;
02436 else if (hwi == long_long_integer_type_node)
02437 diag_ls[i].index = FMT_LEN_ll;
02438 else
02439 gcc_unreachable ();
02440 }
02441
02442
02443 if (!diag_fci)
02444 dynamic_format_types[gcc_diag_format_type].conversion_specs =
02445 diag_fci = (format_char_info *)
02446 xmemdup (gcc_diag_char_table,
02447 sizeof (gcc_diag_char_table),
02448 sizeof (gcc_diag_char_table));
02449 if (loc)
02450 {
02451 i = find_char_info_specifier_index (diag_fci, 'H');
02452 diag_fci[i].types[0].type = &loc;
02453 diag_fci[i].pointer_count = 1;
02454 }
02455 if (t)
02456 {
02457 i = find_char_info_specifier_index (diag_fci, 'J');
02458 diag_fci[i].types[0].type = &t;
02459 diag_fci[i].pointer_count = 1;
02460 }
02461
02462
02463 if (!cdiag_fci)
02464 dynamic_format_types[gcc_cdiag_format_type].conversion_specs =
02465 cdiag_fci = (format_char_info *)
02466 xmemdup (gcc_cdiag_char_table,
02467 sizeof (gcc_cdiag_char_table),
02468 sizeof (gcc_cdiag_char_table));
02469 if (loc)
02470 {
02471 i = find_char_info_specifier_index (cdiag_fci, 'H');
02472 cdiag_fci[i].types[0].type = &loc;
02473 cdiag_fci[i].pointer_count = 1;
02474 }
02475 if (t)
02476 {
02477
02478 i = find_char_info_specifier_index (cdiag_fci, 'D');
02479 cdiag_fci[i].types[0].type = &t;
02480 cdiag_fci[i].pointer_count = 1;
02481 i = find_char_info_specifier_index (cdiag_fci, 'J');
02482 cdiag_fci[i].types[0].type = &t;
02483 cdiag_fci[i].pointer_count = 1;
02484 }
02485
02486
02487 if (!cxxdiag_fci)
02488 dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs =
02489 cxxdiag_fci = (format_char_info *)
02490 xmemdup (gcc_cxxdiag_char_table,
02491 sizeof (gcc_cxxdiag_char_table),
02492 sizeof (gcc_cxxdiag_char_table));
02493 if (loc)
02494 {
02495 i = find_char_info_specifier_index (cxxdiag_fci, 'H');
02496 cxxdiag_fci[i].types[0].type = &loc;
02497 cxxdiag_fci[i].pointer_count = 1;
02498 }
02499 if (t)
02500 {
02501
02502 i = find_char_info_specifier_index (cxxdiag_fci, 'D');
02503 cxxdiag_fci[i].types[0].type = &t;
02504 cxxdiag_fci[i].pointer_count = 1;
02505 i = find_char_info_specifier_index (cxxdiag_fci, 'J');
02506 cxxdiag_fci[i].types[0].type = &t;
02507 cxxdiag_fci[i].pointer_count = 1;
02508 }
02509 }
02510 }
02511
02512 #ifdef TARGET_FORMAT_TYPES
02513 extern const format_kind_info TARGET_FORMAT_TYPES[];
02514 #endif
02515
02516
02517
02518 tree
02519 handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
02520 int flags, bool *no_add_attrs)
02521 {
02522 tree type = *node;
02523 function_format_info info;
02524 tree argument;
02525
02526 #ifdef TARGET_FORMAT_TYPES
02527
02528
02529 if (TARGET_FORMAT_TYPES != NULL && !dynamic_format_types)
02530 {
02531 dynamic_format_types = xmalloc ((n_format_types + TARGET_N_FORMAT_TYPES)
02532 * sizeof (dynamic_format_types[0]));
02533 memcpy (dynamic_format_types, format_types_orig,
02534 sizeof (format_types_orig));
02535 memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES,
02536 TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0]));
02537
02538 format_types = dynamic_format_types;
02539 n_format_types += TARGET_N_FORMAT_TYPES;
02540 }
02541 #endif
02542
02543 if (!decode_format_attr (args, &info, 0))
02544 {
02545 *no_add_attrs = true;
02546 return NULL_TREE;
02547 }
02548
02549 argument = TYPE_ARG_TYPES (type);
02550 if (argument)
02551 {
02552 if (!check_format_string (argument, info.format_num, flags,
02553 no_add_attrs))
02554 return NULL_TREE;
02555
02556 if (info.first_arg_num != 0)
02557 {
02558 unsigned HOST_WIDE_INT arg_num = 1;
02559
02560
02561
02562 while (argument)
02563 arg_num++, argument = TREE_CHAIN (argument);
02564
02565 if (arg_num != info.first_arg_num)
02566 {
02567 if (!(flags & (int) ATTR_FLAG_BUILT_IN))
02568 error ("args to be formatted is not %<...%>");
02569 *no_add_attrs = true;
02570 return NULL_TREE;
02571 }
02572 }
02573 }
02574
02575 if (info.format_type == strftime_format_type && info.first_arg_num != 0)
02576 {
02577 error ("strftime formats cannot format arguments");
02578 *no_add_attrs = true;
02579 return NULL_TREE;
02580 }
02581
02582
02583
02584 if (info.format_type == asm_fprintf_format_type
02585 || info.format_type == gcc_diag_format_type
02586 || info.format_type == gcc_cdiag_format_type
02587 || info.format_type == gcc_cxxdiag_format_type)
02588 {
02589
02590
02591 if (!dynamic_format_types)
02592 format_types = dynamic_format_types = (format_kind_info *)
02593 xmemdup (format_types_orig, sizeof (format_types_orig),
02594 sizeof (format_types_orig));
02595
02596
02597
02598 if (info.format_type == asm_fprintf_format_type)
02599 init_dynamic_asm_fprintf_info ();
02600
02601
02602 else if (info.format_type == gcc_diag_format_type
02603 || info.format_type == gcc_cdiag_format_type
02604 || info.format_type == gcc_cxxdiag_format_type)
02605 init_dynamic_diag_info ();
02606 else
02607 gcc_unreachable ();
02608 }
02609
02610 return NULL_TREE;
02611 }