Compare commits

...

2 Commits

Author SHA1 Message Date
Ed Hennis
9076cbdd1f Merge remote-tracking branch 'XRPLF/develop' into ximinez/revert-coroutine2
* XRPLF/develop:
  fix: Change `Tuning::bookOffers` minimum limit to 1 (6812)
  chore: Make pre-commit line ending conversions work on Windows (6832) (6833)
  fix: Add description for `terLOCKED` error (6811)
  fix: Address AI reviewer comments for Permission Delegation (6675)
  refactor: Combine `AMMHelpers` and `AMMUtils` (6733)
  feat: Add MPT support to DEX (5285)
  fix: Handle WSClient write failure when server closes WebSocket (6671)
  ci: Change conditions for uploading artifacts in public/private/org repos (6734)
  refactor: Rename non-functional uses of `ripple(d)` to `xrpl(d)` (6676)
  refactor: Move more helper files into `libxrpl/ledger/helpers` (6731)
  fix: Minor RPC fixes (6730)
  fix: Prevent deletion of MPTokens with active escrow (6635)
  fix: Clamp VaultClawback to assetsAvailable for zero-amount clawback (6646)
  fix: Add assorted Lending Protocol fixes (6678)
  fix: Change variable signedness and correctly handle `std::optional` (6657)
  refactor: Reorganize RPC handler files (6628)
  chore: Update XRPLF/actions (6713)
  docs: Add explanatory comment to checkFee (6631)
  fix: Decouple reserve from fee in delegate payment (6568)
2026-04-10 12:18:08 -04:00
Ed Hennis
e003a57f07 Revert "fix: Switch to boost::coroutine2 (#6372)"
This reverts commit 983816248a.
2026-04-09 18:20:27 -04:00
9 changed files with 45 additions and 84 deletions

View File

@@ -76,7 +76,7 @@ jobs:
name: ${{ inputs.config_name }} name: ${{ inputs.config_name }}
runs-on: ${{ fromJSON(inputs.runs_on) }} runs-on: ${{ fromJSON(inputs.runs_on) }}
container: ${{ inputs.image != '' && inputs.image || null }} container: ${{ inputs.image != '' && inputs.image || null }}
timeout-minutes: ${{ inputs.sanitizers != '' && 360 || 60 }} timeout-minutes: 60
env: env:
# Use a namespace to keep the objects separate for each configuration. # Use a namespace to keep the objects separate for each configuration.
CCACHE_NAMESPACE: ${{ inputs.config_name }} CCACHE_NAMESPACE: ${{ inputs.config_name }}
@@ -227,17 +227,11 @@ jobs:
- name: Set sanitizer options - name: Set sanitizer options
if: ${{ !inputs.build_only && env.SANITIZERS_ENABLED == 'true' }} if: ${{ !inputs.build_only && env.SANITIZERS_ENABLED == 'true' }}
env:
CONFIG_NAME: ${{ inputs.config_name }}
run: | run: |
ASAN_OPTS="include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-asan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" echo "ASAN_OPTIONS=print_stacktrace=1:detect_container_overflow=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" >> ${GITHUB_ENV}
if [[ "${CONFIG_NAME}" == *gcc* ]]; then echo "TSAN_OPTIONS=second_deadlock_stack=1:halt_on_error=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV}
ASAN_OPTS="${ASAN_OPTS}:alloc_dealloc_mismatch=0" echo "UBSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV}
fi echo "LSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV}
echo "ASAN_OPTIONS=${ASAN_OPTS}" >> ${GITHUB_ENV}
echo "TSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-tsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV}
echo "UBSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV}
echo "LSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-lsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV}
- name: Run the separate tests - name: Run the separate tests
if: ${{ !inputs.build_only }} if: ${{ !inputs.build_only }}

View File

@@ -23,7 +23,7 @@ target_compile_definitions(
BOOST_FILESYSTEM_NO_DEPRECATED BOOST_FILESYSTEM_NO_DEPRECATED
> >
$<$<NOT:$<BOOL:${boost_show_deprecated}>>: $<$<NOT:$<BOOL:${boost_show_deprecated}>>:
BOOST_COROUTINES2_NO_DEPRECATION_WARNING BOOST_COROUTINES_NO_DEPRECATION_WARNING
BOOST_BEAST_ALLOW_DEPRECATED BOOST_BEAST_ALLOW_DEPRECATED
BOOST_FILESYSTEM_DEPRECATED BOOST_FILESYSTEM_DEPRECATED
> >

View File

@@ -7,7 +7,7 @@ find_package(
COMPONENTS COMPONENTS
chrono chrono
container container
context coroutine
date_time date_time
filesystem filesystem
json json
@@ -26,7 +26,7 @@ target_link_libraries(
Boost::headers Boost::headers
Boost::chrono Boost::chrono
Boost::container Boost::container
Boost::context Boost::coroutine
Boost::date_time Boost::date_time
Boost::filesystem Boost::filesystem
Boost::json Boost::json
@@ -38,26 +38,23 @@ target_link_libraries(
if(Boost_COMPILER) if(Boost_COMPILER)
target_link_libraries(xrpl_boost INTERFACE Boost::disable_autolinking) target_link_libraries(xrpl_boost INTERFACE Boost::disable_autolinking)
endif() endif()
if(SANITIZERS_ENABLED AND is_clang)
# GCC 14+ has a false positive -Wuninitialized warning in Boost.Coroutine2's # TODO: gcc does not support -fsanitize-blacklist...can we do something else for gcc ?
# state.hpp when compiled with -O3. This is due to GCC's intentional behavior if(NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers)
# change (Bug #98871, #119388) where warnings from inlined system header code get_target_property(
# are no longer suppressed by -isystem. The warning occurs in operator|= in Boost_INCLUDE_DIRS
# boost/coroutine2/detail/state.hpp when inlined from push_control_block::destroy(). Boost::headers
# See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119388 INTERFACE_INCLUDE_DIRECTORIES
if(is_gcc AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14) )
target_compile_options(xrpl_boost INTERFACE -Wno-uninitialized) endif()
endif() message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist")
file(
# Boost.Context's ucontext backend has ASAN fiber-switching annotations WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt
# (start/finish_switch_fiber) that are compiled in when BOOST_USE_ASAN is defined. "src:${Boost_INCLUDE_DIRS}/*"
# This tells ASAN about coroutine stack switches, preventing false positive )
# stack-use-after-scope errors. BOOST_USE_UCONTEXT ensures the ucontext backend target_compile_options(
# is selected (fcontext does not support ASAN annotations). opts
# These defines must match what Boost was compiled with (see conan/profiles/sanitizers). INTERFACE # ignore boost headers for sanitizing
if(enable_asan) -fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt
target_compile_definitions(
xrpl_boost
INTERFACE BOOST_USE_ASAN BOOST_USE_UCONTEXT
) )
endif() endif()

View File

@@ -7,21 +7,16 @@ include(default)
{% if compiler == "gcc" %} {% if compiler == "gcc" %}
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %} {% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
{% set sanitizer_list = [] %} {% set sanitizer_list = [] %}
{% set defines = [] %}
{% set model_code = "" %} {% set model_code = "" %}
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1", "-Wno-stringop-overflow"] %} {% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1", "-Wno-stringop-overflow"] %}
{% if "address" in sanitizers %} {% if "address" in sanitizers %}
{% set _ = sanitizer_list.append("address") %} {% set _ = sanitizer_list.append("address") %}
{% set model_code = "-mcmodel=large" %} {% set model_code = "-mcmodel=large" %}
{% set _ = defines.append("BOOST_USE_ASAN")%}
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
{% elif "thread" in sanitizers %} {% elif "thread" in sanitizers %}
{% set _ = sanitizer_list.append("thread") %} {% set _ = sanitizer_list.append("thread") %}
{% set model_code = "-mcmodel=medium" %} {% set model_code = "-mcmodel=medium" %}
{% set _ = extra_cxxflags.append("-Wno-tsan") %} {% set _ = extra_cxxflags.append("-Wno-tsan") %}
{% set _ = defines.append("BOOST_USE_TSAN")%}
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
{% endif %} {% endif %}
{% if "undefinedbehavior" in sanitizers %} {% if "undefinedbehavior" in sanitizers %}
@@ -34,22 +29,16 @@ include(default)
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}'] tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
tools.build:sharedlinkflags+=['{{sanitizer_flags}}'] tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
tools.build:exelinkflags+=['{{sanitizer_flags}}'] tools.build:exelinkflags+=['{{sanitizer_flags}}']
tools.build:defines+={{defines}}
{% endif %} {% endif %}
{% elif compiler == "apple-clang" or compiler == "clang" %} {% elif compiler == "apple-clang" or compiler == "clang" %}
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %} {% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
{% set sanitizer_list = [] %} {% set sanitizer_list = [] %}
{% set defines = [] %}
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1"] %} {% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1"] %}
{% if "address" in sanitizers %} {% if "address" in sanitizers %}
{% set _ = sanitizer_list.append("address") %} {% set _ = sanitizer_list.append("address") %}
{% set _ = defines.append("BOOST_USE_ASAN")%}
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
{% elif "thread" in sanitizers %} {% elif "thread" in sanitizers %}
{% set _ = sanitizer_list.append("thread") %} {% set _ = sanitizer_list.append("thread") %}
{% set _ = defines.append("BOOST_USE_TSAN")%}
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
{% endif %} {% endif %}
{% if "undefinedbehavior" in sanitizers %} {% if "undefinedbehavior" in sanitizers %}
@@ -63,24 +52,8 @@ include(default)
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}'] tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
tools.build:sharedlinkflags+=['{{sanitizer_flags}}'] tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
tools.build:exelinkflags+=['{{sanitizer_flags}}'] tools.build:exelinkflags+=['{{sanitizer_flags}}']
tools.build:defines+={{defines}}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endif %} {% endif %}
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags", "tools.build:defines"] tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags"]
[options]
{% if sanitizers %}
{% if "address" in sanitizers %}
# Build Boost.Context with ucontext backend (not fcontext) so that
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
# are compiled into the library. fcontext (assembly) has no ASAN support.
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
boost/*:without_context=False
# Boost stacktrace fails to build with some sanitizers
boost/*:without_stacktrace=True
{% endif %}
{% endif %}

View File

@@ -1,4 +1,3 @@
import os
import re import re
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
@@ -57,9 +56,6 @@ class Xrpl(ConanFile):
"tests": False, "tests": False,
"unity": False, "unity": False,
"xrpld": False, "xrpld": False,
"boost/*:without_context": False,
"boost/*:without_coroutine": True,
"boost/*:without_coroutine2": False,
"date/*:header_only": True, "date/*:header_only": True,
"ed25519/*:shared": False, "ed25519/*:shared": False,
"grpc/*:shared": False, "grpc/*:shared": False,
@@ -129,12 +125,6 @@ class Xrpl(ConanFile):
if self.settings.compiler in ["clang", "gcc"]: if self.settings.compiler in ["clang", "gcc"]:
self.options["boost"].without_cobalt = True self.options["boost"].without_cobalt = True
# Check if environment variable exists
if "SANITIZERS" in os.environ:
sanitizers = os.environ["SANITIZERS"]
if "address" in sanitizers.lower():
self.default_options["fPIC"] = False
def requirements(self): def requirements(self):
self.requires("boost/1.90.0", force=True, transitive_headers=True) self.requires("boost/1.90.0", force=True, transitive_headers=True)
self.requires("date/3.0.4", transitive_headers=True) self.requires("date/3.0.4", transitive_headers=True)
@@ -201,7 +191,7 @@ class Xrpl(ConanFile):
"boost::headers", "boost::headers",
"boost::chrono", "boost::chrono",
"boost::container", "boost::container",
"boost::context", "boost::coroutine",
"boost::date_time", "boost::date_time",
"boost::filesystem", "boost::filesystem",
"boost::json", "boost::json",

View File

@@ -104,7 +104,6 @@ words:
- endmacro - endmacro
- exceptioned - exceptioned
- Falco - Falco
- fcontext
- finalizers - finalizers
- firewalled - firewalled
- fmtdur - fmtdur

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <xrpl/basics/ByteUtilities.h>
namespace xrpl { namespace xrpl {
template <class F> template <class F>
@@ -8,18 +10,16 @@ JobQueue::Coro::Coro(Coro_create_t, JobQueue& jq, JobType type, std::string cons
, type_(type) , type_(type)
, name_(name) , name_(name)
, coro_( , coro_(
// Stack size of 1MB wasn't sufficient for deep calls. ASAN tests flagged the issue. Hence
// increasing the size to 1.5MB.
boost::context::protected_fixedsize_stack(1536 * 1024),
[this, fn = std::forward<F>(f)]( [this, fn = std::forward<F>(f)](
boost::coroutines2::asymmetric_coroutine<void>::push_type& do_yield) { boost::coroutines::asymmetric_coroutine<void>::push_type& do_yield) {
yield_ = &do_yield; yield_ = &do_yield;
yield(); yield();
fn(shared_from_this()); fn(shared_from_this());
#ifndef NDEBUG #ifndef NDEBUG
finished_ = true; finished_ = true;
#endif #endif
}) },
boost::coroutines::attributes(megabytes(1)))
{ {
} }

View File

@@ -7,8 +7,7 @@
#include <xrpl/core/detail/Workers.h> #include <xrpl/core/detail/Workers.h>
#include <xrpl/json/json_value.h> #include <xrpl/json/json_value.h>
#include <boost/context/protected_fixedsize_stack.hpp> #include <boost/coroutine/all.hpp>
#include <boost/coroutine2/all.hpp>
#include <set> #include <set>
@@ -49,8 +48,8 @@ public:
std::mutex mutex_; std::mutex mutex_;
std::mutex mutex_run_; std::mutex mutex_run_;
std::condition_variable cv_; std::condition_variable cv_;
boost::coroutines2::coroutine<void>::pull_type coro_; boost::coroutines::asymmetric_coroutine<void>::pull_type coro_;
boost::coroutines2::coroutine<void>::push_type* yield_; boost::coroutines::asymmetric_coroutine<void>::push_type* yield_;
#ifndef NDEBUG #ifndef NDEBUG
bool finished_ = false; bool finished_ = false;
#endif #endif

View File

@@ -1,6 +1,15 @@
# The idea is to empty this file gradually by fixing the underlying issues and removing suppressions. # The idea is to empty this file gradually by fixing the underlying issues and removing suppressions.
# #
# ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=sanitizers/suppressions/asan.supp:halt_on_error=0" # ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=sanitizers/suppressions/asan.supp:halt_on_error=0"
#
# The detect_container_overflow=0 option disables false positives from:
# - Boost intrusive containers (slist_iterator.hpp, hashtable.hpp, aged_unordered_container.h)
# - Boost context/coroutine stack switching (Workers.cpp, thread.h)
#
# See: https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow
# Boost
interceptor_name:boost/asio
# Suppress false positive stack-buffer errors in thread stack allocation # Suppress false positive stack-buffer errors in thread stack allocation
# Related to ASan's __asan_handle_no_return warnings (github.com/google/sanitizers/issues/189) # Related to ASan's __asan_handle_no_return warnings (github.com/google/sanitizers/issues/189)