diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2021-04-04 03:01:43 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-04-04 00:40:41 +0200 |
commit | 143c68755bd02da1c6b0091025ebe5fe27d93f67 (patch) | |
tree | a91feefe443d0e36b2c93b295d73972a82193686 | |
parent | f05cca7a9a4f4206f68b0f5d029b7c09293816d9 (diff) | |
download | serenity-143c68755bd02da1c6b0091025ebe5fe27d93f67.zip |
LibC: Use 'long long' specialisations of scanf's read_element_concrete
...for 'long long' and 'unsigned long long', instead of reading them as
'long's and 'unsigned long's.
Also add a test for values that can only fit in (unsigned) long long.
Fixes #6096.
-rw-r--r-- | Userland/Libraries/LibC/scanf.cpp | 42 | ||||
-rw-r--r-- | Userland/Tests/LibC/scanf.cpp | 6 |
2 files changed, 44 insertions, 4 deletions
diff --git a/Userland/Libraries/LibC/scanf.cpp b/Userland/Libraries/LibC/scanf.cpp index 7e517c970c..aae825a426 100644 --- a/Userland/Libraries/LibC/scanf.cpp +++ b/Userland/Libraries/LibC/scanf.cpp @@ -164,6 +164,40 @@ struct read_element_concrete<unsigned, ApT, kind> { }; template<typename ApT, ReadKind kind> +struct read_element_concrete<long long, ApT, kind> { + bool operator()(GenericLexer& lexer, va_list* ap) + { + lexer.ignore_while(isspace); + + auto* ptr = va_arg(*ap, ApT*); + long long value = 0; + char* endptr = nullptr; + auto nptr = lexer.remaining().characters_without_null_termination(); + if constexpr (kind == ReadKind::Normal) + value = strtoll(nptr, &endptr, 10); + if constexpr (kind == ReadKind::Octal) + value = strtoll(nptr, &endptr, 8); + if constexpr (kind == ReadKind::Hex) + value = strtoll(nptr, &endptr, 16); + if constexpr (kind == ReadKind::Infer) + value = strtoll(nptr, &endptr, 0); + + if (!endptr) + return false; + + if (endptr == nptr) + return false; + + auto diff = endptr - nptr; + VERIFY(diff > 0); + lexer.ignore((size_t)diff); + + *ptr = value; + return true; + } +}; + +template<typename ApT, ReadKind kind> struct read_element_concrete<unsigned long long, ApT, kind> { bool operator()(GenericLexer& lexer, va_list* ap) { @@ -248,15 +282,15 @@ struct read_element { if constexpr (IsSame<T, unsigned>::value) return read_element_concrete<T, unsigned, kind> {}(input_lexer, ap); if constexpr (IsSame<T, float>::value) - return read_element_concrete<T, double, kind> {}(input_lexer, ap); + return read_element_concrete<int, double, kind> {}(input_lexer, ap); return false; case LongLong: if constexpr (IsSame<T, int>::value) - return read_element_concrete<T, long long, kind> {}(input_lexer, ap); + return read_element_concrete<long long, long long, kind> {}(input_lexer, ap); if constexpr (IsSame<T, unsigned>::value) - return read_element_concrete<T, unsigned long long, kind> {}(input_lexer, ap); + return read_element_concrete<unsigned long long, unsigned long long, kind> {}(input_lexer, ap); if constexpr (IsSame<T, float>::value) - return read_element_concrete<T, double, kind> {}(input_lexer, ap); + return read_element_concrete<long long, double, kind> {}(input_lexer, ap); return false; case IntMax: return read_element_concrete<T, intmax_t, kind> {}(input_lexer, ap); diff --git a/Userland/Tests/LibC/scanf.cpp b/Userland/Tests/LibC/scanf.cpp index 71aeb0a51f..73f6c858ad 100644 --- a/Userland/Tests/LibC/scanf.cpp +++ b/Userland/Tests/LibC/scanf.cpp @@ -31,6 +31,7 @@ typedef long double longdouble; typedef long long longlong; +typedef unsigned long long unsignedlonglong; typedef unsigned long unsignedlong; typedef char charstar[32]; @@ -145,6 +146,7 @@ DECL_WITH_TYPE(float); DECL_WITH_TYPE(double); DECL_WITH_TYPE(longdouble); DECL_WITH_TYPE(unsignedlong); +DECL_WITH_TYPE(unsignedlonglong); #undef DECL_WITH_TYPE @@ -184,6 +186,10 @@ const TestSuite test_suites[] { // GCC failure tests { "%d.%d.%d", "10.2.0", 3, 3, { intarg0, intarg1, intarg2 }, { to_value_t(10), to_value_t(2), to_value_t(0) } }, { "%lu", "3054 ", 1, 1, { unsignedlongarg0 }, { to_value_t(3054ul) } }, + // "actual" long long and unsigned long long, from #6096 + // Note: '9223372036854775806' is the max value for 'long long'. + { "%lld", "9223372036854775805", 1, 1, { longlongarg0 }, { to_value_t(9223372036854775805LL) } }, + { "%llu", "9223372036854775810", 1, 1, { unsignedlonglongarg0 }, { to_value_t(9223372036854775810ULL) } }, }; bool g_any_failed = false; |