From: Jan Janssen Date: Wed, 1 Jun 2022 11:35:29 +0000 (+0200) Subject: boot: Add parse_number8/16 X-Git-Tag: v252-rc1~820^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=72bd3458e53bbdea2d96fd61271dbea2c4aee5bf;p=thirdparty%2Fsystemd.git boot: Add parse_number8/16 --- diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c index b9ef1548ca2..b1d83cb483f 100644 --- a/src/boot/efi/efi-string.c +++ b/src/boot/efi/efi-string.c @@ -239,6 +239,38 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) { return efi_fnmatch_internal(pattern, haystack, 32); } +#define DEFINE_PARSE_NUMBER(type, name) \ + bool name(const type *s, uint64_t *ret_u, const type **ret_tail) { \ + assert(ret_u); \ + \ + if (!s) \ + return false; \ + \ + /* Need at least one digit. */ \ + if (*s < '0' || *s > '9') \ + return false; \ + \ + uint64_t u = 0; \ + while (*s >= '0' && *s <= '9') { \ + if (__builtin_mul_overflow(u, 10, &u)) \ + return false; \ + if (__builtin_add_overflow(u, *s - '0', &u)) \ + return false; \ + s++; \ + } \ + \ + if (!ret_tail && *s != '\0') \ + return false; \ + \ + *ret_u = u; \ + if (ret_tail) \ + *ret_tail = s; \ + return true; \ + } + +DEFINE_PARSE_NUMBER(char, parse_number8); +DEFINE_PARSE_NUMBER(char16_t, parse_number16); + int efi_memcmp(const void *p1, const void *p2, size_t n) { const uint8_t *up1 = p1, *up2 = p2; int r; diff --git a/src/boot/efi/efi-string.h b/src/boot/efi/efi-string.h index 55c9c6e47ad..c25349c0e1e 100644 --- a/src/boot/efi/efi-string.h +++ b/src/boot/efi/efi-string.h @@ -101,6 +101,9 @@ static inline char16_t *xstrdup16(const char16_t *s) { bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack); +bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail); +bool parse_number16(const char16_t *s, uint64_t *ret_u, const char16_t **ret_tail); + #ifdef SD_BOOT /* The compiler normally has knowledge about standard functions such as memcmp, but this is not the case when * compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do diff --git a/src/boot/efi/test-efi-string.c b/src/boot/efi/test-efi-string.c index 178ad766cb4..0bfb564e3d6 100644 --- a/src/boot/efi/test-efi-string.c +++ b/src/boot/efi/test-efi-string.c @@ -371,6 +371,60 @@ TEST(efi_fnmatch) { TEST_FNMATCH_ONE("?a*b[.-0]c", "/a/b/c", true); } +TEST(parse_number8) { + uint64_t u; + const char *tail; + + assert_se(!parse_number8(NULL, &u, NULL)); + assert_se(!parse_number8("", &u, NULL)); + assert_se(!parse_number8("a1", &u, NULL)); + assert_se(!parse_number8("1a", &u, NULL)); + assert_se(!parse_number8("-42", &u, NULL)); + assert_se(!parse_number8("18446744073709551616", &u, NULL)); + + assert_se(parse_number8("0", &u, NULL)); + assert_se(u == 0); + assert_se(parse_number8("1", &u, NULL)); + assert_se(u == 1); + assert_se(parse_number8("999", &u, NULL)); + assert_se(u == 999); + assert_se(parse_number8("18446744073709551615", &u, NULL)); + assert_se(u == UINT64_MAX); + assert_se(parse_number8("42", &u, &tail)); + assert_se(u == 42); + assert_se(streq8(tail, "")); + assert_se(parse_number8("54321rest", &u, &tail)); + assert_se(u == 54321); + assert_se(streq8(tail, "rest")); +} + +TEST(parse_number16) { + uint64_t u; + const char16_t *tail; + + assert_se(!parse_number16(NULL, &u, NULL)); + assert_se(!parse_number16(u"", &u, NULL)); + assert_se(!parse_number16(u"a1", &u, NULL)); + assert_se(!parse_number16(u"1a", &u, NULL)); + assert_se(!parse_number16(u"-42", &u, NULL)); + assert_se(!parse_number16(u"18446744073709551616", &u, NULL)); + + assert_se(parse_number16(u"0", &u, NULL)); + assert_se(u == 0); + assert_se(parse_number16(u"1", &u, NULL)); + assert_se(u == 1); + assert_se(parse_number16(u"999", &u, NULL)); + assert_se(u == 999); + assert_se(parse_number16(u"18446744073709551615", &u, NULL)); + assert_se(u == UINT64_MAX); + assert_se(parse_number16(u"42", &u, &tail)); + assert_se(u == 42); + assert_se(streq16(tail, u"")); + assert_se(parse_number16(u"54321rest", &u, &tail)); + assert_se(u == 54321); + assert_se(streq16(tail, u"rest")); +} + TEST(efi_memcmp) { assert_se(efi_memcmp(NULL, NULL, 0) == 0); assert_se(efi_memcmp(NULL, NULL, 1) == 0);