summaryrefslogtreecommitdiff
path: root/scanner.l
diff options
context:
space:
mode:
authorGuy Harris <gharris@sonic.net>2023-05-07 16:53:39 -0700
committerGuy Harris <gharris@sonic.net>2023-05-07 18:08:46 -0700
commita5cac25efd6ee857bab0b933ca5f7bbe1ede5074 (patch)
tree74acc7c3c043d1611060402da8a3441f8ac9b482 /scanner.l
parent2ad4ea365d4eca1ee38182472198e198636c9b26 (diff)
downloadlibpcap-a5cac25efd6ee857bab0b933ca5f7bbe1ede5074.tar.gz
compiler: parse port numbers in ranges using the standard number parser.
Run them through the same code that's used for numbers in the lexical analyzer, for consistency.
Diffstat (limited to 'scanner.l')
-rw-r--r--scanner.l169
1 files changed, 131 insertions, 38 deletions
diff --git a/scanner.l b/scanner.l
index 85fe395a..c20637b2 100644
--- a/scanner.l
+++ b/scanner.l
@@ -32,6 +32,26 @@
#include "grammar.h"
#include "diag-control.h"
+
+/*
+ * Convert string to 32-bit unsigned integer; the string starts at
+ * string and is string_len bytes long.
+ *
+ * On success, sets *val to the value and returns 1.
+ * On failure, sets the BPF error string and returns 0.
+ *
+ * Also used in gencode.c
+ */
+typedef enum {
+ STOULEN_OK,
+ STOULEN_NOT_HEX_NUMBER,
+ STOULEN_NOT_OCTAL_NUMBER,
+ STOULEN_NOT_DECIMAL_NUMBER,
+ STOULEN_ERROR
+} stoulen_ret;
+
+stoulen_ret stoulen(const char *string, size_t stringlen, bpf_u_int32 *val,
+ compiler_state_t *cstate);
}
/*
@@ -149,7 +169,7 @@ void pcap_set_column(int, yyscan_t);
#include "os-proto.h"
#endif
-static int stou(char *, YYSTYPE *, compiler_state_t *);
+static int stou(const char *, YYSTYPE *, compiler_state_t *);
/*
* Disable diagnostics in the code generated by Flex.
@@ -490,27 +510,20 @@ tcp-cwr { yylval->h = 0x80; return NUM; }
*/
DIAG_ON_FLEX
-/*
- * Convert string to 32-bit unsigned integer. Just like atoi(), but checks for
- * preceding 0x or 0 and uses hex or octal instead of decimal.
- *
- * On success, sets yylval->h to the value and returns NUM.
- * On failure, sets the BPF error string and returns LEX_ERROR, to force
- * the parse to stop.
- */
-static int
-stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
+stoulen_ret
+stoulen(const char *string, size_t string_len, bpf_u_int32 *val,
+ compiler_state_t *cstate)
{
bpf_u_int32 n = 0;
unsigned int digit;
- char *s = yytext_arg;
+ const char *s = string;
/*
- * yytext_arg is guaranteed either to be a string of decimal digits
+ * string is guaranteed either to be a string of decimal digits
* or 0[xX] followed by a string of hex digits.
*/
- if (*s == '0') {
- if (s[1] == 'x' || s[1] == 'X') {
+ if (string_len >= 1 && *s == '0') {
+ if (string_len >= 2 && (s[1] == 'x' || s[1] == 'X')) {
/*
* Begins with 0x or 0X, so hex.
* Guaranteed to be all hex digits following the
@@ -518,13 +531,25 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
* A-F.
*/
s += 2; /* skip the prefix */
- while ((digit = *s++) != '\0') {
+ string_len -= 2;
+ while (string_len != 0) {
+ digit = *s++;
+ string_len--;
if (digit >= '0' && digit <= '9')
digit = digit - '0';
else if (digit >= 'a' && digit <= 'f')
digit = digit - 'a' + 10;
- else
+ else if (digit >= 'A' && digit <= 'F')
digit = digit - 'A' + 10;
+ else {
+ /*
+ * Not a valid hex number.
+ * Don't treat this as an error,
+ * in case the caller wants to
+ * interpret it as something else.
+ */
+ return STOULEN_NOT_HEX_NUMBER;
+ }
/*
* Check for overflow.
@@ -536,10 +561,10 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
* add 4 more; that won't fit
* in 32 bits.
*/
- bpf_set_error(yyextra_arg,
- "number %s overflows 32 bits",
- yytext_arg);
- return LEX_ERROR;
+ bpf_set_error(cstate,
+ "number %.*s overflows 32 bits",
+ (int)string_len, string);
+ return STOULEN_ERROR;
}
n = (n << 4) + digit;
}
@@ -551,14 +576,20 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
* report an error.
*/
s += 1;
- while ((digit = *s++) != '\0') {
+ string_len -= 1;
+ while (string_len != 0) {
+ digit = *s++;
+ string_len--;
if (digit >= '0' && digit <= '7')
digit = digit - '0';
else {
- bpf_set_error(yyextra_arg,
- "number %s contains non-octal digit",
- yytext_arg);
- return LEX_ERROR;
+ /*
+ * Not a valid octal number.
+ * Don't treat this as an error,
+ * in case the caller wants to
+ * interpret it as something else.
+ */
+ return STOULEN_NOT_OCTAL_NUMBER;
}
if (n > 03777777777U) {
/*
@@ -567,10 +598,10 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
* 3 more; that won't fit in
* 32 bits.
*/
- bpf_set_error(yyextra_arg,
- "number %s overflows 32 bits",
- yytext_arg);
- return LEX_ERROR;
+ bpf_set_error(cstate,
+ "number %.*s overflows 32 bits",
+ (int)string_len, string);
+ return STOULEN_ERROR;
}
n = (n << 3) + digit;
}
@@ -579,21 +610,83 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
/*
* Decimal.
*/
- while ((digit = *s++) != '\0') {
- digit = digit - '0';
+ while (string_len != 0) {
+ digit = *s++;
+ string_len--;
+ if (digit >= '0' && digit <= '9')
+ digit = digit - '0';
+ else {
+ /*
+ * Not a valid decimal number.
+ * Don't treat this as an error,
+ * in case the caller wants to
+ * interpret it as something else.
+ */
+ return STOULEN_NOT_DECIMAL_NUMBER;
+ }
#define CUTOFF_DEC (0xFFFFFFFFU / 10U)
#define CUTLIM_DEC (0xFFFFFFFFU % 10U)
if (n > CUTOFF_DEC ||
(n == CUTOFF_DEC && digit > CUTLIM_DEC)) {
- bpf_set_error(yyextra_arg,
- "number %s overflows 32 bits",
- yytext_arg);
- return LEX_ERROR;
+ /*
+ * Adding that digit will result in a
+ * number that won't fit in 32 bits.
+ */
+ bpf_set_error(cstate,
+ "number %.*s overflows 32 bits",
+ (int)string_len, string);
+ return STOULEN_ERROR;
}
n = (n * 10) + digit;
}
}
- yylval_arg->h = n;
- return NUM;
+ *val = n;
+ return STOULEN_OK;
+}
+
+/*
+ * Convert string to 32-bit unsigned integer. Just like atoi(), but checks for
+ * preceding 0x or 0 and uses hex or octal instead of decimal.
+ *
+ * On success, sets yylval->h to the value and returns NUM.
+ * On failure, sets the BPF error string and returns LEX_ERROR, to force
+ * the parse to stop.
+ */
+static int
+stou(const char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
+{
+ stoulen_ret ret;
+
+ ret = stoulen(yytext_arg, strlen(yytext_arg), &yylval_arg->h,
+ yyextra_arg);
+ switch (ret) {
+
+ case STOULEN_OK:
+ return NUM;
+
+ case STOULEN_NOT_OCTAL_NUMBER:
+ bpf_set_error(yyextra_arg, "number %s contains non-octal digit",
+ yytext_arg);
+ return LEX_ERROR;
+
+ case STOULEN_NOT_HEX_NUMBER:
+ bpf_set_error(yyextra_arg, "number %s contains non-hex digit",
+ yytext_arg);
+ return LEX_ERROR;
+
+ case STOULEN_NOT_DECIMAL_NUMBER:
+ bpf_set_error(yyextra_arg, "number %s contains non-decimal digit",
+ yytext_arg);
+ return LEX_ERROR;
+
+ case STOULEN_ERROR:
+ /* Error already set. */
+ return LEX_ERROR;
+
+ default:
+ /* Should not happen */
+ bpf_set_error(yyextra_arg, "stoulen returned %d", ret);
+ return LEX_ERROR;
+ }
}