From 15346114ef67e69650fbfc996616b4d1f2eeaf0b Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 12 Feb 2023 16:21:48 +0900 Subject: [PATCH 1/5] fix: allow long binary integer and leading zeros --- toml/parser.hpp | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index 06e0324..da4b551 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -57,20 +57,42 @@ parse_binary_integer(location& loc) { auto str = token.unwrap().str(); assert(str.size() > 2); // minimum -> 0b1 - if(64 <= str.size()) + assert(str.at(0) == '0' && str.at(1) == 'b'); + + // skip all the zeros and `_` locating at the MSB + str.erase(str.begin(), std::find_if( + str.begin() + 2, // to skip prefix `0b` + str.end(), + [](const char c) { return c == '1'; }) + ); + assert(str.empty() || str.front() == '1'); + + // since toml11 uses int64_t, 64bit (unsigned) input cannot be read. + if(64 + std::count(str.begin(), str.end(), '_') <= str.size()) { - // since toml11 uses int64_t, 64bit (unsigned) input cannot be read. loc.reset(first); - return err(format_underline("toml::parse_binary_integer:", - {{source_location(loc), "too large input (> int64_t)"}})); + return err(format_underline("toml::parse_binary_integer: " + "only signed 64bit integer is available", + {{source_location(loc), "too large input (> int64_t)"}})); } + integer retval(0), base(1); - for(auto i(str.rbegin()), e(str.rend() - 2); i!=e; ++i) + for(auto i(str.rbegin()), e(str.rend()); i!=e; ++i) { - if (*i == '1'){retval += base; base *= 2;} - else if(*i == '0'){base *= 2;} - else if(*i == '_'){/* do nothing. */} - else // internal error. + if(*i == '1') + { + retval += base; + base *= 2; + } + else if(*i == '0') + { + base *= 2; + } + else if(*i == '_') + { + // do nothing. + } + else // should be detected by lex_bin_int. [[unlikely]] { throw internal_error(format_underline( "toml::parse_binary_integer: internal error", From 418bfe911781a1243e1b4af119f9f1dcee433e73 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 12 Feb 2023 16:44:18 +0900 Subject: [PATCH 2/5] fix: cast explicitly to avoid un/signed comparison --- toml/parser.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index da4b551..fb6cb5c 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -68,7 +68,8 @@ parse_binary_integer(location& loc) assert(str.empty() || str.front() == '1'); // since toml11 uses int64_t, 64bit (unsigned) input cannot be read. - if(64 + std::count(str.begin(), str.end(), '_') <= str.size()) + const auto max_length = 63 + std::count(str.begin(), str.end(), '_'); + if(static_cast(max_length) < str.size()) { loc.reset(first); return err(format_underline("toml::parse_binary_integer: " From 51587338cdadbb5d79007697d293bb5f426cd0fb Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 12 Feb 2023 18:50:46 +0900 Subject: [PATCH 3/5] fix: avoid overflow at postproc of the last loop --- toml/parser.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/toml/parser.hpp b/toml/parser.hpp index fb6cb5c..55dfe51 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -80,13 +80,22 @@ parse_binary_integer(location& loc) integer retval(0), base(1); for(auto i(str.rbegin()), e(str.rend()); i!=e; ++i) { + assert(base != 0); // means overflow, checked in the above code if(*i == '1') { retval += base; + if(std::numeric_limits::max() / 2 < base) + { + base = 0; + } base *= 2; } else if(*i == '0') { + if(std::numeric_limits::max() / 2 < base) + { + base = 0; + } base *= 2; } else if(*i == '_') From fd969a679b4a008526d4853a7c98254268b4fc0c Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 12 Feb 2023 19:03:59 +0900 Subject: [PATCH 4/5] test: check if a large bin ints are parsed --- tests/test_parse_integer.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/test_parse_integer.cpp b/tests/test_parse_integer.cpp index 423961f..4a86226 100644 --- a/tests/test_parse_integer.cpp +++ b/tests/test_parse_integer.cpp @@ -84,6 +84,22 @@ BOOST_AUTO_TEST_CASE(test_bin_value) TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0b010000", value(16)); TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0b01_00_00", value(16)); TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, "0b111111", value(63)); + + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "0b1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000", + // 1 0 0 0 + // 0 C 8 4 + value(0x0888888888888888)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "0b01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111", + // 1 0 0 0 + // 0 C 8 4 + value(0x7FFFFFFFFFFFFFFF)); + TOML11_TEST_PARSE_EQUAL_VALUE(parse_value, + "0b00000000_01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111", + // 1 0 0 0 + // 0 C 8 4 + value(0x7FFFFFFFFFFFFFFF)); } BOOST_AUTO_TEST_CASE(test_integer_overflow) @@ -91,7 +107,8 @@ BOOST_AUTO_TEST_CASE(test_integer_overflow) std::istringstream dec_overflow(std::string("dec-overflow = 9223372036854775808")); std::istringstream hex_overflow(std::string("hex-overflow = 0x1_00000000_00000000")); std::istringstream oct_overflow(std::string("oct-overflow = 0o1_000_000_000_000_000_000_000")); - std::istringstream bin_overflow(std::string("bin-overflow = 0b1_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000")); + // 64 56 48 40 32 24 16 8 + std::istringstream bin_overflow(std::string("bin-overflow = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000")); BOOST_CHECK_THROW(toml::parse(dec_overflow), toml::syntax_error); BOOST_CHECK_THROW(toml::parse(hex_overflow), toml::syntax_error); BOOST_CHECK_THROW(toml::parse(oct_overflow), toml::syntax_error); From ce941c318b1b8b361570405aa1c7e00a53b2b4c4 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 12 Feb 2023 20:27:14 +0900 Subject: [PATCH 5/5] fix: prevent windows minmax macro --- toml/parser.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index 55dfe51..8cdd2ce 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -84,7 +84,7 @@ parse_binary_integer(location& loc) if(*i == '1') { retval += base; - if(std::numeric_limits::max() / 2 < base) + if( (std::numeric_limits::max)() / 2 < base ) { base = 0; } @@ -92,7 +92,7 @@ parse_binary_integer(location& loc) } else if(*i == '0') { - if(std::numeric_limits::max() / 2 < base) + if( (std::numeric_limits::max)() / 2 < base ) { base = 0; }