From 22c4dbf23e89e16491b76dceadfc443eca1c56bc Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 9 Aug 2022 21:20:44 +0100 Subject: [PATCH] Harden string processing during parsing in lexer.l, config_gram.y and otherwise - Replace strdup(s) with cfg_strdup(funname, s) that exits on out of mem - Replace malloc(n) with cfg_malloc(funname, n) that exits on out of mem - Change multiline string scanning in lexer.l to avoid core dump - Remove global variables string_buf and string_bug_ptr - Ensure reading strings unescapes strings C-Style - Ensure writing strings escapes strings C-Style again Commit looks longer than needed as unescape() and auxiliary functions needed to be moved from term.c (not in libavrdude) to config.c (in libavrdude). --- src/avr.c | 2 +- src/avrpart.c | 6 +- src/config.c | 338 ++++++++++++++++++++++++++--------- src/config.h | 29 ++- src/config_gram.y | 18 +- src/developer_opts.c | 51 +++--- src/developer_opts_private.h | 15 +- src/lexer.l | 28 ++- src/libavrdude.h | 12 +- src/main.c | 5 +- src/pgm.c | 24 +-- src/pindefs.c | 4 +- src/term.c | 175 +----------------- src/update.c | 50 ++---- 14 files changed, 355 insertions(+), 402 deletions(-) diff --git a/src/avr.c b/src/avr.c index eea0ad8a..62760ce7 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1243,7 +1243,7 @@ void avr_add_mem_order(const char *str) { if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str)) return; if(!avr_mem_order[i]) { - avr_mem_order[i] = strdup(str); + avr_mem_order[i] = cfg_strdup("avr_mem_order()", str); return; } } diff --git a/src/avrpart.c b/src/avrpart.c index c4a2bd8b..40baa449 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -956,7 +956,7 @@ char *cmdbitstr(CMDBIT cb) { else space[1] = 0; - return strdup(space); + return cfg_strdup("cmdbitstr()", space); } @@ -998,7 +998,7 @@ char *opcode2str(OPCODE *op, int opnum, int detailed) { int compact = 1; if(!op) - return strdup("NULL"); + return cfg_strdup("opcode2str()", "NULL"); // Can the opcode be printed in a compact way? Only if address bits are systematic. for(int i=31; i >= 0; i--) @@ -1033,7 +1033,7 @@ char *opcode2str(OPCODE *op, int opnum, int detailed) { *sp++ = '"'; *sp = 0; - return strdup(space); + return cfg_strdup("opcode2str()", space); } diff --git a/src/config.c b/src/config.c index 34745daf..8d99848d 100644 --- a/src/config.c +++ b/src/config.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "avrdude.h" #include "libavrdude.h" @@ -38,9 +39,6 @@ char default_serial[PATH_MAX]; char default_spi[PATH_MAX]; double default_bitclock; -char string_buf[MAX_STR_CONST]; -char *string_buf_ptr; - LISTID string_list; LISTID number_list; PROGRAMMER * current_prog; @@ -82,6 +80,25 @@ int init_config(void) return 0; } +void *cfg_malloc(const char *funcname, size_t n) { + void *ret = malloc(n); + if(!ret) { + avrdude_message(MSG_INFO, "%s: out of memory in %s\n", progname, funcname); + exit(1); + } + memset(ret, 0, n); + return ret; +} + + +char *cfg_strdup(const char *funcname, const char *s) { + char *ret = strdup(s); + if(!ret) { + avrdude_message(MSG_INFO, "%s: out of memory in %s\n", progname, funcname); + exit(1); + } + return ret; +} int yywrap() @@ -124,20 +141,9 @@ int yywarning(char * errmsg, ...) } -TOKEN * new_token(int primary) -{ - TOKEN * tkn; - - tkn = (TOKEN *)malloc(sizeof(TOKEN)); - if (tkn == NULL) { - yyerror("new_token(): out of memory"); - return NULL; - } - - memset(tkn, 0, sizeof(TOKEN)); - +TOKEN * new_token(int primary) { + TOKEN * tkn = (TOKEN *) cfg_malloc("new_token()", sizeof(TOKEN)); tkn->primary = primary; - return tkn; } @@ -173,14 +179,8 @@ void free_tokens(int n, ...) -TOKEN * number(char * text) -{ - struct token_t * tkn; - - tkn = new_token(TKN_NUMBER); - if (tkn == NULL) { - return NULL; /* yyerror already called */ - } +TOKEN *number(const char *text) { + struct token_t *tkn = new_token(TKN_NUMBER); tkn->value.type = V_NUM; tkn->value.number = atoi(text); @@ -191,11 +191,8 @@ TOKEN * number(char * text) return tkn; } -TOKEN * number_real(char * text) -{ - struct token_t * tkn; - - tkn = new_token(TKN_NUMBER); +TOKEN *number_real(const char *text) { + struct token_t * tkn = new_token(TKN_NUMBER); tkn->value.type = V_NUM_REAL; tkn->value.number_real = atof(text); @@ -206,15 +203,10 @@ TOKEN * number_real(char * text) return tkn; } -TOKEN * hexnumber(char * text) -{ - struct token_t * tkn; +TOKEN *hexnumber(const char *text) { + struct token_t *tkn = new_token(TKN_NUMBER); char * e; - tkn = new_token(TKN_NUMBER); - if (tkn == NULL) { - return NULL; /* yyerror already called */ - } tkn->value.type = V_NUM; tkn->value.number = strtoul(text, &e, 16); if ((e == text) || (*e != 0)) { @@ -231,26 +223,10 @@ TOKEN * hexnumber(char * text) } -TOKEN * string(char * text) -{ - struct token_t * tkn; - int len; - - tkn = new_token(TKN_STRING); - if (tkn == NULL) { - return NULL; /* yyerror already called */ - } - - len = strlen(text); - +TOKEN *string(const char *text) { + struct token_t *tkn = new_token(TKN_STRING); tkn->value.type = V_STR; - tkn->value.string = (char *) malloc(len+1); - if (tkn->value.string == NULL) { - yyerror("string(): out of memory"); - free_token(tkn); - return NULL; - } - strcpy(tkn->value.string, text); + tkn->value.string = cfg_strdup("string()", text); #if DEBUG avrdude_message(MSG_INFO, "STRING(%s)\n", tkn->value.string); @@ -260,13 +236,8 @@ TOKEN * string(char * text) } -TOKEN * keyword(int primary) -{ - struct token_t * tkn; - - tkn = new_token(primary); - - return tkn; +TOKEN * keyword(int primary) { + return new_token(primary); } @@ -306,19 +277,6 @@ void pyytext(void) } -char * dup_string(const char * str) -{ - char * s; - - s = strdup(str); - if (s == NULL) { - yyerror("dup_string(): out of memory"); - return NULL; - } - - return s; -} - #ifdef HAVE_YYLEX_DESTROY /* reset lexer and free any allocated memory */ extern int yylex_destroy(void); @@ -386,11 +344,7 @@ const char *cache_string(const char *file) { } } - fnames[n] = strdup(file); - if(!fnames[n]) { - yyerror("cache_string(): out of memory"); - return NULL; - } + fnames[n] = cfg_strdup("cache_string()", file); return fnames[n++]; } @@ -399,3 +353,227 @@ const char *cache_string(const char *file) { int capture_comment_char(int c) { return c; } + + +// Convert the next n hex digits of s to a hex number +static unsigned int tohex(const unsigned char *s, unsigned int n) { + int ret, c; + + ret = 0; + while(n--) { + ret *= 16; + c = *s++; + ret += c >= '0' && c <= '9'? c - '0': c >= 'a' && c <= 'f'? c - 'a' + 10: c - 'A' + 10; + } + + return ret; +} + +/* + * Create a utf-8 character sequence from a single unicode character. + * Permissive for some invalid unicode sequences but not for those with + * high bit set). Returns numbers of characters written (0-6). + */ +static int wc_to_utf8str(unsigned int wc, unsigned char *str) { + if(!(wc & ~0x7fu)) { + *str = (char) wc; + return 1; + } + if(!(wc & ~0x7ffu)) { + *str++ = (char) ((wc >> 6) | 0xc0); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 2; + } + if(!(wc & ~0xffffu)) { + *str++ = (char) ((wc >> 12) | 0xe0); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 3; + } + if(!(wc & ~0x1fffffu)) { + *str++ = (char) ((wc >> 18) | 0xf0); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 4; + } + if(!(wc & ~0x3ffffffu)) { + *str++ = (char) ((wc >> 24) | 0xf8); + *str++ = (char) (((wc >> 18) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 5; + } + if(!(wc & ~0x7fffffffu)) { + *str++ = (char) ((wc >> 30) | 0xfc); + *str++ = (char) (((wc >> 24) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 18) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 6; + } + return 0; +} + +// Unescape C-style strings, destination d must hold enough space (and can be source s) +unsigned char *cfg_unescapeu(unsigned char *d, const unsigned char *s) { + unsigned char *ret = d; + int n, k; + + while(*s) { + switch (*s) { + case '\\': + switch (*++s) { + case 'n': + *d = '\n'; + break; + case 't': + *d = '\t'; + break; + case 'a': + *d = '\a'; + break; + case 'b': + *d = '\b'; + break; + case 'e': // Non-standard ESC + *d = 27; + break; + case 'f': + *d = '\f'; + break; + case 'r': + *d = '\r'; + break; + case 'v': + *d = '\v'; + break; + case '?': + *d = '?'; + break; + case '`': + *d = '`'; + break; + case '"': + *d = '"'; + break; + case '\'': + *d = '\''; + break; + case '\\': + *d = '\\'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': // 1-3 octal digits + n = *s - '0'; + for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // Max 2 more octal characters + n *= 8, n += s[1] - '0', s++; + *d = n; + break; + case 'x': // Unlimited hex digits + for(k = 0; isxdigit(s[k + 1]); k++) + continue; + if(k > 0) { + *d = tohex(s + 1, k); + s += k; + } else { // No hex digits after \x? copy \x + *d++ = '\\'; + *d = 'x'; + } + break; + case 'u': // Exactly 4 hex digits and valid unicode + if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && + (n = wc_to_utf8str(tohex(s+1, 4), d))) { + d += n - 1; + s += 4; + } else { // Invalid \u sequence? copy \u + *d++ = '\\'; + *d = 'u'; + } + break; + case 'U': // Exactly 6 hex digits and valid unicode + if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) && isxdigit(s[6]) && + (n = wc_to_utf8str(tohex(s+1, 6), d))) { + d += n - 1; + s += 6; + } else { // Invalid \U sequence? copy \U + *d++ = '\\'; + *d = 'U'; + } + break; + default: // Keep the escape sequence (C would warn and remove \) + *d++ = '\\'; + *d = *s; + } + break; + + default: // Not an escape sequence: just copy the character + *d = *s; + } + d++; + s++; + } + *d = *s; // Terminate + + return ret; +} + +// Unescape C-style strings, destination d must hold enough space (and can be source s) +char *cfg_unescape(char *d, const char *s) { + return (char *) cfg_unescapeu((unsigned char *) d, (const unsigned char *) s); +} + +// Return an escaped string that looks like a C-style input string incl quotes, memory is malloc()ed +char *cfg_escape(const char *s) { + char *ret = (char *) cfg_malloc("cfg_escape()", 4*strlen(s)+2+3), *d = ret; + + *d++ = '"'; + for(; *s; s++) { + switch(*s) { + case '\n': + *d++ = '\\'; *d++ = 'n'; + break; + case '\t': + *d++ = '\\'; *d++ = 't'; + break; + case '\a': + *d++ = '\\'; *d++ = 'a'; + break; + case '\b': + *d++ = '\\'; *d++ = 'b'; + break; + case '\f': + *d++ = '\\'; *d++ = 'f'; + break; +#if '\r' != '\n' + case '\r': + *d++ = '\\'; *d++ = 'r'; + break; +#endif + case '\v': + *d++ = '\\'; *d++ = 'v'; + break; + case '\"': + *d++ = '\\'; *d++ = '\"'; + break; + default: + if(*s == 0x7f || (*s >= 0 && *s < 32)) { + sprintf(d, "\\%03o", *s); + d += strlen(d); + } else + *d++ = *s; + } + } + *d++ = '"'; + *d = 0; + + return ret; +} diff --git a/src/config.h b/src/config.h index 1ebd2f70..260d404a 100644 --- a/src/config.h +++ b/src/config.h @@ -35,11 +35,11 @@ enum { V_NONE, V_NUM, V_NUM_REAL, V_STR }; typedef struct value_t { int type; - /*union { TODO: use an anonymous union here ? */ + union { int number; double number_real; char * string; - /*};*/ + }; } VALUE; @@ -66,41 +66,36 @@ extern bool is_alias; // current entry is alias #endif extern YYSTYPE yylval; -extern char string_buf[MAX_STR_CONST]; -extern char *string_buf_ptr; - #ifdef __cplusplus extern "C" { #endif int yyparse(void); -int yyerror(char * errmsg, ...); +int yyerror(char *errmsg, ...); -int yywarning(char * errmsg, ...); +int yywarning(char *errmsg, ...); -TOKEN * new_token(int primary); +TOKEN *new_token(int primary); -void free_token(TOKEN * tkn); +void free_token(TOKEN *tkn); void free_tokens(int n, ...); -TOKEN * number(char * text); +TOKEN *number(const char *text); -TOKEN * number_real(char * text); +TOKEN *number_real(const char *text); -TOKEN * hexnumber(char * text); +TOKEN *hexnumber(const char *text); -TOKEN * string(char * text); +TOKEN *string(const char *text); -TOKEN * keyword(int primary); +TOKEN *keyword(int primary); -void print_token(TOKEN * tkn); +void print_token(TOKEN *tkn); void pyytext(void); -char * dup_string(const char * str); - int capture_comment_char(int c); #ifdef __cplusplus diff --git a/src/config_gram.y b/src/config_gram.y index c3554dcc..0b9cf6cd 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -453,25 +453,11 @@ prog_parms : prog_parm : K_ID TKN_EQUAL string_list { { - TOKEN * t; - char *s; - int do_yyabort = 0; while (lsize(string_list)) { - t = lrmv_n(string_list, 1); - if (!do_yyabort) { - s = dup_string(t->value.string); - if (s == NULL) { - do_yyabort = 1; - } else { - ladd(current_prog->id, s); - } - } - /* if do_yyabort == 1 just make the list empty */ + TOKEN *t = lrmv_n(string_list, 1); + ladd(current_prog->id, cfg_strdup("config_gram.y", t->value.string)); free_token(t); } - if (do_yyabort) { - YYABORT; - } } } | prog_parm_type diff --git a/src/developer_opts.c b/src/developer_opts.c index b4f69753..6cbfa4f2 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -187,20 +187,17 @@ static char *dev_sprintf(const char *fmt, ...) { va_end(ap); if(size < 0) - return NULL; + return cfg_strdup("dev_sprintf()", ""); - size++; // For temrinating '\0' - if(!(p = malloc(size))) - return NULL; + size++; // For terminating '\0' + p = cfg_malloc("dev_sprintf()", size); va_start(ap, fmt); size = vsnprintf(p, size, fmt, ap); va_end(ap); - if(size < 0) { - free(p); - return NULL; - } + if(size < 0) + *p = 0; return p; } @@ -438,9 +435,10 @@ static void dev_part_raw(AVRPART *part) { static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { + char *descstr = cfg_escape(p->desc); if(!tsv) { dev_info("#------------------------------------------------------------\n"); - dev_info("# %s\n", p->desc); + dev_info("# %.*s\n", strlen(descstr+1)-1, descstr+1); dev_info("#------------------------------------------------------------\n"); if(p->parent_id && *p->parent_id) dev_info("\npart parent \"%s\"\n", p->parent_id); @@ -448,9 +446,9 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { dev_info("\npart\n"); } - _if_partout(strcmp, "\"%s\"", desc); - _if_partout(strcmp, "\"%s\"", id); - _if_partout(strcmp, "\"%s\"", family_id); + _if_partout_str(strcmp, descstr, desc); + _if_partout_str(strcmp, cfg_escape(p->id), id); + _if_partout_str(strcmp, cfg_escape(p->family_id), family_id); _if_partout(intcmp, "%d", hvupdi_variant); _if_partout(intcmp, "0x%02x", stk500_devcode); _if_partout(intcmp, "0x%02x", avr910_devcode); @@ -461,9 +459,13 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { _if_partout(intcmp, "0x%04x", usbpid); if(!base || base->reset_disposition != p->reset_disposition) - _partout_str(strdup(p->reset_disposition == RESET_DEDICATED? "dedicated": p->reset_disposition == RESET_IO? "io": "unknown"), reset); + _partout_str(cfg_strdup("dev_part_strct()", + p->reset_disposition == RESET_DEDICATED? "dedicated": p->reset_disposition == RESET_IO? "io": "unknown"), + reset); - _if_partout_str(intcmp, strdup(p->retry_pulse == PIN_AVR_RESET? "reset": p->retry_pulse == PIN_AVR_SCK? "sck": "unknown"), retry_pulse); + _if_partout_str(intcmp, cfg_strdup("dev_part_strct()", + p->retry_pulse == PIN_AVR_RESET? "reset": p->retry_pulse == PIN_AVR_SCK? "sck": "unknown"), + retry_pulse); if(!base || base->flags != p->flags) { if(tsv) { @@ -482,7 +484,9 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { if(!base || (base->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL)) != (p->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL))) { int par = p->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL); - _partout_str(strdup(par == 0? "no": par == AVRPART_PSEUDOPARALLEL? "unknown": AVRPART_PARALLELOK? "yes": "pseudo"), parallel); + _partout_str(cfg_strdup("dev_part_strct()", + par == 0? "no": par == AVRPART_PSEUDOPARALLEL? "unknown": AVRPART_PARALLELOK? "yes": "pseudo"), + parallel); } } } @@ -984,13 +988,16 @@ static void dev_pgm_strct(PROGRAMMER *pgm, bool tsv, PROGRAMMER *base) { if(!firstid) dev_info(", "); firstid = 0; - dev_info("\"%s\"", ldata(ln)); + char *str = cfg_escape(ldata(ln)); + dev_info("%s", str); + free(str); } dev_info(tsv? "\n": ";\n"); - _if_pgmout(strcmp, "\"%s\"", desc); + _if_pgmout_str(strcmp, cfg_escape(pgm->desc), desc); _pgmout_fmt("type", "\"%s\"", locate_programmer_type_id(pgm->initpgm)); - _pgmout_fmt("connection_type", "%s", connstr(pgm->conntype)); + if(!base || base->conntype != pgm->conntype) + _pgmout_fmt("connection_type", "%s", connstr(pgm->conntype)); _if_pgmout(intcmp, "%d", baudrate); _if_pgmout(intcmp, "0x%04x", usbvid); @@ -1009,10 +1016,10 @@ static void dev_pgm_strct(PROGRAMMER *pgm, bool tsv, PROGRAMMER *base) { dev_info(tsv? "\n": ";\n"); } - _if_pgmout(strcmp, "\"%s\"", usbdev); - _if_pgmout(strcmp, "\"%s\"", usbsn); - _if_pgmout(strcmp, "\"%s\"", usbvendor); - _if_pgmout(strcmp, "\"%s\"", usbproduct); + _if_pgmout_str(strcmp, cfg_escape(pgm->usbdev), usbdev); + _if_pgmout_str(strcmp, cfg_escape(pgm->usbsn), usbsn); + _if_pgmout_str(strcmp, cfg_escape(pgm->usbvendor), usbvendor); + _if_pgmout_str(strcmp, cfg_escape(pgm->usbproduct), usbproduct); for(int i=0; ipin+i); diff --git a/src/developer_opts_private.h b/src/developer_opts_private.h index e6be1ee9..a5c1562e 100644 --- a/src/developer_opts_private.h +++ b/src/developer_opts_private.h @@ -62,6 +62,7 @@ static int dev_message(int msglvl, const char *fmt, ...); dev_part_strct_entry(tsv, ".prog", id, NULL, #component, dev_sprintf(fmt, pgm->component)); \ } while(0) +// Result must be a malloc()ed string #define _if_pgmout_str(cmp, result, component) do { \ if(!base || cmp(base->component, pgm->component)) \ dev_part_strct_entry(tsv, ".prog", id, NULL, #component, result); \ @@ -80,14 +81,17 @@ static int dev_message(int msglvl, const char *fmt, ...); dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)); \ } while(0) +// Result must be a malloc()ed string #define _partout_str(result, component) \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result) +// Result must be a malloc()ed string #define _if_partout_str(cmp, result, component) do { \ if(!base || cmp(base->component, p->component)) \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ } while(0) +// Result must be a malloc()ed string #define _if_n_partout_str(cmp, n, result, component) do { \ if(!base || cmp(base->component, p->component, n)) \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ @@ -102,30 +106,33 @@ static int dev_message(int msglvl, const char *fmt, ...); dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, dev_sprintf(fmt, m->component)); \ } while(0) +// Result must be a malloc()ed string #define _memout_str(result, component) \ dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result) +// Result must be a malloc()ed string #define _if_n_memout_str(cmp, n, result, component) do { \ if(!bm || cmp(bm->component, m->component, n)) \ dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result); \ } while(0) #define _memout_yn(component) \ - dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, strdup(m->component? "yes": "no")) + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, cfg_strdup("_memout_yn()", m->component? "yes": "no")) #define _if_memout_yn(component) do { \ if(!bm || bm->component != m->component) \ - dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, strdup(m->component? "yes": "no")); \ + dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, cfg_strdup("_if_memout_yn()", m->component? "yes": "no")); \ } while(0) #define _flagout(mask, name) \ - _partout_str(strdup(p->flags & (mask)? "yes": "no"), name) + _partout_str(cfg_strdup("_flagout()", p->flags & (mask)? "yes": "no"), name) #define _if_flagout(mask, name) do { \ if(!base || (base->flags & (mask)) != (p->flags & (mask))) \ - _partout_str(strdup(p->flags & (mask)? "yes": "no"), name); \ + _partout_str(cfg_strdup("_if_flagout()", p->flags & (mask)? "yes": "no"), name); \ } while(0) +// Result must be a malloc()ed string #define _cmderr(result, component) \ dev_part_strct_entry(tsv, ".cmderr", p->desc, m->desc, #component, result) diff --git a/src/lexer.l b/src/lexer.l index c55d7853..23fd2277 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -45,7 +45,6 @@ DIGIT [0-9] HEXDIGIT [0-9a-fA-F] SIGN [+-] -%x strng %x incl %x comment %option nounput @@ -61,12 +60,19 @@ SIGN [+-] {SIGN}?{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; } {SIGN}?"."{DIGIT}+ { yylval = number_real(yytext); return TKN_NUMBER_REAL; } -"\"" { string_buf_ptr = string_buf; BEGIN(strng); } +["]([^"\\\n]|\\.|\\\n)*["] { + char *str= cfg_strdup("lexer.l", yytext); + cfg_unescape(str, str+1); + size_t len = strlen(str); + if(len) + str[len-1] = 0; + yylval = string(str); + free(str); + return TKN_STRING; +} 0x{HEXDIGIT}+ { yylval = hexnumber(yytext); return TKN_NUMBER; } - - # { /* The following captures all '#' style comments to end of line */ BEGIN(comment); } [^\n]*\n+ { /* eat comments */ @@ -107,20 +113,6 @@ SIGN [+-] } -\" { *string_buf_ptr = 0; string_buf_ptr = string_buf; - yylval = string(string_buf_ptr); BEGIN(INITIAL); return TKN_STRING; } -\\n *string_buf_ptr++ = '\n'; -\\t *string_buf_ptr++ = '\t'; -\\r *string_buf_ptr++ = '\r'; -\\b *string_buf_ptr++ = '\b'; -\\f *string_buf_ptr++ = '\f'; -\\(.|\n) *(string_buf_ptr++) = yytext[1]; -[^\\\n\"]+ { char *yptr = yytext; while (*yptr) - *(string_buf_ptr++) = *(yptr++); } - -\n { yyerror("unterminated character constant"); - return YYERRCODE; } - alias { yylval=NULL; return K_ALIAS; } allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; } avr910_devcode { yylval=NULL; return K_AVR910_DEVCODE; } diff --git a/src/libavrdude.h b/src/libavrdude.h index fb4a53dd..840d8fc1 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -536,7 +536,7 @@ const char * pins_to_str(const struct pindef_t * const pindef); * This function returns a string of defined pins, eg, ~1, 2, ~4, ~5, 7 or "" * * @param[in] pindef the pin definition for which we want the string representation - * @returns a pointer to a string, which was created by strdup (NULL if out of memory) + * @returns a pointer to a string, which was created by strdup */ char *pins_to_strdup(const struct pindef_t * const pindef); @@ -1006,6 +1006,10 @@ extern double default_bitclock; extern "C" { #endif +void *cfg_malloc(const char *funcname, size_t n); + +char *cfg_strdup(const char *funcname, const char *s); + int init_config(void); void cleanup_config(void); @@ -1014,6 +1018,12 @@ int read_config(const char * file); const char *cache_string(const char *file); +unsigned char *cfg_unescapeu(unsigned char *d, const unsigned char *s); + +char *cfg_unescape(char *d, const char *s); + +char *cfg_escape(const char *s); + #ifdef __cplusplus } #endif diff --git a/src/main.c b/src/main.c index ab10b4fa..b696d6d7 100644 --- a/src/main.c +++ b/src/main.c @@ -922,10 +922,7 @@ int main(int argc, char * argv []) progname, (upd->op == DEVICE_READ)? 'r': (upd->op == DEVICE_WRITE)? 'w': 'v', upd->filename, mtype); - if ((upd->memtype = strdup(mtype)) == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory\n", progname); - exit(1); - } + upd->memtype = cfg_strdup("main()", mtype); } if (!avr_mem_might_be_known(upd->memtype)) { diff --git a/src/pgm.c b/src/pgm.c index 238f61d8..07cbed57 100644 --- a/src/pgm.c +++ b/src/pgm.c @@ -67,14 +67,7 @@ PROGRAMMER * pgm_new(void) PROGRAMMER * pgm; const char *nulp = cache_string(""); - pgm = (PROGRAMMER *)malloc(sizeof(*pgm)); - if (pgm == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n", - progname); - return NULL; - } - - memset(pgm, 0, sizeof(*pgm)); + pgm = (PROGRAMMER *) cfg_malloc("pgm_new()", sizeof(*pgm)); pgm->id = lcreat(NULL, 0); pgm->usbpid = lcreat(NULL, 0); @@ -162,24 +155,13 @@ PROGRAMMER * pgm_dup(const PROGRAMMER * const src) PROGRAMMER * pgm; LNODEID ln; - pgm = (PROGRAMMER *)malloc(sizeof(*pgm)); - if (pgm == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n", - progname); - return NULL; - } - + pgm = (PROGRAMMER *) cfg_malloc("pgm_dup()", sizeof(*pgm)); memcpy(pgm, src, sizeof(*pgm)); pgm->id = lcreat(NULL, 0); pgm->usbpid = lcreat(NULL, 0); for (ln = lfirst(src->usbpid); ln; ln = lnext(ln)) { - int *ip = malloc(sizeof(int)); - if (ip == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n", - progname); - exit(1); - } + int *ip = cfg_malloc("pgm_dup()", sizeof(int)); *ip = *(int *) ldata(ln); ladd(pgm->usbpid, ip); } diff --git a/src/pindefs.c b/src/pindefs.c index 625d1f18..2e78c8df 100644 --- a/src/pindefs.c +++ b/src/pindefs.c @@ -350,7 +350,7 @@ const char * pins_to_str(const struct pindef_t * const pindef) { * This function returns a string of defined pins, eg, ~1, 2, ~4, ~5, 7 or "" * * @param[in] pindef the pin definition for which we want the string representation - * @returns a pointer to a string, which was created by strdup (NULL if out of memory) + * @returns a pointer to a string, which was created by strdup */ char *pins_to_strdup(const struct pindef_t * const pindef) { char buf[6*(PIN_MAX+1)], *p = buf; @@ -365,7 +365,7 @@ char *pins_to_strdup(const struct pindef_t * const pindef) { } } - return strdup(buf); + return cfg_strdup("pins_to_strdup()", buf); } /** diff --git a/src/term.c b/src/term.c index f02f95c5..672a09cd 100644 --- a/src/term.c +++ b/src/term.c @@ -20,7 +20,6 @@ #include "ac_cfg.h" -#include #include #include #include @@ -346,178 +345,6 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } -// Convert the next n hex digits of s to a hex number -static unsigned int tohex(const unsigned char *s, unsigned int n) { - int ret, c; - - ret = 0; - while(n--) { - ret *= 16; - c = *s++; - ret += c >= '0' && c <= '9'? c - '0': c >= 'a' && c <= 'f'? c - 'a' + 10: c - 'A' + 10; - } - - return ret; -} - -/* - * Create a utf-8 character sequence from a single unicode character. - * Permissive for some invalid unicode sequences but not for those with - * high bit set). Returns numbers of characters written (0-6). - */ -static int wc_to_utf8str(unsigned int wc, unsigned char *str) { - if(!(wc & ~0x7fu)) { - *str = (char) wc; - return 1; - } - if(!(wc & ~0x7ffu)) { - *str++ = (char) ((wc >> 6) | 0xc0); - *str++ = (char) ((wc & 0x3f) | 0x80); - return 2; - } - if(!(wc & ~0xffffu)) { - *str++ = (char) ((wc >> 12) | 0xe0); - *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); - *str++ = (char) ((wc & 0x3f) | 0x80); - return 3; - } - if(!(wc & ~0x1fffffu)) { - *str++ = (char) ((wc >> 18) | 0xf0); - *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); - *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); - *str++ = (char) ((wc & 0x3f) | 0x80); - return 4; - } - if(!(wc & ~0x3ffffffu)) { - *str++ = (char) ((wc >> 24) | 0xf8); - *str++ = (char) (((wc >> 18) & 0x3f) | 0x80); - *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); - *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); - *str++ = (char) ((wc & 0x3f) | 0x80); - return 5; - } - if(!(wc & ~0x7fffffffu)) { - *str++ = (char) ((wc >> 30) | 0xfc); - *str++ = (char) (((wc >> 24) & 0x3f) | 0x80); - *str++ = (char) (((wc >> 18) & 0x3f) | 0x80); - *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); - *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); - *str++ = (char) ((wc & 0x3f) | 0x80); - return 6; - } - return 0; -} - -// Unescape C-style strings, destination d must hold enough space (and can be source s) -static unsigned char *unescape(unsigned char *d, const unsigned char *s) { - unsigned char *ret = d; - int n, k; - - while(*s) { - switch (*s) { - case '\\': - switch (*++s) { - case 'n': - *d = '\n'; - break; - case 't': - *d = '\t'; - break; - case 'a': - *d = '\a'; - break; - case 'b': - *d = '\b'; - break; - case 'e': // Non-standard ESC - *d = 27; - break; - case 'f': - *d = '\f'; - break; - case 'r': - *d = '\r'; - break; - case 'v': - *d = '\v'; - break; - case '?': - *d = '?'; - break; - case '`': - *d = '`'; - break; - case '"': - *d = '"'; - break; - case '\'': - *d = '\''; - break; - case '\\': - *d = '\\'; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': // 1-3 octal digits - n = *s - '0'; - for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // Max 2 more octal characters - n *= 8, n += s[1] - '0', s++; - *d = n; - break; - case 'x': // Unlimited hex digits - for(k = 0; isxdigit(s[k + 1]); k++) - continue; - if(k > 0) { - *d = tohex(s + 1, k); - s += k; - } else { // No hex digits after \x? copy \x - *d++ = '\\'; - *d = 'x'; - } - break; - case 'u': // Exactly 4 hex digits and valid unicode - if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && - (n = wc_to_utf8str(tohex(s+1, 4), d))) { - d += n - 1; - s += 4; - } else { // Invalid \u sequence? copy \u - *d++ = '\\'; - *d = 'u'; - } - break; - case 'U': // Exactly 6 hex digits and valid unicode - if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) && isxdigit(s[6]) && - (n = wc_to_utf8str(tohex(s+1, 6), d))) { - d += n - 1; - s += 6; - } else { // Invalid \U sequence? copy \U - *d++ = '\\'; - *d = 'U'; - } - break; - default: // Keep the escape sequence (C would warn and remove \) - *d++ = '\\'; - *d = *s; - } - break; - - default: // Not an escape sequence: just copy the character - *d = *s; - } - d++; - s++; - } - *d = *s; // Terminate - - return ret; -} - - static size_t maxstrlen(int argc, char **argv) { size_t max = 0; @@ -800,7 +627,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Strip start and end quotes, and unescape C string strncpy(s, argi+1, arglen-2); - unescape((unsigned char *) s, (unsigned char *) s); + cfg_unescape(s, s); if (*argi == '\'') { // Single C-style character if(*s && s[1]) terminal_message(MSG_INFO, "%s (write): only using first character of %s\n", diff --git a/src/update.c b/src/update.c index 2aa2579b..972c3847 100644 --- a/src/update.c +++ b/src/update.c @@ -37,11 +37,7 @@ UPDATE * parse_op(char * s) int i; size_t fnlen; - upd = (UPDATE *)malloc(sizeof(UPDATE)); - if (upd == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory\n", progname); - exit(1); - } + upd = (UPDATE *) cfg_malloc("parse_op()", sizeof(UPDATE)); i = 0; p = s; @@ -52,22 +48,12 @@ UPDATE * parse_op(char * s) if (*p != ':') { upd->memtype = NULL; /* default memtype, "flash", or "application" */ upd->op = DEVICE_WRITE; - upd->filename = (char *)malloc(strlen(buf) + 1); - if (upd->filename == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory\n", progname); - exit(1); - } - strcpy(upd->filename, buf); + upd->filename = cfg_strdup("parse_op()", buf); upd->format = FMT_AUTO; return upd; } - upd->memtype = (char *)malloc(strlen(buf)+1); - if (upd->memtype == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory\n", progname); - exit(1); - } - strcpy(upd->memtype, buf); + upd->memtype = cfg_strdup("parse_op()", buf); p++; if (*p == 'r') { @@ -118,10 +104,10 @@ UPDATE * parse_op(char * s) // and to binary for read operations: upd->format = upd->op == DEVICE_READ? FMT_RBIN: FMT_AUTO; fnlen = strlen(cp); - upd->filename = (char *)malloc(fnlen + 1); + upd->filename = (char *) cfg_malloc("parse_op()", fnlen + 1); } else { fnlen = p - cp; - upd->filename = (char *)malloc(fnlen +1); + upd->filename = (char *) cfg_malloc("parse_op()", fnlen +1); c = *++p; if (c && p[1]) /* More than one char - force failure below. */ @@ -147,12 +133,6 @@ UPDATE * parse_op(char * s) } } - if (upd->filename == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory\n", progname); - free(upd->memtype); - free(upd); - return NULL; - } memcpy(upd->filename, cp, fnlen); upd->filename[fnlen] = 0; @@ -163,19 +143,15 @@ UPDATE * dup_update(UPDATE * upd) { UPDATE * u; - u = (UPDATE *)malloc(sizeof(UPDATE)); - if (u == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory\n", progname); - exit(1); - } + u = (UPDATE *) cfg_malloc("dup_update()", sizeof(UPDATE)); memcpy(u, upd, sizeof(UPDATE)); if (upd->memtype != NULL) - u->memtype = strdup(upd->memtype); + u->memtype = cfg_strdup("dup_update()", upd->memtype); else u->memtype = NULL; - u->filename = strdup(upd->filename); + u->filename = cfg_strdup("dup_update()", upd->filename); return u; } @@ -184,14 +160,10 @@ UPDATE * new_update(int op, char * memtype, int filefmt, char * filename) { UPDATE * u; - u = (UPDATE *)malloc(sizeof(UPDATE)); - if (u == NULL) { - avrdude_message(MSG_INFO, "%s: out of memory\n", progname); - exit(1); - } + u = (UPDATE *) cfg_malloc("new_update()", sizeof(UPDATE)); - u->memtype = strdup(memtype); - u->filename = strdup(filename); + u->memtype = cfg_strdup("new_update()", memtype); + u->filename = cfg_strdup("new_update()", filename); u->op = op; u->format = filefmt;