mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-23 15:10:34 +00:00
fix ubsan
This commit is contained in:
@@ -15,6 +15,9 @@
|
||||
|
||||
#include <secp256k1_mpt.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
@@ -61,10 +64,12 @@ struct EcPair
|
||||
inline void
|
||||
incrementConfidentialVersion(STObject& mptoken)
|
||||
{
|
||||
// Retrieve current version and increment.
|
||||
// Unsigned integer overflow is defined behavior in C++ (wraps to 0),
|
||||
// which is acceptable here.
|
||||
mptoken[sfConfidentialBalanceVersion] = mptoken[~sfConfidentialBalanceVersion].valueOr(0u) + 1u;
|
||||
// Retrieve current version and increment, wrapping back to 0 at UINT32_MAX.
|
||||
// The wrap is computed explicitly rather than relying on unsigned overflow
|
||||
// of `+ 1u`, as it trips the unsigned-integer-overflow sanitizer in the UBSan CI build.
|
||||
auto const current = mptoken[~sfConfidentialBalanceVersion].valueOr(0u);
|
||||
mptoken[sfConfidentialBalanceVersion] =
|
||||
current == std::numeric_limits<std::uint32_t>::max() ? 0u : current + 1u;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -506,10 +506,16 @@ ValidConfidentialMPToken::visitEntry(
|
||||
return beast::kZero;
|
||||
};
|
||||
|
||||
// Clamp to the cap (== INT64_MAX) before the signed conversion. We do INT64_MAX + 1
|
||||
// which the invariant tests inject, which would result in undefined behavior (under UBSan).
|
||||
auto const toSignedAmount = [](std::uint64_t v) -> std::int64_t {
|
||||
return static_cast<std::int64_t>(std::min(v, kMaxMpTokenAmount));
|
||||
};
|
||||
|
||||
if (before && before->getType() == ltMPTOKEN)
|
||||
{
|
||||
uint192 const id = getMptID(before);
|
||||
changes_[id].mptAmountDelta -= static_cast<std::int64_t>(before->getFieldU64(sfMPTAmount));
|
||||
changes_[id].mptAmountDelta -= toSignedAmount(before->getFieldU64(sfMPTAmount));
|
||||
|
||||
// Cannot delete MPToken with non-zero confidential state or non-zero public amount
|
||||
if (isDelete)
|
||||
@@ -527,7 +533,7 @@ ValidConfidentialMPToken::visitEntry(
|
||||
if (after && after->getType() == ltMPTOKEN)
|
||||
{
|
||||
uint192 const id = getMptID(after);
|
||||
changes_[id].mptAmountDelta += static_cast<std::int64_t>(after->getFieldU64(sfMPTAmount));
|
||||
changes_[id].mptAmountDelta += toSignedAmount(after->getFieldU64(sfMPTAmount));
|
||||
|
||||
// Encrypted field existence consistency
|
||||
bool const hasIssuerBalance = after->isFieldPresent(sfIssuerEncryptedBalance);
|
||||
@@ -565,10 +571,9 @@ ValidConfidentialMPToken::visitEntry(
|
||||
if (before->isFieldPresent(sfConfidentialOutstandingAmount))
|
||||
{
|
||||
changes_[id].coaDelta -=
|
||||
static_cast<std::int64_t>(before->getFieldU64(sfConfidentialOutstandingAmount));
|
||||
toSignedAmount(before->getFieldU64(sfConfidentialOutstandingAmount));
|
||||
}
|
||||
changes_[id].outstandingDelta -=
|
||||
static_cast<std::int64_t>(before->getFieldU64(sfOutstandingAmount));
|
||||
changes_[id].outstandingDelta -= toSignedAmount(before->getFieldU64(sfOutstandingAmount));
|
||||
}
|
||||
|
||||
if (after && after->getType() == ltMPTOKEN_ISSUANCE)
|
||||
@@ -581,9 +586,9 @@ ValidConfidentialMPToken::visitEntry(
|
||||
std::uint64_t const oa = after->getFieldU64(sfOutstandingAmount);
|
||||
|
||||
if (hasCOA)
|
||||
change.coaDelta += static_cast<std::int64_t>(coa);
|
||||
change.coaDelta += toSignedAmount(coa);
|
||||
|
||||
change.outstandingDelta += static_cast<std::int64_t>(oa);
|
||||
change.outstandingDelta += toSignedAmount(oa);
|
||||
change.issuance = after;
|
||||
|
||||
// COA <= OutstandingAmount
|
||||
|
||||
Reference in New Issue
Block a user