From: Guy Harris Date: Sat, 5 Dec 2015 03:00:46 +0000 (-0800) Subject: Generate a reentrant lexical analyzer and parser. X-Git-Tag: libpcap-1.8.0-bp~108 X-Git-Url: https://git.tcpdump.org/libpcap/commitdiff_plain/5823e2382c11cb9cdbe895c7e34b045a25c3bd78 Generate a reentrant lexical analyzer and parser. This doesn't make pcap_compile() completely reentrant and thread-safe, but it's a significant step along the way. Get rid of some stuff left over from when we supported classic Lex. --- diff --git a/gencode.c b/gencode.c index 165920e6..1d4d8947 100644 --- a/gencode.c +++ b/gencode.c @@ -74,6 +74,9 @@ #include "pcap/ipnet.h" #include "arcnet.h" +#include "grammar.h" +#include "scanner.h" + #if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) #include #include @@ -472,6 +475,8 @@ pcap_compile(pcap_t *p, struct bpf_program *program, { extern int n_errors; const char * volatile xbuf = buf; + yyscan_t scanner = NULL; + YY_BUFFER_STATE in_buffer = NULL; u_int len; int rc; @@ -512,8 +517,6 @@ pcap_compile(pcap_t *p, struct bpf_program *program, ai = NULL; } #endif - lex_cleanup(); - freechunks(); rc = -1; goto quit; } @@ -528,9 +531,11 @@ pcap_compile(pcap_t *p, struct bpf_program *program, goto quit; } - lex_init(xbuf ? xbuf : ""); + if (pcap_lex_init(&scanner) != 0) + bpf_error("can't initialize scanner: %s", pcap_strerror(errno)); + in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner); init_linktype(p); - (void)pcap_parse(); + (void)pcap_parse(scanner); if (n_errors) syntax(); @@ -547,13 +552,21 @@ pcap_compile(pcap_t *p, struct bpf_program *program, program->bf_insns = icode_to_fcode(root, &len); program->bf_len = len; - lex_cleanup(); - pcap_lex_destroy(); - freechunks(); - rc = 0; /* We're all okay */ quit: + /* + * Clean up everything for the lexical analyzer. + */ + if (in_buffer != NULL) + pcap__delete_buffer(in_buffer, scanner); + if (scanner != NULL) + pcap_lex_destroy(scanner); + + /* + * Clean up our own allocated memory. + */ + freechunks(); #ifdef _WIN32 LeaveCriticalSection(&g_PcapCompileCriticalSection); diff --git a/gencode.h b/gencode.h index 67ed0dc0..5abca72d 100644 --- a/gencode.h +++ b/gencode.h @@ -353,9 +353,7 @@ void finish_parse(struct block *); char *sdup(const char *); struct bpf_insn *icode_to_fcode(struct block *, u_int *); -int pcap_parse(void); -void lex_init(const char *); -void lex_cleanup(void); +int pcap_parse(void *); void sappend(struct slist *, struct slist *); /* XXX */ diff --git a/grammar.y b/grammar.y index cb94824b..5acf13ca 100644 --- a/grammar.y +++ b/grammar.y @@ -1,3 +1,16 @@ +/* + * We want a reentrant parser. + */ +%pure-parser + +/* + * We also want a reentrant scanner, so we have to pass the + * handle for the reentrant scanner to the parser, and the + * parser has to pass it to the lexical analyzer. + */ +%parse-param {yyscan_t yyscanner} +%lex-param {yyscan_t yyscanner} + %{ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 @@ -49,6 +62,9 @@ struct rtentry; #include "pcap-int.h" #include "gencode.h" +#include "grammar.h" +#include "scanner.h" + #ifdef HAVE_NET_PFVAR_H #include #include @@ -174,7 +190,7 @@ int n_errors = 0; static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; static void -yyerror(const char *msg) +yyerror(yyscan_t yyscanner, const char *msg) { ++n_errors; bpf_error("%s", msg); diff --git a/pcap-int.h b/pcap-int.h index 091b0419..04d2ba4b 100644 --- a/pcap-int.h +++ b/pcap-int.h @@ -361,8 +361,6 @@ struct oneshot_userdata { pcap_t *pd; }; -int yylex(void); - #ifndef min #define min(a, b) ((a) > (b) ? (b) : (a)) #endif diff --git a/scanner.l b/scanner.l index 6b46fbe3..451f86b4 100644 --- a/scanner.l +++ b/scanner.l @@ -5,11 +5,28 @@ #endif } +/* + * We want a reentrant scanner. + */ +%option reentrant + +/* + * We don't use input, so don't generate code for it. + */ +%option noinput + +/* + * We don't use unput, so don't generate code for it. + */ +%option nounput + /* * We don't read from the terminal. */ %option never-interactive +%option bison-bridge + %{ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 @@ -53,6 +70,15 @@ #include "gencode.h" +#include "grammar.h" + +/* + * Earlier versions of Flex dsn't declare these, so we declare them + * ourselves to squelch warnings. + */ +int pcap_get_column(yyscan_t); +void pcap_set_column(int, yyscan_t); + #ifdef INET6 #ifdef _WIN32 @@ -101,20 +127,6 @@ static int stoi(char *); static inline int xdtoi(int); -#ifdef FLEX_SCANNER -#define YY_NO_INPUT -#define YY_NO_UNPUT -static YY_BUFFER_STATE in_buffer; -#else -static const char *in_buffer; - -#undef getc -#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++) -#endif - -#define yylval pcap_lval -extern YYSTYPE yylval; - %} N ([0-9]+|(0X|0x)[0-9A-Fa-f]+) @@ -357,17 +369,17 @@ hsls return HSLS; "==" return '='; "<<" return LSH; ">>" return RSH; -${B} { yylval.e = pcap_ether_aton(((char *)yytext)+1); - if (yylval.e == NULL) +${B} { yylval->e = pcap_ether_aton(((char *)yytext)+1); + if (yylval->e == NULL) bpf_error("malloc"); return AID; } -{MAC} { yylval.e = pcap_ether_aton((char *)yytext); - if (yylval.e == NULL) +{MAC} { yylval->e = pcap_ether_aton((char *)yytext); + if (yylval->e == NULL) bpf_error("malloc"); return EID; } -{N} { yylval.i = stoi((char *)yytext); return NUM; } +{N} { yylval->i = stoi((char *)yytext); return NUM; } ({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) { - yylval.s = sdup((char *)yytext); return HID; } + yylval->s = sdup((char *)yytext); return HID; } {V6} { #ifdef INET6 struct addrinfo hints, *res; @@ -378,67 +390,44 @@ ${B} { yylval.e = pcap_ether_aton(((char *)yytext)+1); bpf_error("bogus IPv6 address %s", yytext); else { freeaddrinfo(res); - yylval.s = sdup((char *)yytext); return HID6; + yylval->s = sdup((char *)yytext); return HID6; } #else bpf_error("IPv6 address %s not supported", yytext); #endif /*INET6*/ } {B}:+({B}:+)+ { bpf_error("bogus ethernet address %s", yytext); } -icmptype { yylval.i = 0; return NUM; } -icmpcode { yylval.i = 1; return NUM; } -icmp-echoreply { yylval.i = 0; return NUM; } -icmp-unreach { yylval.i = 3; return NUM; } -icmp-sourcequench { yylval.i = 4; return NUM; } -icmp-redirect { yylval.i = 5; return NUM; } -icmp-echo { yylval.i = 8; return NUM; } -icmp-routeradvert { yylval.i = 9; return NUM; } -icmp-routersolicit { yylval.i = 10; return NUM; } -icmp-timxceed { yylval.i = 11; return NUM; } -icmp-paramprob { yylval.i = 12; return NUM; } -icmp-tstamp { yylval.i = 13; return NUM; } -icmp-tstampreply { yylval.i = 14; return NUM; } -icmp-ireq { yylval.i = 15; return NUM; } -icmp-ireqreply { yylval.i = 16; return NUM; } -icmp-maskreq { yylval.i = 17; return NUM; } -icmp-maskreply { yylval.i = 18; return NUM; } -tcpflags { yylval.i = 13; return NUM; } -tcp-fin { yylval.i = 0x01; return NUM; } -tcp-syn { yylval.i = 0x02; return NUM; } -tcp-rst { yylval.i = 0x04; return NUM; } -tcp-push { yylval.i = 0x08; return NUM; } -tcp-ack { yylval.i = 0x10; return NUM; } -tcp-urg { yylval.i = 0x20; return NUM; } +icmptype { yylval->i = 0; return NUM; } +icmpcode { yylval->i = 1; return NUM; } +icmp-echoreply { yylval->i = 0; return NUM; } +icmp-unreach { yylval->i = 3; return NUM; } +icmp-sourcequench { yylval->i = 4; return NUM; } +icmp-redirect { yylval->i = 5; return NUM; } +icmp-echo { yylval->i = 8; return NUM; } +icmp-routeradvert { yylval->i = 9; return NUM; } +icmp-routersolicit { yylval->i = 10; return NUM; } +icmp-timxceed { yylval->i = 11; return NUM; } +icmp-paramprob { yylval->i = 12; return NUM; } +icmp-tstamp { yylval->i = 13; return NUM; } +icmp-tstampreply { yylval->i = 14; return NUM; } +icmp-ireq { yylval->i = 15; return NUM; } +icmp-ireqreply { yylval->i = 16; return NUM; } +icmp-maskreq { yylval->i = 17; return NUM; } +icmp-maskreply { yylval->i = 18; return NUM; } +tcpflags { yylval->i = 13; return NUM; } +tcp-fin { yylval->i = 0x01; return NUM; } +tcp-syn { yylval->i = 0x02; return NUM; } +tcp-rst { yylval->i = 0x04; return NUM; } +tcp-push { yylval->i = 0x08; return NUM; } +tcp-ack { yylval->i = 0x10; return NUM; } +tcp-urg { yylval->i = 0x20; return NUM; } [A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? { - yylval.s = sdup((char *)yytext); return ID; } -"\\"[^ !()\n\t]+ { yylval.s = sdup((char *)yytext + 1); return ID; } + yylval->s = sdup((char *)yytext); return ID; } +"\\"[^ !()\n\t]+ { yylval->s = sdup((char *)yytext + 1); return ID; } [^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { bpf_error("illegal token: %s", yytext); } . { bpf_error("illegal char '%c'", *yytext); } %% -void -lex_init(buf) - const char *buf; -{ -#ifdef FLEX_SCANNER - in_buffer = yy_scan_string(buf); -#else - in_buffer = buf; -#endif -} - -/* - * Do any cleanup necessary after parsing. - */ -void -lex_cleanup() -{ -#ifdef FLEX_SCANNER - if (in_buffer != NULL) - yy_delete_buffer(in_buffer); - in_buffer = NULL; -#endif -} /* * Also define a yywrap. Note that if we're using flex, it will