// OpenVPN -- An application to securely tunnel IP networks // over a single port, with support for SSL/TLS-based // session authentication and key exchange, // packet encryption, packet authentication, and // packet compression. // // Copyright (C) 2023 OpenVPN Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License Version 3 // as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program in the COPYING file. // If not, see . #pragma once #include "numeric_util.hpp" #include #include #include // For OPENVPN_EXCEPTION_INHERIT /*** * @brief Exception type for numeric conversion failures */ OPENVPN_EXCEPTION_INHERIT(std::range_error, numeric_out_of_range); namespace openvpn::numeric_util { /* ============================================================================================================= */ // numeric_cast /* ============================================================================================================= */ /** * @brief Tests attempted casts to ensure the input value does not exceed the capacity of the output type * * If the types are the same, or the range of the output type equals or exceeds the range of the input type * we just cast and return the value which should ideally optimize away completely. Otherwise we do appropriate * range checks and if those succeed we cast, otherwise the failure exception openvpn::numeric_out_of_range * is thrown. * * Example: * * int64_t s64 = std::numeric_limits::max(); * EXPECT_THROW(numeric_cast(s64), numeric_out_of_range); * * @param inVal The value to be converted. * @return The safely converted inVal. * @tparam InT Source (input) type, inferred from 'inVal' * @tparam OutT Desired result type */ template OutT numeric_cast(InT inVal) { if constexpr (!numeric_util::is_int_rangesafe() && numeric_util::is_int_u2s()) { // Conversion to uintmax_t should be safe for ::max() in all integral cases if (static_cast(inVal) > static_cast(std::numeric_limits::max())) { throw numeric_out_of_range("Range exceeded for unsigned --> signed integer conversion"); } } else if constexpr (!numeric_util::is_int_rangesafe() && numeric_util::is_int_s2u()) { // Cast to uintmax_t only applied if inVal is positive ... if (inVal < 0 || static_cast(inVal) > static_cast(std::numeric_limits::max())) { throw numeric_out_of_range("Range exceeded for signed --> unsigned integer conversion"); } } else if constexpr (!numeric_util::is_int_rangesafe()) { // We already know the in and out are sign compatible if (std::numeric_limits::min() > inVal || std::numeric_limits::max() < inVal) { throw numeric_out_of_range("Range exceeded for integer conversion"); } } return static_cast(inVal); } } // namespace openvpn::numeric_util