From 7c766ef9bd9dd35c011ad583351909d744222985 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:01:14 +0100 Subject: [PATCH] Refine type detection in terminal write The code no longer accepts valid mantissa-only doubles that are integer rejects, eg, 078 or ULL overflows. These are most likely input errors by the user: 8 is not an octal digit, they might have typed 17 hex digits, not 16. It's just too hard to explain that 0xffffFFFFffffFFFFf writes 0x4430000000000000, which is the correct double representation of the valid 17-digit hex mantissa that strtod() is perfectly happy to accept. --- src/term.c | 55 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/term.c b/src/term.c index 865a413c..1f5ec4b4 100644 --- a/src/term.c +++ b/src/term.c @@ -531,6 +531,30 @@ static void change_endian(void *p, int size) { } +// Looks like a double mantissa in hex or dec notation +static int is_mantissa_only(char *p) { + char *digs; + + if(*p == '+' || *p == '-') + p++; + + if(*p == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + digs = "0123456789abcdefABCDEF"; + } else + digs = "0123456789"; + + if(!*p) + return 0; + + while(*p) + if(!strchr(digs, *p++)) + return 0; + + return 1; +} + + static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { @@ -741,18 +765,20 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } + if(!data.size) { // Try double now that input was rejected as integer + data.d = strtod(argi, &end_ptr); + // Do not accept valid doubles that are integer rejects (eg, 078 or ULL overflows) + if (end_ptr != argi && *end_ptr == 0) + if (!is_mantissa_only(argi)) + data.size = 8; + } + if(!data.size) { // Try float data.f = strtof(argi, &end_ptr); if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) data.size = 4; } - if(!data.size) { // Try double - data.d = strtod(argi, &end_ptr); - if (end_ptr != argi && *end_ptr == 0) - data.size = 8; - } - if(!data.size) { // Try C-style string or single character if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); @@ -774,16 +800,17 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } else { // C-style string data.str_ptr = s; } - } else { - avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", - progname, argi); - free(buf); - if(data.str_ptr != NULL) - free(data.str_ptr); - return -1; } } - // ensure we have little endian representation in data.a + + if(!data.size && !data.str_ptr) { + avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", + progname, argi); + free(buf); + return -1; + } + + // Assume endianness is the same for double and int, and ensure little endian representation if(is_big_endian && data.size > 1) change_endian(data.a, data.size); }