{
/* 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;
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 (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 (ptr_skip == type_signed_char || ptr_skip == type_unsigned_char)
+ if (unqual_ptr == type_signed_char || unqual_ptr == type_unsigned_char)
goto next_arg;
}
error_arg_type:
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;
}