Skip to content

Commit

Permalink
Add safe_cast
Browse files Browse the repository at this point in the history
* Ensure no overflow in casts between enums and integral types.
* Fixes: RIPD-1702
  • Loading branch information
HowardHinnant committed Jan 11, 2019
1 parent dfb45ba commit a7e4541
Show file tree
Hide file tree
Showing 35 changed files with 213 additions and 86 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,7 @@ install (
src/ripple/basics/FileUtilities.h
src/ripple/basics/LocalValue.h
src/ripple/basics/Log.h
src/ripple/basics/safe_cast.h
src/ripple/basics/Slice.h
src/ripple/basics/StringUtilities.h
src/ripple/basics/ToString.h
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/app/main/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <ripple/app/tx/apply.h>
#include <ripple/basics/ByteUtilities.h>
#include <ripple/basics/ResolverAsio.h>
#include <ripple/basics/safe_cast.h>
#include <ripple/basics/Sustain.h>
#include <ripple/basics/PerfLog.h>
#include <ripple/json/json_reader.h>
Expand Down Expand Up @@ -1068,7 +1069,7 @@ class ApplicationImp
*db << "PRAGMA page_count;", soci::into(pageCount);
std::uint32_t freePages = maxPages - pageCount;
std::uint64_t freeSpace =
static_cast<std::uint64_t>(freePages) * pageSize;
safe_cast<std::uint64_t>(freePages) * pageSize;
JLOG(m_journal.info())
<< "Transaction DB pathname: " << dbPath.string()
<< "; file size: " << dbSize.value_or(-1) << " bytes"
Expand Down
7 changes: 4 additions & 3 deletions src/ripple/app/misc/NetworkOPs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <ripple/basics/base64.h>
#include <ripple/basics/mulDiv.h>
#include <ripple/basics/PerfLog.h>
#include <ripple/basics/safe_cast.h>
#include <ripple/basics/UptimeClock.h>
#include <ripple/core/ConfigSections.h>
#include <ripple/crypto/csprng.h>
Expand Down Expand Up @@ -1664,7 +1665,7 @@ void NetworkOPsImp::pubServer ()
if(f.em)
{
auto const loadFactor =
std::max(static_cast<std::uint64_t>(f.loadFactorServer),
std::max(safe_cast<std::uint64_t>(f.loadFactorServer),
mulDiv(f.em->openLedgerFeeLevel, f.loadBaseServer,
f.em->referenceFeeLevel).second);

Expand Down Expand Up @@ -2121,7 +2122,7 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin, bool counters)
{
if (when)
info[jss::validator_list_expires] =
static_cast<Json::UInt>(when->time_since_epoch().count());
safe_cast<Json::UInt>(when->time_since_epoch().count());
else
info[jss::validator_list_expires] = 0;
}
Expand Down Expand Up @@ -2227,7 +2228,7 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin, bool counters)
auto const loadBaseFeeEscalation =
escalationMetrics.referenceFeeLevel;

auto const loadFactor = std::max(static_cast<std::uint64_t>(loadFactorServer),
auto const loadFactor = std::max(safe_cast<std::uint64_t>(loadFactorServer),
mulDiv(loadFactorFeeEscalation, loadBaseServer, loadBaseFeeEscalation).second);

if (!human)
Expand Down
5 changes: 3 additions & 2 deletions src/ripple/app/misc/impl/LoadFeeTrack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <ripple/app/misc/LoadFeeTrack.h>
#include <ripple/basics/contract.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/safe_cast.h>
#include <ripple/core/Config.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/protocol/STAmount.h>
Expand Down Expand Up @@ -149,8 +150,8 @@ scaleFeeLoad(std::uint64_t fee, LoadFeeTrack const& feeTrack,
// The denominator of the fraction we're trying to compute.
// fees.units and lftNormalFee are both 32 bit,
// so the multiplication can't overflow.
auto den = static_cast<std::uint64_t>(fees.units)
* static_cast<std::uint64_t>(feeTrack.getLoadBase());
auto den = safe_cast<std::uint64_t>(fees.units)
* safe_cast<std::uint64_t>(feeTrack.getLoadBase());
// Reduce fee * baseFee * feeFactor / (fees.units * lftNormalFee)
// to lowest terms.
lowestTerms(fee, den);
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/app/tx/impl/Escrow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <ripple/app/misc/HashRouter.h>
#include <ripple/basics/chrono.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/safe_cast.h>
#include <ripple/conditions/Condition.h>
#include <ripple/conditions/Fulfillment.h>
#include <ripple/ledger/ApplyView.h>
Expand Down Expand Up @@ -358,7 +359,7 @@ EscrowFinish::calculateBaseFee (
if (auto const fb = tx[~sfFulfillment])
{
extraFee += view.fees().units *
(32 + static_cast<std::uint64_t> (fb->size() / 16));
(32 + safe_cast<std::uint64_t> (fb->size() / 16));
}

return Transactor::calculateBaseFee (view, tx) + extraFee;
Expand Down
5 changes: 3 additions & 2 deletions src/ripple/basics/impl/Sustain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
//==============================================================================

#include <ripple/basics/safe_cast.h>
#include <ripple/basics/Sustain.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <boost/format.hpp>
Expand All @@ -41,8 +42,8 @@ namespace ripple {
static auto const sleepBeforeWaiting = 10;
static auto const sleepBetweenWaits = 1;

static pid_t pManager = static_cast<pid_t> (0);
static pid_t pChild = static_cast<pid_t> (0);
static pid_t pManager = safe_cast<pid_t> (0);
static pid_t pChild = safe_cast<pid_t> (0);

static void pass_signal (int a)
{
Expand Down
78 changes: 78 additions & 0 deletions src/ripple/basics/safe_cast.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2018 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================

#ifndef RIPPLE_BASICS_SAFE_CAST_H_INCLUDED
#define RIPPLE_BASICS_SAFE_CAST_H_INCLUDED

#include <type_traits>

namespace ripple {

// safe_cast adds compile-time checks to a static_cast to ensure that
// the destination can hold all values of the source. This is particularly
// handy when the source or destination is an enumeration type.

template <class Dest, class Src>
inline
constexpr
std::enable_if_t
<
std::is_integral<Dest>::value && std::is_integral<Src>::value,
Dest
>
safe_cast(Src s) noexcept
{
static_assert(std::is_signed<Dest>::value || std::is_unsigned<Src>::value,
"Cannot cast signed to unsigned");
constexpr unsigned not_same = std::is_signed<Dest>::value !=
std::is_signed<Src>::value;
static_assert(sizeof(Dest) >= sizeof(Src) + not_same,
"Destination is too small to hold all values of source");
return static_cast<Dest>(s);
}

template <class Dest, class Src>
inline
constexpr
std::enable_if_t
<
std::is_enum<Dest>::value && std::is_integral<Src>::value,
Dest
>
safe_cast(Src s) noexcept
{
return static_cast<Dest>(safe_cast<std::underlying_type_t<Dest>>(s));
}

template <class Dest, class Src>
inline
constexpr
std::enable_if_t
<
std::is_integral<Dest>::value && std::is_enum<Src>::value,
Dest
>
safe_cast(Src s) noexcept
{
return safe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
}

} // ripple

#endif
14 changes: 8 additions & 6 deletions src/ripple/conditions/impl/Fulfillment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
//==============================================================================

#include <ripple/basics/safe_cast.h>
#include <ripple/conditions/Condition.h>
#include <ripple/conditions/Fulfillment.h>
#include <ripple/conditions/impl/PreimageSha256.h>
Expand Down Expand Up @@ -116,31 +117,32 @@ Fulfillment::deserialize(

std::unique_ptr<Fulfillment> f;

switch (static_cast<Type>(p.tag))
using TagType = decltype(p.tag);
switch (p.tag)
{
case Type::preimageSha256:
case safe_cast<TagType>(Type::preimageSha256):
f = PreimageSha256::deserialize(Slice(s.data(), p.length), ec);
if (ec)
return {};
s += p.length;
break;

case Type::prefixSha256:
case safe_cast<TagType>(Type::prefixSha256):
ec = error::unsupported_type;
return {};
break;

case Type::thresholdSha256:
case safe_cast<TagType>(Type::thresholdSha256):
ec = error::unsupported_type;
return {};
break;

case Type::rsaSha256:
case safe_cast<TagType>(Type::rsaSha256):
ec = error::unsupported_type;
return {};
break;

case Type::ed25519Sha256:
case safe_cast<TagType>(Type::ed25519Sha256):
ec = error::unsupported_type;
return {};

Expand Down
5 changes: 3 additions & 2 deletions src/ripple/conditions/impl/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
//==============================================================================

#include <ripple/basics/safe_cast.h>
#include <ripple/conditions/impl/error.h>
#include <system_error>
#include <string>
Expand All @@ -41,7 +42,7 @@ class cryptoconditions_error_category
std::string
message(int ev) const override
{
switch (static_cast<error>(ev))
switch (safe_cast<error>(ev))
{
case error::unsupported_type:
return "Specification: Requested type not supported.";
Expand Down Expand Up @@ -136,7 +137,7 @@ std::error_code
make_error_code(error ev)
{
return std::error_code {
static_cast<std::underlying_type<error>::type>(ev),
safe_cast<std::underlying_type<error>::type>(ev),
detail::get_cryptoconditions_error_category()
};
}
Expand Down
24 changes: 13 additions & 11 deletions src/ripple/ledger/ApplyView.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
#ifndef RIPPLE_LEDGER_APPLYVIEW_H_INCLUDED
#define RIPPLE_LEDGER_APPLYVIEW_H_INCLUDED

#include <ripple/basics/safe_cast.h>
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
#include <boost/optional.hpp>

namespace ripple {

enum ApplyFlags
: std::uint32_t
{
tapNONE = 0x00,

Expand All @@ -48,24 +50,24 @@ ApplyFlags
operator|(ApplyFlags const& lhs,
ApplyFlags const& rhs)
{
return static_cast<ApplyFlags>(
static_cast<std::underlying_type_t<ApplyFlags>>(lhs) |
static_cast<std::underlying_type_t<ApplyFlags>>(rhs));
return safe_cast<ApplyFlags>(
safe_cast<std::underlying_type_t<ApplyFlags>>(lhs) |
safe_cast<std::underlying_type_t<ApplyFlags>>(rhs));
}

static_assert((tapPREFER_QUEUE | tapRETRY) == static_cast<ApplyFlags>(0x60),
static_assert((tapPREFER_QUEUE | tapRETRY) == safe_cast<ApplyFlags>(0x60u),
"ApplyFlags operator |");
static_assert((tapRETRY | tapPREFER_QUEUE) == static_cast<ApplyFlags>(0x60),
static_assert((tapRETRY | tapPREFER_QUEUE) == safe_cast<ApplyFlags>(0x60u),
"ApplyFlags operator |");

constexpr
ApplyFlags
operator&(ApplyFlags const& lhs,
ApplyFlags const& rhs)
{
return static_cast<ApplyFlags>(
static_cast<std::underlying_type_t<ApplyFlags>>(lhs) &
static_cast<std::underlying_type_t<ApplyFlags>>(rhs));
return safe_cast<ApplyFlags>(
safe_cast<std::underlying_type_t<ApplyFlags>>(lhs) &
safe_cast<std::underlying_type_t<ApplyFlags>>(rhs));
}

static_assert((tapPREFER_QUEUE & tapRETRY) == tapNONE,
Expand All @@ -77,11 +79,11 @@ constexpr
ApplyFlags
operator~(ApplyFlags const& flags)
{
return static_cast<ApplyFlags>(
~static_cast<std::underlying_type_t<ApplyFlags>>(flags));
return safe_cast<ApplyFlags>(
~safe_cast<std::underlying_type_t<ApplyFlags>>(flags));
}

static_assert(~tapRETRY == static_cast<ApplyFlags>(~0x20),
static_assert(~tapRETRY == safe_cast<ApplyFlags>(0xFFFFFFDFu),
"ApplyFlags operator ~");

inline
Expand Down
5 changes: 3 additions & 2 deletions src/ripple/ledger/CashDiff.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#ifndef RIPPLE_LEDGER_CASHDIFF_H_INCLUDED
#define RIPPLE_LEDGER_CASHDIFF_H_INCLUDED

#include <ripple/basics/safe_cast.h>
#include <ripple/protocol/STAmount.h>
#include <memory> // std::unique_ptr

Expand All @@ -44,13 +45,13 @@ inline CashFilter operator| (CashFilter lhs, CashFilter rhs)
{
using ul_t = std::underlying_type<CashFilter>::type;
return static_cast<CashFilter>(
static_cast<ul_t>(lhs) | static_cast<ul_t>(rhs));
safe_cast<ul_t>(lhs) | safe_cast<ul_t>(rhs));
}
inline CashFilter operator& (CashFilter lhs, CashFilter rhs)
{
using ul_t = std::underlying_type<CashFilter>::type;
return static_cast<CashFilter>(
static_cast<ul_t>(lhs) & static_cast<ul_t>(rhs));
safe_cast<ul_t>(lhs) & safe_cast<ul_t>(rhs));
}

//------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions src/ripple/nodestore/NodeObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace ripple {

/** The types of node objects. */
enum NodeObjectType
: std::uint32_t
{
hotUNKNOWN = 0,
hotLEDGER = 1,
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/nodestore/impl/DecodedBlob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
//==============================================================================

#include <ripple/basics/safe_cast.h>
#include <ripple/nodestore/impl/DecodedBlob.h>
#include <algorithm>
#include <cassert>
Expand Down Expand Up @@ -48,7 +49,7 @@ DecodedBlob::DecodedBlob (void const* key, void const* value, int valueBytes)
if (valueBytes > 8)
{
unsigned char const* byte = static_cast <unsigned char const*> (value);
m_objectType = static_cast <NodeObjectType> (byte [8]);
m_objectType = safe_cast <NodeObjectType> (byte [8]);
}

if (valueBytes > 9)
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/overlay/impl/Message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
//==============================================================================

#include <ripple/basics/safe_cast.h>
#include <ripple/overlay/Message.h>
#include <ripple/overlay/impl/TrafficCount.h>
#include <cstdint>
Expand All @@ -38,7 +39,7 @@ Message::Message (::google::protobuf::Message const& message, int type)
message.SerializeToArray (&mBuffer [Message::kHeaderBytes], messageBytes);
}

mCategory = static_cast<int>(TrafficCount::categorize
mCategory = safe_cast<int>(TrafficCount::categorize
(message, type, false));
}

Expand Down
Loading

0 comments on commit a7e4541

Please sign in to comment.