On Wed, Apr 03, 2019 at 04:35:49PM +0100, Ben Dooks wrote: > The variadic argumnet code did not check any of the variadic arguments > as it did not previously know the possible type. Now we have the possible > formatting information stored in the ctype, we can do some checks on the > printf formatting types. ... > diff --git a/evaluate.c b/evaluate.c > index d9cd41d..d6e8415 100644 > --- a/evaluate.c > +++ b/evaluate.c > @@ -2319,6 +2319,420 @@ static struct symbol *evaluate_alignof(struct expression *expr) > return size_t_ctype; > } > > +struct format_type; This line can be removed. > +struct format_type { > + const char *format; > + int (*test)(struct format_type *fmt, struct expression **expr, struct symbol *ctype, struct symbol **target, const char **typediff); > + void *data; The only use of this field is for a struct symbol *. Better to change its type and even rename it to 'type' (and *if* some other data type will be needed for some extension, a type will most probably also be needed). > +static struct format_type *parse_printf_get_fmt(const char *msg, const char **msgout) > +{ > + struct format_type *type = &ret; > + const char *ptr = msg; > + int szmod=0; > + > + type->test = NULL; > + *msgout = ptr; > + > + if (*ptr == 's') { > + ptr++; > + type->test = printf_fmt_string; > + } else if (*ptr == 'c') { > + ptr++; > + type->test = printf_fmt_numtype; > + type->data = &char_ctype; > + } else if (*ptr == 'p') { > + ptr++; > + type->test = printf_fmt_print_pointer; > + //todo - check if there's anything after these? > + if (*ptr == 'x' || *ptr == 'X') { > + ptr++; > + } else if (isalpha(*ptr)) { > + // probably sxomething that /is/ being de-referenced > + ptr++; > + type->test = printf_fmt_pointer; > + } OK. > + } else { > + if (*ptr == 'l') { > + szmod++; > + ptr++; > + if (*ptr == 'l') { > + szmod++; > + ptr++; > + } > + } else { > + if (*ptr == 'h') { // short/char to int > + szmod = -1; > + ptr++; > + if (*ptr == 'h') // promotion from char > + ptr++; > + } > + if (*ptr == 't') { // ptrdiff_t > + szmod = 2; > + ptr++; > + } > + if (*ptr == 'j') { // intmax_t > + szmod = 1; This won't be OK on 32-bit (where intmax_t is long long) but Sparse will need to know about intmax_ctype. Maybe, for now, just add a comment about it? > + if (*ptr == 'x' || *ptr == 'X' || *ptr == 'u' || *ptr == 'o') { > + ptr++; > + type->test = printf_fmt_numtype; > + switch (szmod) { > + case -1: > + type->data = &ushort_ctype; > + break; > + case 0: > + type->data = &uint_ctype; > + break; > + case 1: > + type->data = &ulong_ctype; > + break; > + case 2: > + type->data = &ullong_ctype; > + break; > + default: > + type->test = NULL; > + } > + } else if (*ptr == 'i' || *ptr == 'd') { > + ptr++; > + type->test = printf_fmt_numtype; > + switch (szmod) { > + case -1: > + type->data = &short_ctype; > + break; > + case 0: > + type->data = &int_ctype; > + break; > + case 1: > + type->data = &long_ctype; > + break; > + case 2: > + type->data = &llong_ctype; > + break; > + default: > + type->test = NULL; > + } > + } else if (*ptr == 'f' || *ptr == 'g' || *ptr == 'F' || *ptr == 'G') { > + type->test = printf_fmt_numtype; > + type->data = &double_ctype; > + ptr++; > + } else if (*ptr == 'L') { > + type->test = printf_fmt_numtype; > + type->data = &ldouble_ctype; This should be combined with the f/g/F/G just above, since 'L' is a size specifier. The remaining looks good but I'll need a bit more time to look closer at it. -- Luc