On Tue, Sep 04, 2018 at 08:15:23PM +0200, Denis Fondras wrote:
> Hi,
>
> While generating big prefixlists macros with bgpq3 (big like
> as2914:as-europe-v6
> for example), OpenBGPd cannot load the config file (error "string too long").
> This diff implements a dynamic buffer to overcome this limitation.
I would not go down this road. People should not use macros for massive
prefix lists or similar things. Instead prefix-sets should be used. There
are no such limitations with them and they will soon (as n2k18 is
aproaching) get better.
--
:wq Claudio
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
> retrieving revision 1.331
> diff -u -p -r1.331 parse.y
> --- parse.y 27 Aug 2018 19:32:37 -0000 1.331
> +++ parse.y 4 Sep 2018 18:13:48 -0000
> @@ -2746,13 +2746,22 @@ findeol(void)
> return (ERROR);
> }
>
> +#define READBUFFERSIZE 1024
> +
> int
> yylex(void)
> {
> - u_char buf[8096];
> + u_char *buf = NULL;
> u_char *p, *val;
> int quotec, next, c;
> int token;
> + u_int32_t bufsize = READBUFFERSIZE;
> +
> + buf = malloc(bufsize);
> + if (buf == NULL) {
> + yyerror("malloc failed");
> + return (findeol());
> + }
>
> top:
> p = buf;
> @@ -2765,12 +2774,19 @@ top:
> ; /* nothing */
> if (c == '$' && !expanding) {
> while (1) {
> - if ((c = lgetc(0)) == EOF)
> + if ((c = lgetc(0)) == EOF) {
> + free(buf);
> return (0);
> + }
>
> - if (p + 1 >= buf + sizeof(buf) - 1) {
> - yyerror("string too long");
> - return (findeol());
> + if (p + 1 >= buf + bufsize - 1) {
> + bufsize += READBUFFERSIZE;
> + buf = realloc(buf, bufsize);
> + if (buf == NULL) {
> + yyerror("realloc failed");
> + return (findeol());
> + }
> + p = buf + bufsize - READBUFFERSIZE - 2;
> }
> if (isalnum(c) || c == '_') {
> *p++ = c;
> @@ -2783,6 +2799,7 @@ top:
> val = symget(buf);
> if (val == NULL) {
> yyerror("macro '%s' not defined", buf);
> + free(buf);
> return (findeol());
> }
> p = val + strlen(val) - 1;
> @@ -2800,14 +2817,18 @@ top:
> case '"':
> quotec = c;
> while (1) {
> - if ((c = lgetc(quotec)) == EOF)
> + if ((c = lgetc(quotec)) == EOF) {
> + free(buf);
> return (0);
> + }
> if (c == '\n') {
> file->lineno++;
> continue;
> } else if (c == '\\') {
> - if ((next = lgetc(quotec)) == EOF)
> + if ((next = lgetc(quotec)) == EOF) {
> + free(buf);
> return (0);
> + }
> if (next == quotec || c == ' ' || c == '\t')
> c = next;
> else if (next == '\n') {
> @@ -2820,36 +2841,52 @@ top:
> break;
> } else if (c == '\0') {
> yyerror("syntax error");
> + free(buf);
> return (findeol());
> }
> - if (p + 1 >= buf + sizeof(buf) - 1) {
> - yyerror("string too long");
> - return (findeol());
> + if (p + 1 >= buf + bufsize - 1) {
> + bufsize += READBUFFERSIZE;
> + buf = realloc(buf, bufsize);
> + if (buf == NULL) {
> + yyerror("realloc failed");
> + return (findeol());
> + }
> + p = buf + bufsize - READBUFFERSIZE - 2;
> }
> *p++ = c;
> }
> yylval.v.string = strdup(buf);
> - if (yylval.v.string == NULL)
> + if (yylval.v.string == NULL) {
> + free(buf);
> fatal("yylex: strdup");
> + }
> return (STRING);
> case '!':
> next = lgetc(0);
> - if (next == '=')
> + if (next == '=') {
> + free(buf);
> return (NE);
> + }
> lungetc(next);
> break;
> case '<':
> next = lgetc(0);
> - if (next == '=')
> + if (next == '=') {
> + free(buf);
> return (LE);
> + }
> lungetc(next);
> break;
> case '>':
> next = lgetc(0);
> - if (next == '<')
> + if (next == '<') {
> + free(buf);
> return (XRANGE);
> - else if (next == '=')
> + }
> + else if (next == '=') {
> + free(buf);
> return (GE);
> + }
> lungetc(next);
> break;
> }
> @@ -2860,9 +2897,14 @@ top:
> if (c == '-' || isdigit(c)) {
> do {
> *p++ = c;
> - if ((unsigned)(p-buf) >= sizeof(buf)) {
> - yyerror("string too long");
> - return (findeol());
> + if ((unsigned)(p-buf) >= bufsize) {
> + bufsize += READBUFFERSIZE;
> + buf = realloc(buf, bufsize);
> + if (buf == NULL) {
> + yyerror("realloc failed");
> + return (findeol());
> + }
> + p = buf + bufsize - READBUFFERSIZE;
> }
> } while ((c = lgetc(0)) != EOF && isdigit(c));
> lungetc(c);
> @@ -2877,16 +2919,20 @@ top:
> if (errstr) {
> yyerror("\"%s\" invalid number: %s",
> buf, errstr);
> + free(buf);
> return (findeol());
> }
> + free(buf);
> return (NUMBER);
> } else {
> nodigits:
> while (p > buf + 1)
> lungetc(*--p);
> c = *--p;
> - if (c == '-')
> + if (c == '-') {
> + free(buf);
> return (c);
> + }
> }
> }
>
> @@ -2899,22 +2945,31 @@ nodigits:
> if (isalnum(c) || c == ':' || c == '_' || c == '*') {
> do {
> *p++ = c;
> - if ((unsigned)(p-buf) >= sizeof(buf)) {
> - yyerror("string too long");
> - return (findeol());
> + if ((unsigned)(p-buf) >= bufsize) {
> + bufsize += READBUFFERSIZE;
> + buf = realloc(buf, bufsize);
> + if (buf == NULL) {
> + yyerror("realloc failed");
> + return (findeol());
> + }
> + p = buf + bufsize - READBUFFERSIZE;
> }
> } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
> lungetc(c);
> *p = '\0';
> if ((token = lookup(buf)) == STRING)
> - if ((yylval.v.string = strdup(buf)) == NULL)
> + if ((yylval.v.string = strdup(buf)) == NULL) {
> + free(buf);
> fatal("yylex: strdup");
> + }
> + free(buf);
> return (token);
> }
> if (c == '\n') {
> yylval.lineno = file->lineno;
> file->lineno++;
> }
> + free(buf);
> if (c == EOF)
> return (0);
> return (c);
>
>