From e92e2c7362cf80a5e67e20d61a79f2b8a4712627 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sat, 1 Jun 2019 19:41:42 +0200 Subject: [PATCH] [PATCH #62] Fixed buffer overrun. Reworked to not use dstring for more efficient parsing. --- src/include/ngspice/stringutil.h | 2 +- src/misc/string.c | 150 +++++++++++++++++++------------ 2 files changed, 96 insertions(+), 56 deletions(-) diff --git a/src/include/ngspice/stringutil.h b/src/include/ngspice/stringutil.h index e8faf1aa8..17b25052d 100644 --- a/src/include/ngspice/stringutil.h +++ b/src/include/ngspice/stringutil.h @@ -22,7 +22,7 @@ int cieq(const char *p, const char *s); int ciprefix(const char *p, const char *s); void strtolower(char *str); void strtoupper(char *str); -char * stripWhiteSpacesInsideParens(char *str); +char * stripWhiteSpacesInsideParens(const char *str); char * gettok(char **s); char * gettok_instance(char **); char * gettok_char(char **s, char p, bool inc_p, bool nested); diff --git a/src/misc/string.c b/src/misc/string.c index ed89a3582..14d049514 100644 --- a/src/misc/string.c +++ b/src/misc/string.c @@ -275,7 +275,6 @@ cimatch(char *p, char *s) * since I didn't want to break any fcns which called it from elsewhere than * subckt.c. -- SDB 12.3.2003. *-------------------------------------------------------------------------*/ - char * gettok(char **s) { @@ -350,44 +349,63 @@ nexttok(const char *s) char * gettok_iv(char **s) { - char c; - int paren; - char *token; /* return token */ - SPICE_DSTRING buf; /* allow any length string */ + char *p_src = *s; /* location in source string */ + char c; /* current char */ - paren = 0; - while (isspace_c(**s) || (**s == '=')) - (*s)++; + /* Step past whitespace and '=' */ + while (isspace_c(c = *p_src) || (c == '=')) { + p_src++; + } - if ((!**s) || ((**s != 'v') && (**s != 'i') && (**s != 'V') && (**s != 'I'))) - return NULL; + /* Test for valid leading character */ + if (((c =*p_src) == '\0') || + ((c != 'v') && (c != 'i') && (c != 'V') && (c != 'I'))) { + *s = p_src; /* update position in string */ + return (char *) NULL; + } - // initialize string - spice_dstring_init(&buf); - // add v or i to buf - spice_dstring_append_char(&buf, *(*s)++); + /* Allocate buffer for token being returned */ + char * const token = TMALLOC(char, strlen(p_src) + 1); + char *p_dst = token; /* location in token */ - while ((c = **s) != '\0') { - if (c == '(') - paren += 1; - else if (c == ')') - paren -= 1; - if (isspace_c(c)) - (*s)++; - else { - spice_dstring_append_char(&buf, *(*s)++); - if (paren == 0) - break; + // add v or i to buf + *p_dst++ = *p_src++; + + { + int n_paren = 0; + /* Skip any space between v/V/i/I and '(' */ + p_src = skip_ws(p_src); + + while ((c = *p_src) != '\0') { + /* Keep track of nesting level */ + if (c == '(') { + n_paren++; + } + else if (c == ')') { + n_paren--; + } + + if (isspace_c(c)) { /* Do not copy whitespace to output */ + p_src++; + } + else { + *p_dst++ = *p_src++; + if (n_paren == 0) { + break; + } + } } } - while (isspace_c(**s) || **s == ',') - (*s)++; + /* Step past whitespace and ',' */ + while (isspace_c(c = *p_src) || (c == ',')) { + p_src++; + } - token = copy(spice_dstring_value(&buf)); - spice_dstring_free(&buf); + *s = p_src; /* update position in string */ return token; -} +} /* end of function gettok_iv */ + /*-------------------------------------------------------------------------* @@ -650,36 +668,55 @@ get_r_paren(char **s) /*-------------------------------------------------------------------------* * this function strips all white space inside parens - * is needed in gettoks (dotcards.c) for right processing of expressions - * like ".plot v( 5,4) v(6)" + * is needed in gettoks (dotcards.c) for correct processing of expressions + * like " .plot v( 5 , 4 ) v( 6 )" -> .plot v(5,4) v(6)" *-------------------------------------------------------------------------*/ - char * -stripWhiteSpacesInsideParens(char *str) +stripWhiteSpacesInsideParens(const char *str) { - char *token; /* return token */ - SPICE_DSTRING buf; /* allow any length string */ - int i = 0; /* index into string */ - - while ((str[i] == ' ') || (str[i] == '\t')) - i++; - - spice_dstring_init(&buf); - for (; str[i]; i++) - if (str[i] != '(') { - spice_dstring_append_char(&buf, str[i]); - } else { - spice_dstring_append_char(&buf, str[i]); - while (str[i++] != ')') - if (str[i] != ' ') - spice_dstring_append_char(&buf, str[i]); - i--; + str = skip_ws(str); /* Skip leading whitespace */ + const size_t n_char_str = strlen(str); + + /* Allocate buffer for string being built */ + char * const str_out = TMALLOC(char, n_char_str + 1); + char *p_dst = str_out; /* location in str_out */ + char ch; /* current char */ + + /* Process input string until its end */ + for ( ; ; ) { + /* Add char. If at end of input string, return the string + * that was built */ + if ((*p_dst++ = (ch = *str++)) == '\0') { + return str_out; } - token = copy(spice_dstring_value(&buf)); - spice_dstring_free(&buf); - return token; -} + /* If the char is a ')' add all non-whitespace until ')' or, + * if the string is malformed, until '\0' */ + if (ch == '(') { + for ( ; ; ) { + /* If at end of input string, the closing ') was missing. + * The caller will need to resolve this issue. */ + if ((ch = *str++) == '\0') { + *p_dst = '\0'; + return str_out; + } + + if (isspace((int) ch)) { /* skip whitespace */ + continue; + } + + /* Not whitespace, so add next character */ + *p_dst++ = ch; + + /* If the char that was added was ')', done */ + if (ch == ')') { + break; + } + } /* end of loop processing () */ + } /* end of case of '(' found */ + } /* end of loop over chars in input string */ +} /* end of function stripWhiteSpacesInsideParens */ + bool @@ -761,3 +798,6 @@ model_name_match(const char *token, const char *model_name) return 2; } + + +