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).
This commit is contained in:
Stefan Rueger 2022-08-09 21:20:44 +01:00
parent 8a717987ec
commit 22c4dbf23e
No known key found for this signature in database
GPG Key ID: B0B4F1FD86B1EC55
14 changed files with 355 additions and 402 deletions

View File

@ -1243,7 +1243,7 @@ void avr_add_mem_order(const char *str) {
if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str)) if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str))
return; return;
if(!avr_mem_order[i]) { if(!avr_mem_order[i]) {
avr_mem_order[i] = strdup(str); avr_mem_order[i] = cfg_strdup("avr_mem_order()", str);
return; return;
} }
} }

View File

@ -956,7 +956,7 @@ char *cmdbitstr(CMDBIT cb) {
else else
space[1] = 0; 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; int compact = 1;
if(!op) 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. // Can the opcode be printed in a compact way? Only if address bits are systematic.
for(int i=31; i >= 0; i--) for(int i=31; i >= 0; i--)
@ -1033,7 +1033,7 @@ char *opcode2str(OPCODE *op, int opnum, int detailed) {
*sp++ = '"'; *sp++ = '"';
*sp = 0; *sp = 0;
return strdup(space); return cfg_strdup("opcode2str()", space);
} }

View File

@ -25,6 +25,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <ctype.h>
#include "avrdude.h" #include "avrdude.h"
#include "libavrdude.h" #include "libavrdude.h"
@ -38,9 +39,6 @@ char default_serial[PATH_MAX];
char default_spi[PATH_MAX]; char default_spi[PATH_MAX];
double default_bitclock; double default_bitclock;
char string_buf[MAX_STR_CONST];
char *string_buf_ptr;
LISTID string_list; LISTID string_list;
LISTID number_list; LISTID number_list;
PROGRAMMER * current_prog; PROGRAMMER * current_prog;
@ -82,6 +80,25 @@ int init_config(void)
return 0; 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() int yywrap()
@ -124,20 +141,9 @@ int yywarning(char * errmsg, ...)
} }
TOKEN * new_token(int primary) TOKEN * new_token(int primary) {
{ TOKEN * tkn = (TOKEN *) cfg_malloc("new_token()", sizeof(TOKEN));
TOKEN * tkn;
tkn = (TOKEN *)malloc(sizeof(TOKEN));
if (tkn == NULL) {
yyerror("new_token(): out of memory");
return NULL;
}
memset(tkn, 0, sizeof(TOKEN));
tkn->primary = primary; tkn->primary = primary;
return tkn; return tkn;
} }
@ -173,14 +179,8 @@ void free_tokens(int n, ...)
TOKEN * number(char * text) TOKEN *number(const char *text) {
{ struct token_t *tkn = new_token(TKN_NUMBER);
struct token_t * tkn;
tkn = new_token(TKN_NUMBER);
if (tkn == NULL) {
return NULL; /* yyerror already called */
}
tkn->value.type = V_NUM; tkn->value.type = V_NUM;
tkn->value.number = atoi(text); tkn->value.number = atoi(text);
@ -191,11 +191,8 @@ TOKEN * number(char * text)
return tkn; return tkn;
} }
TOKEN * number_real(char * text) TOKEN *number_real(const char *text) {
{ struct token_t * tkn = new_token(TKN_NUMBER);
struct token_t * tkn;
tkn = new_token(TKN_NUMBER);
tkn->value.type = V_NUM_REAL; tkn->value.type = V_NUM_REAL;
tkn->value.number_real = atof(text); tkn->value.number_real = atof(text);
@ -206,15 +203,10 @@ TOKEN * number_real(char * text)
return tkn; return tkn;
} }
TOKEN * hexnumber(char * text) TOKEN *hexnumber(const char *text) {
{ struct token_t *tkn = new_token(TKN_NUMBER);
struct token_t * tkn;
char * e; char * e;
tkn = new_token(TKN_NUMBER);
if (tkn == NULL) {
return NULL; /* yyerror already called */
}
tkn->value.type = V_NUM; tkn->value.type = V_NUM;
tkn->value.number = strtoul(text, &e, 16); tkn->value.number = strtoul(text, &e, 16);
if ((e == text) || (*e != 0)) { if ((e == text) || (*e != 0)) {
@ -231,26 +223,10 @@ TOKEN * hexnumber(char * text)
} }
TOKEN * string(char * text) TOKEN *string(const char *text) {
{ struct token_t *tkn = new_token(TKN_STRING);
struct token_t * tkn;
int len;
tkn = new_token(TKN_STRING);
if (tkn == NULL) {
return NULL; /* yyerror already called */
}
len = strlen(text);
tkn->value.type = V_STR; tkn->value.type = V_STR;
tkn->value.string = (char *) malloc(len+1); tkn->value.string = cfg_strdup("string()", text);
if (tkn->value.string == NULL) {
yyerror("string(): out of memory");
free_token(tkn);
return NULL;
}
strcpy(tkn->value.string, text);
#if DEBUG #if DEBUG
avrdude_message(MSG_INFO, "STRING(%s)\n", tkn->value.string); avrdude_message(MSG_INFO, "STRING(%s)\n", tkn->value.string);
@ -260,13 +236,8 @@ TOKEN * string(char * text)
} }
TOKEN * keyword(int primary) TOKEN * keyword(int primary) {
{ return new_token(primary);
struct token_t * tkn;
tkn = new_token(primary);
return tkn;
} }
@ -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 #ifdef HAVE_YYLEX_DESTROY
/* reset lexer and free any allocated memory */ /* reset lexer and free any allocated memory */
extern int yylex_destroy(void); extern int yylex_destroy(void);
@ -386,11 +344,7 @@ const char *cache_string(const char *file) {
} }
} }
fnames[n] = strdup(file); fnames[n] = cfg_strdup("cache_string()", file);
if(!fnames[n]) {
yyerror("cache_string(): out of memory");
return NULL;
}
return fnames[n++]; return fnames[n++];
} }
@ -399,3 +353,227 @@ const char *cache_string(const char *file) {
int capture_comment_char(int c) { int capture_comment_char(int c) {
return 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;
}

View File

@ -35,11 +35,11 @@
enum { V_NONE, V_NUM, V_NUM_REAL, V_STR }; enum { V_NONE, V_NUM, V_NUM_REAL, V_STR };
typedef struct value_t { typedef struct value_t {
int type; int type;
/*union { TODO: use an anonymous union here ? */ union {
int number; int number;
double number_real; double number_real;
char * string; char * string;
/*};*/ };
} VALUE; } VALUE;
@ -66,41 +66,36 @@ extern bool is_alias; // current entry is alias
#endif #endif
extern YYSTYPE yylval; extern YYSTYPE yylval;
extern char string_buf[MAX_STR_CONST];
extern char *string_buf_ptr;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
int yyparse(void); 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, ...); 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); void pyytext(void);
char * dup_string(const char * str);
int capture_comment_char(int c); int capture_comment_char(int c);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -453,25 +453,11 @@ prog_parms :
prog_parm : prog_parm :
K_ID TKN_EQUAL string_list { K_ID TKN_EQUAL string_list {
{ {
TOKEN * t;
char *s;
int do_yyabort = 0;
while (lsize(string_list)) { while (lsize(string_list)) {
t = lrmv_n(string_list, 1); TOKEN *t = lrmv_n(string_list, 1);
if (!do_yyabort) { ladd(current_prog->id, cfg_strdup("config_gram.y", t->value.string));
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 */
free_token(t); free_token(t);
} }
if (do_yyabort) {
YYABORT;
}
} }
} | } |
prog_parm_type prog_parm_type

View File

@ -187,20 +187,17 @@ static char *dev_sprintf(const char *fmt, ...) {
va_end(ap); va_end(ap);
if(size < 0) if(size < 0)
return NULL; return cfg_strdup("dev_sprintf()", "");
size++; // For temrinating '\0' size++; // For terminating '\0'
if(!(p = malloc(size))) p = cfg_malloc("dev_sprintf()", size);
return NULL;
va_start(ap, fmt); va_start(ap, fmt);
size = vsnprintf(p, size, fmt, ap); size = vsnprintf(p, size, fmt, ap);
va_end(ap); va_end(ap);
if(size < 0) { if(size < 0)
free(p); *p = 0;
return NULL;
}
return p; return p;
} }
@ -438,9 +435,10 @@ static void dev_part_raw(AVRPART *part) {
static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) { static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) {
char *descstr = cfg_escape(p->desc);
if(!tsv) { if(!tsv) {
dev_info("#------------------------------------------------------------\n"); dev_info("#------------------------------------------------------------\n");
dev_info("# %s\n", p->desc); dev_info("# %.*s\n", strlen(descstr+1)-1, descstr+1);
dev_info("#------------------------------------------------------------\n"); dev_info("#------------------------------------------------------------\n");
if(p->parent_id && *p->parent_id) if(p->parent_id && *p->parent_id)
dev_info("\npart parent \"%s\"\n", 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"); dev_info("\npart\n");
} }
_if_partout(strcmp, "\"%s\"", desc); _if_partout_str(strcmp, descstr, desc);
_if_partout(strcmp, "\"%s\"", id); _if_partout_str(strcmp, cfg_escape(p->id), id);
_if_partout(strcmp, "\"%s\"", family_id); _if_partout_str(strcmp, cfg_escape(p->family_id), family_id);
_if_partout(intcmp, "%d", hvupdi_variant); _if_partout(intcmp, "%d", hvupdi_variant);
_if_partout(intcmp, "0x%02x", stk500_devcode); _if_partout(intcmp, "0x%02x", stk500_devcode);
_if_partout(intcmp, "0x%02x", avr910_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_partout(intcmp, "0x%04x", usbpid);
if(!base || base->reset_disposition != p->reset_disposition) 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(!base || base->flags != p->flags) {
if(tsv) { 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))) { if(!base || (base->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL)) != (p->flags & (AVRPART_PARALLELOK | AVRPART_PSEUDOPARALLEL))) {
int par = 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) if(!firstid)
dev_info(", "); dev_info(", ");
firstid = 0; firstid = 0;
dev_info("\"%s\"", ldata(ln)); char *str = cfg_escape(ldata(ln));
dev_info("%s", str);
free(str);
} }
dev_info(tsv? "\n": ";\n"); 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("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, "%d", baudrate);
_if_pgmout(intcmp, "0x%04x", usbvid); _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"); dev_info(tsv? "\n": ";\n");
} }
_if_pgmout(strcmp, "\"%s\"", usbdev); _if_pgmout_str(strcmp, cfg_escape(pgm->usbdev), usbdev);
_if_pgmout(strcmp, "\"%s\"", usbsn); _if_pgmout_str(strcmp, cfg_escape(pgm->usbsn), usbsn);
_if_pgmout(strcmp, "\"%s\"", usbvendor); _if_pgmout_str(strcmp, cfg_escape(pgm->usbvendor), usbvendor);
_if_pgmout(strcmp, "\"%s\"", usbproduct); _if_pgmout_str(strcmp, cfg_escape(pgm->usbproduct), usbproduct);
for(int i=0; i<N_PINS; i++) { for(int i=0; i<N_PINS; i++) {
char *str = pins_to_strdup(pgm->pin+i); char *str = pins_to_strdup(pgm->pin+i);

View File

@ -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)); \ dev_part_strct_entry(tsv, ".prog", id, NULL, #component, dev_sprintf(fmt, pgm->component)); \
} while(0) } while(0)
// Result must be a malloc()ed string
#define _if_pgmout_str(cmp, result, component) do { \ #define _if_pgmout_str(cmp, result, component) do { \
if(!base || cmp(base->component, pgm->component)) \ if(!base || cmp(base->component, pgm->component)) \
dev_part_strct_entry(tsv, ".prog", id, NULL, #component, result); \ 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)); \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component)); \
} while(0) } while(0)
// Result must be a malloc()ed string
#define _partout_str(result, component) \ #define _partout_str(result, component) \
dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result) 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 { \ #define _if_partout_str(cmp, result, component) do { \
if(!base || cmp(base->component, p->component)) \ if(!base || cmp(base->component, p->component)) \
dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \
} while(0) } while(0)
// Result must be a malloc()ed string
#define _if_n_partout_str(cmp, n, result, component) do { \ #define _if_n_partout_str(cmp, n, result, component) do { \
if(!base || cmp(base->component, p->component, n)) \ if(!base || cmp(base->component, p->component, n)) \
dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, result); \ 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)); \ dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, dev_sprintf(fmt, m->component)); \
} while(0) } while(0)
// Result must be a malloc()ed string
#define _memout_str(result, component) \ #define _memout_str(result, component) \
dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result) 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 { \ #define _if_n_memout_str(cmp, n, result, component) do { \
if(!bm || cmp(bm->component, m->component, n)) \ if(!bm || cmp(bm->component, m->component, n)) \
dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result); \ dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, result); \
} while(0) } while(0)
#define _memout_yn(component) \ #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 { \ #define _if_memout_yn(component) do { \
if(!bm || bm->component != m->component) \ 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) } while(0)
#define _flagout(mask, name) \ #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 { \ #define _if_flagout(mask, name) do { \
if(!base || (base->flags & (mask)) != (p->flags & (mask))) \ 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) } while(0)
// Result must be a malloc()ed string
#define _cmderr(result, component) \ #define _cmderr(result, component) \
dev_part_strct_entry(tsv, ".cmderr", p->desc, m->desc, #component, result) dev_part_strct_entry(tsv, ".cmderr", p->desc, m->desc, #component, result)

View File

@ -45,7 +45,6 @@ DIGIT [0-9]
HEXDIGIT [0-9a-fA-F] HEXDIGIT [0-9a-fA-F]
SIGN [+-] SIGN [+-]
%x strng
%x incl %x incl
%x comment %x comment
%option nounput %option nounput
@ -61,12 +60,19 @@ SIGN [+-]
{SIGN}?{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; } {SIGN}?{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
{SIGN}?"."{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; } 0x{HEXDIGIT}+ { yylval = hexnumber(yytext); return TKN_NUMBER; }
# { /* The following captures all '#' style comments to end of line */ # { /* The following captures all '#' style comments to end of line */
BEGIN(comment); } BEGIN(comment); }
<comment>[^\n]*\n+ { /* eat comments */ <comment>[^\n]*\n+ { /* eat comments */
@ -107,20 +113,6 @@ SIGN [+-]
} }
<strng>\" { *string_buf_ptr = 0; string_buf_ptr = string_buf;
yylval = string(string_buf_ptr); BEGIN(INITIAL); return TKN_STRING; }
<strng>\\n *string_buf_ptr++ = '\n';
<strng>\\t *string_buf_ptr++ = '\t';
<strng>\\r *string_buf_ptr++ = '\r';
<strng>\\b *string_buf_ptr++ = '\b';
<strng>\\f *string_buf_ptr++ = '\f';
<strng>\\(.|\n) *(string_buf_ptr++) = yytext[1];
<strng>[^\\\n\"]+ { char *yptr = yytext; while (*yptr)
*(string_buf_ptr++) = *(yptr++); }
<strng>\n { yyerror("unterminated character constant");
return YYERRCODE; }
alias { yylval=NULL; return K_ALIAS; } alias { yylval=NULL; return K_ALIAS; }
allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; } allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; }
avr910_devcode { yylval=NULL; return K_AVR910_DEVCODE; } avr910_devcode { yylval=NULL; return K_AVR910_DEVCODE; }

View File

@ -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 "" * 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 * @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 *pins_to_strdup(const struct pindef_t * const pindef);
@ -1006,6 +1006,10 @@ extern double default_bitclock;
extern "C" { extern "C" {
#endif #endif
void *cfg_malloc(const char *funcname, size_t n);
char *cfg_strdup(const char *funcname, const char *s);
int init_config(void); int init_config(void);
void cleanup_config(void); void cleanup_config(void);
@ -1014,6 +1018,12 @@ int read_config(const char * file);
const char *cache_string(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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -922,10 +922,7 @@ int main(int argc, char * argv [])
progname, progname,
(upd->op == DEVICE_READ)? 'r': (upd->op == DEVICE_WRITE)? 'w': 'v', (upd->op == DEVICE_READ)? 'r': (upd->op == DEVICE_WRITE)? 'w': 'v',
upd->filename, mtype); upd->filename, mtype);
if ((upd->memtype = strdup(mtype)) == NULL) { upd->memtype = cfg_strdup("main()", mtype);
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
exit(1);
}
} }
if (!avr_mem_might_be_known(upd->memtype)) { if (!avr_mem_might_be_known(upd->memtype)) {

View File

@ -67,14 +67,7 @@ PROGRAMMER * pgm_new(void)
PROGRAMMER * pgm; PROGRAMMER * pgm;
const char *nulp = cache_string(""); const char *nulp = cache_string("");
pgm = (PROGRAMMER *)malloc(sizeof(*pgm)); pgm = (PROGRAMMER *) cfg_malloc("pgm_new()", 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->id = lcreat(NULL, 0); pgm->id = lcreat(NULL, 0);
pgm->usbpid = lcreat(NULL, 0); pgm->usbpid = lcreat(NULL, 0);
@ -162,24 +155,13 @@ PROGRAMMER * pgm_dup(const PROGRAMMER * const src)
PROGRAMMER * pgm; PROGRAMMER * pgm;
LNODEID ln; LNODEID ln;
pgm = (PROGRAMMER *)malloc(sizeof(*pgm)); pgm = (PROGRAMMER *) cfg_malloc("pgm_dup()", sizeof(*pgm));
if (pgm == NULL) {
avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n",
progname);
return NULL;
}
memcpy(pgm, src, sizeof(*pgm)); memcpy(pgm, src, sizeof(*pgm));
pgm->id = lcreat(NULL, 0); pgm->id = lcreat(NULL, 0);
pgm->usbpid = lcreat(NULL, 0); pgm->usbpid = lcreat(NULL, 0);
for (ln = lfirst(src->usbpid); ln; ln = lnext(ln)) { for (ln = lfirst(src->usbpid); ln; ln = lnext(ln)) {
int *ip = malloc(sizeof(int)); int *ip = cfg_malloc("pgm_dup()", sizeof(int));
if (ip == NULL) {
avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n",
progname);
exit(1);
}
*ip = *(int *) ldata(ln); *ip = *(int *) ldata(ln);
ladd(pgm->usbpid, ip); ladd(pgm->usbpid, ip);
} }

View File

@ -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 "" * 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 * @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 *pins_to_strdup(const struct pindef_t * const pindef) {
char buf[6*(PIN_MAX+1)], *p = buf; 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);
} }
/** /**

View File

@ -20,7 +20,6 @@
#include "ac_cfg.h" #include "ac_cfg.h"
#include <ctype.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -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) { static size_t maxstrlen(int argc, char **argv) {
size_t max = 0; 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 // Strip start and end quotes, and unescape C string
strncpy(s, argi+1, arglen-2); strncpy(s, argi+1, arglen-2);
unescape((unsigned char *) s, (unsigned char *) s); cfg_unescape(s, s);
if (*argi == '\'') { // Single C-style character if (*argi == '\'') { // Single C-style character
if(*s && s[1]) if(*s && s[1])
terminal_message(MSG_INFO, "%s (write): only using first character of %s\n", terminal_message(MSG_INFO, "%s (write): only using first character of %s\n",

View File

@ -37,11 +37,7 @@ UPDATE * parse_op(char * s)
int i; int i;
size_t fnlen; size_t fnlen;
upd = (UPDATE *)malloc(sizeof(UPDATE)); upd = (UPDATE *) cfg_malloc("parse_op()", sizeof(UPDATE));
if (upd == NULL) {
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
exit(1);
}
i = 0; i = 0;
p = s; p = s;
@ -52,22 +48,12 @@ UPDATE * parse_op(char * s)
if (*p != ':') { if (*p != ':') {
upd->memtype = NULL; /* default memtype, "flash", or "application" */ upd->memtype = NULL; /* default memtype, "flash", or "application" */
upd->op = DEVICE_WRITE; upd->op = DEVICE_WRITE;
upd->filename = (char *)malloc(strlen(buf) + 1); upd->filename = cfg_strdup("parse_op()", buf);
if (upd->filename == NULL) {
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
exit(1);
}
strcpy(upd->filename, buf);
upd->format = FMT_AUTO; upd->format = FMT_AUTO;
return upd; return upd;
} }
upd->memtype = (char *)malloc(strlen(buf)+1); upd->memtype = cfg_strdup("parse_op()", buf);
if (upd->memtype == NULL) {
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
exit(1);
}
strcpy(upd->memtype, buf);
p++; p++;
if (*p == 'r') { if (*p == 'r') {
@ -118,10 +104,10 @@ UPDATE * parse_op(char * s)
// and to binary for read operations: // and to binary for read operations:
upd->format = upd->op == DEVICE_READ? FMT_RBIN: FMT_AUTO; upd->format = upd->op == DEVICE_READ? FMT_RBIN: FMT_AUTO;
fnlen = strlen(cp); fnlen = strlen(cp);
upd->filename = (char *)malloc(fnlen + 1); upd->filename = (char *) cfg_malloc("parse_op()", fnlen + 1);
} else { } else {
fnlen = p - cp; fnlen = p - cp;
upd->filename = (char *)malloc(fnlen +1); upd->filename = (char *) cfg_malloc("parse_op()", fnlen +1);
c = *++p; c = *++p;
if (c && p[1]) if (c && p[1])
/* More than one char - force failure below. */ /* 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); memcpy(upd->filename, cp, fnlen);
upd->filename[fnlen] = 0; upd->filename[fnlen] = 0;
@ -163,19 +143,15 @@ UPDATE * dup_update(UPDATE * upd)
{ {
UPDATE * u; UPDATE * u;
u = (UPDATE *)malloc(sizeof(UPDATE)); u = (UPDATE *) cfg_malloc("dup_update()", sizeof(UPDATE));
if (u == NULL) {
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
exit(1);
}
memcpy(u, upd, sizeof(UPDATE)); memcpy(u, upd, sizeof(UPDATE));
if (upd->memtype != NULL) if (upd->memtype != NULL)
u->memtype = strdup(upd->memtype); u->memtype = cfg_strdup("dup_update()", upd->memtype);
else else
u->memtype = NULL; u->memtype = NULL;
u->filename = strdup(upd->filename); u->filename = cfg_strdup("dup_update()", upd->filename);
return u; return u;
} }
@ -184,14 +160,10 @@ UPDATE * new_update(int op, char * memtype, int filefmt, char * filename)
{ {
UPDATE * u; UPDATE * u;
u = (UPDATE *)malloc(sizeof(UPDATE)); u = (UPDATE *) cfg_malloc("new_update()", sizeof(UPDATE));
if (u == NULL) {
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
exit(1);
}
u->memtype = strdup(memtype); u->memtype = cfg_strdup("new_update()", memtype);
u->filename = strdup(filename); u->filename = cfg_strdup("new_update()", filename);
u->op = op; u->op = op;
u->format = filefmt; u->format = filefmt;