From ad480502ebeaf912b1eb62bb67ffb02fb4a3c6f5 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Oct 2021 18:23:26 -0500 Subject: [PATCH] parser: properly support 64-bit numbers The language supports specifying 64-bit unsigned values, but the num field of the token structure is not guaranteed to be 64 bits wide. Change its type to be unsigned long long, and change the code that parses numbers to use strtoull() so we can actually accept a 64-bit value. This is also true of the value field of the token type. Change it to unsigned long long as well (and format it as unsigned). Check the return value of strtoull(), and if the result is out of range, report an error. Signed-off-by: Alex Elder Message-Id: <20211001232338.769309-23-elder@linaro.org> Signed-off-by: Bjorn Andersson --- parser.c | 11 +++++++++-- qmic.c | 2 +- qmic.h | 2 +- tests/num_large.qmi | 23 +++++++++++++++++++++++ tests/num_too_big.qmi | 22 ++++++++++++++++++++++ 5 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 tests/num_large.qmi create mode 100644 tests/num_too_big.qmi diff --git a/parser.c b/parser.c index 7e93175..f7ab041 100644 --- a/parser.c +++ b/parser.c @@ -50,7 +50,7 @@ enum token_id { struct token { enum token_id id; char *str; - unsigned num; + unsigned long long num; struct qmi_struct *qmi_struct; }; @@ -169,6 +169,7 @@ static struct token yylex() { struct symbol *sym; struct token token = {}; + unsigned long long num; char buf[128]; char *p = buf; int base; @@ -227,8 +228,14 @@ static struct token yylex() else base = 10; + errno = 0; + num = strtoull(buf, NULL, base); + if (errno) + yyerror("number %s out of range", buf); + + token.num = num; token.id = TOK_NUM; - token.num = strtol(buf, NULL, base); + return token; } else if (!ch) { token.id = TOK_EOF; diff --git a/qmic.c b/qmic.c index f542f82..05c86c4 100644 --- a/qmic.c +++ b/qmic.c @@ -28,7 +28,7 @@ void qmi_const_header(FILE *fp) return; list_for_each_entry(qc, &qmi_consts, node) - fprintf(fp, "#define %s %d\n", qc->name, qc->value); + fprintf(fp, "#define %s %llu\n", qc->name, qc->value); fprintf(fp, "\n"); } diff --git a/qmic.h b/qmic.h index 670adeb..b898d04 100644 --- a/qmic.h +++ b/qmic.h @@ -28,7 +28,7 @@ extern const char *qmi_package; struct qmi_const { const char *name; - unsigned value; + unsigned long long value; struct list_head node; }; diff --git a/tests/num_large.qmi b/tests/num_large.qmi new file mode 100644 index 0000000..96ef038 --- /dev/null +++ b/tests/num_large.qmi @@ -0,0 +1,23 @@ +package test; + +# As a 32 bit signed number, this would be negative +const TEST_NUMBER = 0x87654321; +# This value requires more than 32 bits to represent +const TEST_NUMBER = 0x123456789; + +struct qmi_result { + u16 result; + u16 error; +}; + +request test_request { + required u8 test_number = 0x12; +} = 0x80000000; + +response test_response { + required qmi_result r = 2; +} = 020000000000; + +indication test_indication { + optional u64 value = 0x99; +} = 0x7; diff --git a/tests/num_too_big.qmi b/tests/num_too_big.qmi new file mode 100644 index 0000000..10fe70a --- /dev/null +++ b/tests/num_too_big.qmi @@ -0,0 +1,22 @@ +package test; + +# This value requires more than 32 bits to represent +const TEST_NUMBER = 0x123456789; + +struct qmi_result { + u16 result; + u16 error; +}; + +request test_request { + required u8 test_number = 0x12; +} = 0x100000000; + +response test_response { + required qmi_result r = 2; +} = 040000000000; + +indication test_indication { + # This value requires more than 64 bits to represent + optional u64 value = 0x12345678987654321; +} = 0x7;