From f52da8e8e10fe19e9a86ff725310cebb5a6dcb1a Mon Sep 17 00:00:00 2001 From: fhgffy <102001626+fhgffy@users.noreply.github.com> Date: Fri, 9 Oct 2026 08:28:40 +0800 Subject: [PATCH] Reject trailing characters when parsing rfl::Timestamp strptime() stops at the end of the format and returns a pointer to whatever is left, but only a NULL result was treated as an error, so "1987-04-19T10:00:00" was accepted for "%Y-%m-%d" and the rest was silently dropped. Require the whole string to be consumed. The Windows fallback also returned _s + tellg() when the stream hit EOF, where tellg() is -1; return the end of the string in that case, as ParserTimePoint already does. --- include/rfl/Timestamp.hpp | 10 ++++++++-- tests/json/test_timestamp.cpp | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/rfl/Timestamp.hpp b/include/rfl/Timestamp.hpp index 5c15122b1..a940e0fcb 100644 --- a/include/rfl/Timestamp.hpp +++ b/include/rfl/Timestamp.hpp @@ -1,6 +1,7 @@ #ifndef RFL_TIMESTAMP_HPP_ #define RFL_TIMESTAMP_HPP_ +#include #include #include #include @@ -35,7 +36,7 @@ class Timestamp { /// @throws std::runtime_error if the string doesn't match the format Timestamp(const char* _str) : tm_(std::tm{}) { const auto r = strptime(_str, _format.str().c_str(), &tm_); - if (r == NULL) { + if (r == NULL || *r != '\0') { throw std::runtime_error("String '" + std::string(_str) + "' did not match format '" + Format().str() + "'."); @@ -169,7 +170,12 @@ class Timestamp { if (input.fail()) { return NULL; } - return (char*)(_s + input.tellg()); + const auto pos = input.tellg(); + if (pos == std::streampos(-1)) { + // The stream reached EOF, so all of the input was consumed. + return (char*)(_s + std::strlen(_s)); + } + return (char*)(_s + static_cast(pos)); } #endif diff --git a/tests/json/test_timestamp.cpp b/tests/json/test_timestamp.cpp index 0c91fb744..f4a237a5d 100644 --- a/tests/json/test_timestamp.cpp +++ b/tests/json/test_timestamp.cpp @@ -25,4 +25,13 @@ TEST(json, test_timestamp) { bart, R"({"firstName":"Bart","lastName":"Simpson","birthday":"1987-04-19"})"); } + +TEST(json, test_timestamp_trailing_characters) { + EXPECT_TRUE(!TS::from_string("1987-04-19T10:00:00")); + EXPECT_TRUE(!TS::from_string("1987-04-19x")); + + const auto res = rfl::json::read( + R"({"firstName":"Bart","lastName":"Simpson","birthday":"1987-04-19x"})"); + EXPECT_TRUE(!res); +} } // namespace test_timestamp