This checking is currently done by check_assignment_types() for all numeric types but this is not adequate because we want to have a better control over what is allowed or not So, add a custom checking function: *) checking if the argument is one of the integer types. *) currently accepting bitwise types too *) easily extended to handle -Wformat-signedness Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- verify-format.c | 74 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/verify-format.c b/verify-format.c index 6bcbfdfef1b4..fdfe9c22e858 100644 --- a/verify-format.c +++ b/verify-format.c @@ -98,12 +98,76 @@ static inline int type_class(struct symbol *type, struct symbol **base) return CLASS_OTHER; } -static int printf_fmt_numtype(struct format_type *fmt, +static struct symbol *normalize_sint(struct symbol *s) +{ + if (s == &sint_ctype) + return &int_ctype; + if (s == &slong_ctype) + return &long_ctype; + if (s == &sllong_ctype) + return &llong_ctype; + if (s == &sint128_ctype) + return &int128_ctype; + return s; +} + +static struct symbol *normalize_uint(struct symbol *s) +{ + if (s == &uint_ctype) + return &int_ctype; + if (s == &ulong_ctype) + return &long_ctype; + if (s == &ullong_ctype) + return &llong_ctype; + if (s == &uint128_ctype) + return &int128_ctype; + return s; +} + +static const char *check_printf_int(struct format_type *fmt, struct symbol *source, int sign) +{ + const char *typediff = "different base types"; + struct symbol *target = fmt->type; + int class = type_class(source, &source); + + if (class == CLASS_BITWISE) + class = type_class(source->ctype.base_type, &source); + if (class != CLASS_INT) + return typediff; + + // For now, ignore the signedness + target = normalize_uint(target); + source = normalize_uint(source); + source = normalize_sint(source); + if (source == target) + return NULL; + return typediff; +} + +static const char *check_printf_sint(struct format_type *fmt, struct symbol *source) +{ + return check_printf_int(fmt, source, 1); +} + +static int printf_fmt_sint(struct format_type *fmt, + struct expression **expr, + struct symbol *ctype, + const char **typediff) +{ + return !(*typediff = check_printf_sint(fmt, ctype)); +} + +static const char *check_printf_uint(struct format_type *fmt, struct symbol *source) +{ + return check_printf_int(fmt, source, 0); +} + +static int printf_fmt_uint(struct format_type *fmt, struct expression **expr, struct symbol *ctype, const char **typediff) { - return check_assignment_types(fmt->type, expr, typediff); + return !(*typediff = check_printf_uint(fmt, ctype)); } static const char *check_printf_float(struct format_type *fmt, struct symbol *source) @@ -274,7 +338,7 @@ static struct format_type *parse_printf_get_fmt(struct format_type *type, switch (*ptr++) { case 'd': case 'i': - type->test = printf_fmt_numtype; + type->test = printf_fmt_sint; switch (szmod) { case LEN_hh: case LEN_h: @@ -302,7 +366,7 @@ static struct format_type *parse_printf_get_fmt(struct format_type *type, } break; case 'u': case 'o': case 'x': case 'X': - type->test = printf_fmt_numtype; + type->test = printf_fmt_uint; switch (szmod) { case LEN_hh: case LEN_h: @@ -344,7 +408,7 @@ static struct format_type *parse_printf_get_fmt(struct format_type *type, } break; case 'c': - type->test = printf_fmt_numtype; + type->test = printf_fmt_sint; // FIXME: need its own check? switch (szmod) { case LEN_none: type->type = &int_ctype; -- 2.28.0