Compare commits

...

2 Commits

Author SHA1 Message Date
Vito
943c92ca1e perf: Dispatch hasInvalidAmount on type tag instead of dynamic_cast
hasInvalidAmount runs on the per-transaction invariant-checking path
(ValidAmounts::finalize) and at preflight, walking every field of every
modified entry. The previous implementation tried a dynamic_cast chain
(STAmount, STObject, STArray) on each field, so every scalar non-amount
field paid three failed RTTI casts.

Dispatch on the serialized type tag via getSType() and a switch instead.
The object-like tags all denote STObject subclasses (STLedgerEntry, STTx),
so the downcast is sound; safeDowncast keeps a dynamic_cast validity
assert in debug builds while compiling to static_cast in release.
2026-06-04 15:27:22 +02:00
Ayaz Salikhov
6c543426c3 ci: Fix clang asan include dirs in nix images, add curl & gnupg (#7400) 2026-06-03 22:19:15 +00:00
6 changed files with 41 additions and 7 deletions

View File

@@ -134,6 +134,7 @@ words:
- iou
- ious
- isrdc
- isystem
- itype
- jemalloc
- jlog

View File

@@ -8,11 +8,13 @@ clang++ --version
clang-format --version
cmake --version
conan --version
curl --version
g++ --version
gcc --version
gcov --version
gcovr --version
git --version
gpg --version
less --version
make --version
mold --version

View File

@@ -2,6 +2,13 @@
#include <cstddef>
#include <iostream>
// Regression test: the compiler-rt sanitizer interface headers must be on the
// include path. A bare on-PATH clang in the Nix CI env doesn't get them
// propagated automatically, so this include would fail to compile with clang++
// if the env isn't wired up correctly. abseil hits the same include during
// sanitizer builds. LeakSanitizer ships with AddressSanitizer.
#include <sanitizer/lsan_interface.h>
#if defined(__clang__) || defined(__GNUC__)
__attribute__((noinline))
#elif defined(_MSC_VER)

View File

@@ -94,6 +94,14 @@ let
ln -s "${customCompilerRt.out}/lib" "$rsrc/lib"
ln -s "${customCompilerRt.out}/share" "$rsrc/share" || true
echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
# compiler-rt ships the sanitizer/profile/xray interface headers (e.g.
# <sanitizer/lsan_interface.h>) in its `dev` output. In a normal Nix
# build these reach the include path because compiler-rt is propagated
# via depsTargetTargetPropagated and stdenv's setup hooks add its
# dev/include. The CI image runs clang outside a Nix stdenv (binaries
# on PATH, no setup hooks), so that never happens; add the headers
# explicitly. gcc ships its own copy, which is why this is clang-only.
echo "-isystem ${customCompilerRt.dev}/include" >> $out/nix-support/cc-cflags
'';
};

View File

@@ -11,9 +11,11 @@ in
ccache
cmake
conan
curlMinimal # needed for codecov/codecov-action
gcovr
git
gnumake
gnupg # needed for signing commits & codecov/codecov-action
llvmPackages_22.clang-tools
less # needed for git diff
mold

View File

@@ -1250,16 +1250,30 @@ hasInvalidAmount(STBase const& field, int depth, beast::Journal j)
return true;
}
if (auto const amount = dynamic_cast<STAmount const*>(&field))
return !isLegalMPT(*amount) || !isLegalNet(*amount);
// Dispatch on the serialized type tag rather than RTTI: this is on the invariant-checking path
// and a dynamic_cast chain over every field of every modified entry is measurably expensive.
// The object-like tags below all denote STObject subclasses (STLedgerEntry, STTx), so the
// downcast is sound; nested fields are only ever plain STI_OBJECT / STI_ARRAY containers.
// safeDowncast keeps a dynamic_cast validity assert in debug builds while compiling to
// static_cast in release.
switch (field.getSType())
{
case STI_AMOUNT: {
auto const& amount = safeDowncast<STAmount const&>(field);
return !isLegalMPT(amount) || !isLegalNet(amount);
}
if (auto const object = dynamic_cast<STObject const*>(&field))
return hasInvalidAmount(*object, depth + 1, j);
case STI_OBJECT:
case STI_LEDGERENTRY:
case STI_TRANSACTION:
return hasInvalidAmount(safeDowncast<STObject const&>(field), depth + 1, j);
if (auto const array = dynamic_cast<STArray const*>(&field))
return hasInvalidAmount(*array, depth + 1, j);
case STI_ARRAY:
return hasInvalidAmount(safeDowncast<STArray const&>(field), depth + 1, j);
return false;
default:
return false;
}
}
bool