From 8cd688c06378ebdb2def6f310fb1e78898b75bde Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Thu, 1 Apr 2021 22:07:28 +0300 Subject: keysym: avoid strtoul in xkb_keysym_from_name Signed-off-by: Ran Benita --- src/keysym.c | 38 ++++++++++++++++++++++++++++---------- test/keysym.c | 11 +++++++++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/keysym.c b/src/keysym.c index 10c5a52..83a418e 100644 --- a/src/keysym.c +++ b/src/keysym.c @@ -91,12 +91,37 @@ xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size) return snprintf(buffer, size, "0x%08x", ks); } +/* + * Parse the numeric part of a 0xXXXX and UXXXX keysym. + * Not using strtoul -- it's slower and accepts a bunch of stuff + * we don't want to allow, like signs, spaces, even locale stuff. + */ +static bool +parse_keysym_hex(const char *s, uint32_t *out) +{ + uint32_t result = 0; + int i; + for (i = 0; i < 8 && s[i] != '\0'; i++) { + result <<= 4; + if ('0' <= s[i] && s[i] <= '9') + result += s[i] - '0'; + else if ('a' <= s[i] && s[i] <= 'f') + result += 10 + s[i] - 'a'; + else if ('A' <= s[i] && s[i] <= 'F') + result += 10 + s[i] - 'A'; + else + return false; + } + *out = result; + return s[i] == '\0' && i > 0; +} + XKB_EXPORT xkb_keysym_t xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags) { const struct name_keysym *entry = NULL; char *tmp; - unsigned long val; + uint32_t val; bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE); if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE) @@ -169,9 +194,7 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags) } if (*name == 'U' || (icase && *name == 'u')) { - errno = 0; - val = strtoul(&name[1], &tmp, 16); - if ((tmp && *tmp != '\0') || errno != 0) + if (!parse_keysym_hex(&name[1], &val)) return XKB_KEY_NoSymbol; if (val < 0x20 || (val > 0x7e && val < 0xa0)) @@ -183,13 +206,8 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags) return (xkb_keysym_t) val | 0x01000000; } else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) { - errno = 0; - val = strtoul(&name[2], &tmp, 16); - if ((tmp && *tmp != '\0') || errno != 0) + if (!parse_keysym_hex(&name[2], &val)) return XKB_KEY_NoSymbol; - if (val > UINT32_MAX) - return XKB_KEY_NoSymbol; - return (xkb_keysym_t) val; } diff --git a/test/keysym.c b/test/keysym.c index b802bcb..0c3ba9f 100644 --- a/test/keysym.c +++ b/test/keysym.c @@ -136,7 +136,18 @@ main(void) assert(test_string("XF86_Switch_VT_5", 0x1008FE05)); assert(test_string("VoidSymbol", 0xFFFFFF)); assert(test_string("U4567", 0x1004567)); + assert(test_string("U+4567", XKB_KEY_NoSymbol)); + assert(test_string("U+4567ffff", XKB_KEY_NoSymbol)); + assert(test_string("U+4567ffffff", XKB_KEY_NoSymbol)); + assert(test_string("U 4567", XKB_KEY_NoSymbol)); + assert(test_string("U +4567", XKB_KEY_NoSymbol)); assert(test_string("0x10203040", 0x10203040)); + assert(test_string("0x102030400", XKB_KEY_NoSymbol)); + assert(test_string("0x010203040", XKB_KEY_NoSymbol)); + assert(test_string("0x+10203040", XKB_KEY_NoSymbol)); + assert(test_string("0x 10203040", XKB_KEY_NoSymbol)); + assert(test_string("0x +10203040", XKB_KEY_NoSymbol)); + assert(test_string("0x-10203040", XKB_KEY_NoSymbol)); assert(test_string("a", 0x61)); assert(test_string("A", 0x41)); assert(test_string("ch", 0xfea0)); -- cgit v1.2.1