{
/* find format arg */
unsigned idx = 0;
- for (; idx < spec->fmt_idx; ++idx)
+ for (; idx < spec->fmt_idx; ++idx) {
+ if (arg == NULL)
+ return;
arg = arg->next;
+ }
const expression_t *fmt_expr = arg->expression;
if (fmt_expr->kind == EXPR_UNARY_CAST_IMPLICIT) {
return;
}
/* find the real args */
- for(; idx < spec->arg_idx; ++idx)
+ for(; idx < spec->arg_idx && arg != NULL; ++idx)
arg = arg->next;
const source_position_t *pos = &fmt_expr->base.source_position;
default:
warningf(pos, "encountered unknown conversion specifier '%%%C' at position %u", (wint_t)fmt, num_fmt);
+ if (arg == NULL) {
+ warningf(pos, "too few arguments for format string");
+ return;
+ }
goto next_arg;
}
format_flags_t wrong_flags = fmt_flags & ~allowed_flags;
if (wrong_flags != 0) {
- char wrong[8];
- int idx = 0;
- if (wrong_flags & FMT_FLAG_HASH) wrong[idx++] = '#';
- if (wrong_flags & FMT_FLAG_ZERO) wrong[idx++] = '0';
- if (wrong_flags & FMT_FLAG_MINUS) wrong[idx++] = '-';
- if (wrong_flags & FMT_FLAG_SPACE) wrong[idx++] = ' ';
- if (wrong_flags & FMT_FLAG_PLUS) wrong[idx++] = '+';
- if (wrong_flags & FMT_FLAG_TICK) wrong[idx++] = '\'';
- wrong[idx] = '\0';
+ char wrong[8];
+ char *p = wrong;
+ if (wrong_flags & FMT_FLAG_HASH) *p++ = '#';
+ if (wrong_flags & FMT_FLAG_ZERO) *p++ = '0';
+ if (wrong_flags & FMT_FLAG_MINUS) *p++ = '-';
+ if (wrong_flags & FMT_FLAG_SPACE) *p++ = ' ';
+ if (wrong_flags & FMT_FLAG_PLUS) *p++ = '+';
+ if (wrong_flags & FMT_FLAG_TICK) *p++ = '\'';
+ *p = '\0';
warningf(pos, "invalid format flags \"%s\" in conversion specification %%%c at position %u", wrong, fmt, num_fmt);
}
arg = arg->next;
}
if (!atend(&vchar)) {
- warningf(pos, "format string contains NUL");
+ warningf(pos, "format string contains '\\0'");
}
if (arg != NULL) {
unsigned num_args = num_fmt;
++num_args;
arg = arg->next;
}
- warningf(pos, "%u argument%s but only %u format string%s",
+ warningf(pos, "%u argument%s but only %u format specifier%s",
num_args, num_args != 1 ? "s" : "",
num_fmt, num_fmt != 1 ? "s" : "");
}
{
/* find format arg */
unsigned idx = 0;
- for (; idx < spec->fmt_idx; ++idx)
+ for (; idx < spec->fmt_idx; ++idx) {
+ if (arg == NULL)
+ return;
arg = arg->next;
+ }
const expression_t *fmt_expr = arg->expression;
if (fmt_expr->kind == EXPR_UNARY_CAST_IMPLICIT) {
return;
}
/* find the real args */
- for (; idx < spec->arg_idx; ++idx)
+ for (; idx < spec->arg_idx && arg != NULL; ++idx)
arg = arg->next;
const source_position_t *pos = &fmt_expr->base.source_position;
}
type_t *expected_type;
- type_qualifiers_t expected_qual = TYPE_QUALIFIER_NONE;
switch (fmt) {
case 'd':
case 'i':
warn_invalid_length_modifier(pos, fmt_mod, fmt);
goto next_arg;
}
- expected_type = type_wchar_t_ptr;
- expected_qual = TYPE_QUALIFIER_CONST;
+ expected_type = type_wchar_t;
break;
case 's':
+ case '[':
switch (fmt_mod) {
- case FMT_MOD_NONE: expected_type = type_char_ptr; break;
- case FMT_MOD_l: expected_type = type_wchar_t_ptr; break;
- case FMT_MOD_w: expected_type = type_wchar_t_ptr; break;
+ case FMT_MOD_NONE: expected_type = type_char; break;
+ case FMT_MOD_l: expected_type = type_wchar_t; break;
+ case FMT_MOD_w: expected_type = type_wchar_t; break;
default:
warn_invalid_length_modifier(pos, fmt_mod, fmt);
goto next_arg;
}
- expected_qual = TYPE_QUALIFIER_CONST;
break;
case 'p':
default:
warningf(pos, "encountered unknown conversion specifier '%%%C' at position %u", (wint_t)fmt, num_fmt);
+ if (arg == NULL) {
+ warningf(pos, "too few arguments for format string");
+ return;
+ }
goto next_arg;
}
goto next_arg;
}
- if (is_type_pointer(expected_type_skip)) {
- if (is_type_pointer(ptr_skip)) {
- type_t *const exp_to = skip_typeref(expected_type_skip->pointer.points_to);
- type_t *const arg_to = skip_typeref(ptr_skip->pointer.points_to);
- if ((arg_to->base.qualifiers & ~expected_qual) == 0 &&
- get_unqualified_type(arg_to) == exp_to) {
- goto next_arg;
- }
- }
- } else {
- if (get_unqualified_type(ptr_skip) == expected_type_skip) {
+ /* do NOT allow const or restrict, all other should be ok */
+ if (ptr_skip->base.qualifiers & (TYPE_QUALIFIER_CONST | TYPE_QUALIFIER_VOLATILE))
+ goto error_arg_type;
+ type_t *const unqual_ptr = get_unqualified_type(ptr_skip);
+ if (unqual_ptr == expected_type_skip) {
+ goto next_arg;
+ } else if (expected_type_skip == type_char) {
+ /* char matches with unsigned char AND signed char */
+ if (unqual_ptr == type_signed_char || unqual_ptr == type_unsigned_char)
goto next_arg;
- }
}
error_arg_type:
if (is_type_valid(arg_skip)) {
arg = arg->next;
}
if (!atend(&vchar)) {
- warningf(pos, "format string contains NUL");
+ warningf(pos, "format string contains '\\0'");
}
if (arg != NULL) {
unsigned num_args = num_fmt;
++num_args;
arg = arg->next;
}
- warningf(pos, "%u argument%s but only %u format string%s",
+ warningf(pos, "%u argument%s but only %u format specifier%s",
num_args, num_args != 1 ? "s" : "",
num_fmt, num_fmt != 1 ? "s" : "");
}
case FORMAT_SCANF:
check_scanf_format(arg, &builtin_table[i]);
break;
+ case FORMAT_STRFTIME:
+ case FORMAT_STRFMON:
+ /* TODO: implement other cases */
+ break;
}
break;
}