Skip to content

Commit c50c869

Browse files
committed
feat core: do not allow parsing Inf and NaN
Tests: протестировано CI commit_hash:952319cbe41f5dad6b4d617a24b917511f5e956e
1 parent e5ee060 commit c50c869

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

universal/include/userver/formats/parse/common.hpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ void CheckInBounds(const Value& value, T x, T min, T max) {
3737

3838
template <typename Value>
3939
void CheckDoubleFitsInFloat(const Value& value, const double dval) {
40-
if (std::isinf(dval) || std::isnan(dval)) {
41-
// double infinity and NaN are directly convertible to float infinity and NaN
42-
return;
40+
if (!std::isfinite(dval)) {
41+
auto msg = fmt::format(
42+
"Double value ({}) of '{}' is prohibited for use. Inf and NaN values lead to vulnerabilities in code",
43+
dval,
44+
value.GetPath()
45+
);
46+
UASSERT_MSG(false, msg);
47+
throw typename Value::ParseException(std::move(msg));
4348
}
4449

4550
auto fval = static_cast<float>(dval);
@@ -53,7 +58,7 @@ void CheckDoubleFitsInFloat(const Value& value, const double dval) {
5358

5459
template <typename Value>
5560
float NarrowToFloat(double x, const Value& value) {
56-
CheckDoubleFitsInFloat(value, x);
61+
impl::CheckDoubleFitsInFloat(value, x);
5762
return static_cast<float>(x);
5863
}
5964

universal/src/formats/common/value_test.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,29 @@ TYPED_TEST_P(Parsing, MaxMinFloat) {
220220
EXPECT_EQ(float_negative_min.template As<float>(), -kFloatMin);
221221
}
222222

223+
TYPED_TEST_P(Parsing, InfNanFloatDouble) {
224+
// May abort in test builds
225+
#ifdef NDEBUG
226+
using Value = std::decay_t<decltype(this->kFromString(""))>;
227+
using Exception = typename Value::Exception;
228+
229+
constexpr float kFloatInf = std::numeric_limits<float>::infinity();
230+
constexpr float kFloatNan = std::numeric_limits<float>::quiet_NaN();
231+
232+
EXPECT_THROW(this->kFromString(fmt::format("[{}]", kFloatInf))[0].template As<float>(), Exception);
233+
EXPECT_THROW(this->kFromString(fmt::format("[{}]", -kFloatInf))[0].template As<float>(), Exception);
234+
EXPECT_THROW(this->kFromString(fmt::format("[{}]", kFloatNan))[0].template As<float>(), Exception);
235+
EXPECT_THROW(this->kFromString(fmt::format("[{}]", -kFloatNan))[0].template As<float>(), Exception);
236+
237+
constexpr double kDoubleInf = std::numeric_limits<double>::infinity();
238+
constexpr double kDoubleNan = std::numeric_limits<double>::quiet_NaN();
239+
EXPECT_THROW(this->kFromString(fmt::format("[{}]", kDoubleInf))[0].template As<double>(), Exception);
240+
EXPECT_THROW(this->kFromString(fmt::format("[{}]", -kDoubleInf))[0].template As<double>(), Exception);
241+
EXPECT_THROW(this->kFromString(fmt::format("[{}]", kDoubleNan))[0].template As<double>(), Exception);
242+
EXPECT_THROW(this->kFromString(fmt::format("[{}]", -kDoubleNan))[0].template As<double>(), Exception);
243+
#endif
244+
}
245+
223246
TYPED_TEST_P(Parsing, UserProvidedCommonParser) {
224247
auto value = this->kFromString("[42]")[0];
225248

@@ -394,6 +417,7 @@ REGISTER_TYPED_TEST_SUITE_P(
394417
UInt,
395418
IntOverflow,
396419
MaxMinFloat,
420+
InfNanFloatDouble,
397421
UserProvidedCommonParser,
398422

399423
ChronoDoubleSeconds,

0 commit comments

Comments
 (0)