switch to coroutine2 and remove string caching

Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
This commit is contained in:
Pratik Mankawde
2026-02-06 13:46:04 +00:00
parent 65ba439117
commit 69597e4b3b
10 changed files with 33 additions and 74 deletions

View File

@@ -17,7 +17,7 @@ find_dependency(Boost
chrono
container
context
coroutine
coroutine2
date_time
filesystem
program_options

View File

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

View File

@@ -4,13 +4,12 @@ include(XrplSanitizers)
find_package(Boost REQUIRED
COMPONENTS chrono
container
coroutine
context
date_time
filesystem
json
program_options
regex
system
thread)
add_library(xrpl_boost INTERFACE)
@@ -21,7 +20,7 @@ target_link_libraries(
INTERFACE Boost::headers
Boost::chrono
Boost::container
Boost::coroutine
Boost::context
Boost::date_time
Boost::filesystem
Boost::json

View File

@@ -56,6 +56,9 @@ class Xrpl(ConanFile):
"static": True,
"tests": False,
"xrpld": False,
"boost/*:without_context": False,
"boost/*:without_coroutine": True,
"boost/*:without_coroutine2": False,
"date/*:header_only": True,
"ed25519/*:shared": False,
"grpc/*:shared": False,
@@ -124,6 +127,9 @@ class Xrpl(ConanFile):
self.options["boost"].visibility = "global"
if self.settings.compiler in ["clang", "gcc"]:
self.options["boost"].without_cobalt = True
self.options["boost"].without_context = False
self.options["boost"].without_coroutine = True
self.options["boost"].without_coroutine2 = False
# Check if environment variable exists
if "SANITIZERS" in os.environ:
@@ -200,7 +206,8 @@ class Xrpl(ConanFile):
"boost::headers",
"boost::chrono",
"boost::container",
"boost::coroutine",
"boost::context",
"boost::coroutine2",
"boost::date_time",
"boost::filesystem",
"boost::json",

View File

@@ -3,7 +3,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <sstream>
#include <string>
namespace beast {
@@ -159,17 +158,6 @@ public:
std::ostream&
operator<<(T const& t) const;
/** Overload for const char* for chained operations.
Handles cases like: stream << "text1" << "text2"
Converts to std::string to prevent stack-use-after-scope issues.
*/
std::ostream&
operator<<(char const* t) const
{
m_ostream << std::string(t);
return m_ostream;
}
private:
Sink& m_sink;
Severity const m_level;
@@ -250,18 +238,6 @@ public:
template <typename T>
ScopedStream
operator<<(T const& t) const;
/** Overload for const char* to ensure immediate copy.
This prevents stack-use-after-scope issues when the source
pointer becomes invalid due to coroutine context switches or
stack unwinding. Converts to std::string immediately to copy
the data before constructing ScopedStream.
*/
ScopedStream
operator<<(char const* t) const
{
return t ? ScopedStream(*this, std::string(t)) : ScopedStream(*this, std::string());
}
/** @} */
private:

View File

@@ -18,16 +18,14 @@ JobQueue::Coro::Coro(Coro_create_t, JobQueue& jq, JobType type, std::string cons
, type_(type)
, name_(name)
, running_(false)
, coro_(
[this, fn = std::forward<F>(f)](boost::coroutines::asymmetric_coroutine<void>::push_type& do_yield) {
yield_ = &do_yield;
yield();
fn(shared_from_this());
, coro_([this, fn = std::forward<F>(f)](boost::coroutines2::asymmetric_coroutine<void>::push_type& do_yield) {
yield_ = &do_yield;
yield();
fn(shared_from_this());
#ifndef NDEBUG
finished_ = true;
finished_ = true;
#endif
},
boost::coroutines::attributes(megabytes(4))) // 4MB stack (increased from 1MB)
})
{
}

View File

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

View File

@@ -1,7 +1,8 @@
detect_container_overflow=0
detect_stack_use_after_return=0
detect_stack-buffer-overflow=0
debug=true
halt_on_error=0
halt_on_error=false
print_stats=true
print_legend=true
symbolize=true

View File

@@ -69,17 +69,13 @@ make_name(std::string const& object, std::string const& field)
if (field.empty())
return object;
return object + "." + field;
return {object + "." + field};
}
// Note: Store make_name() result in a local variable before string concatenation
// to prevent stack-use-after-scope when the temporary is used in chained operations
static inline Json::Value
not_an_object(std::string const& object, std::string const& field)
{
auto const fieldName = make_name(object, field);
std::string const msg = "Field '" + fieldName + "' is not a JSON object.";
return RPC::make_error(rpcINVALID_PARAMS, msg);
return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is not a JSON object.");
}
static inline Json::Value
@@ -97,33 +93,25 @@ not_an_array(std::string const& object)
static inline Json::Value
unknown_field(std::string const& object, std::string const& field)
{
auto const fieldName = make_name(object, field);
std::string const msg = "Field '" + fieldName + "' is unknown.";
return RPC::make_error(rpcINVALID_PARAMS, msg);
return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is unknown.");
}
static inline Json::Value
out_of_range(std::string const& object, std::string const& field)
{
auto const fieldName = make_name(object, field);
std::string const msg = "Field '" + fieldName + "' is out of range.";
return RPC::make_error(rpcINVALID_PARAMS, msg);
return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is out of range.");
}
static inline Json::Value
bad_type(std::string const& object, std::string const& field)
{
auto const fieldName = make_name(object, field);
std::string const msg = "Field '" + fieldName + "' has bad type.";
return RPC::make_error(rpcINVALID_PARAMS, msg);
return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' has bad type.");
}
static inline Json::Value
invalid_data(std::string const& object, std::string const& field)
{
auto const fieldName = make_name(object, field);
std::string const msg = "Field '" + fieldName + "' has invalid data.";
return RPC::make_error(rpcINVALID_PARAMS, msg);
return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' has invalid data.");
}
static inline Json::Value
@@ -135,17 +123,13 @@ invalid_data(std::string const& object)
static inline Json::Value
array_expected(std::string const& object, std::string const& field)
{
auto const fieldName = make_name(object, field);
std::string const msg = "Field '" + fieldName + "' must be a JSON array.";
return RPC::make_error(rpcINVALID_PARAMS, msg);
return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' must be a JSON array.");
}
static inline Json::Value
string_expected(std::string const& object, std::string const& field)
{
auto const fieldName = make_name(object, field);
std::string const msg = "Field '" + fieldName + "' must be a string.";
return RPC::make_error(rpcINVALID_PARAMS, msg);
return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' must be a string.");
}
static inline Json::Value

View File

@@ -179,10 +179,7 @@ AMMLiquidity<TIn, TOut>::getOffer(ReadView const& view, std::optional<Quality> c
}
catch (std::overflow_error const& e)
{
// Store e.what() in a local variable to prevent stack-use-after-scope
// when the exception's internal storage becomes invalid in coroutine context
std::string const errorMsg = e.what();
JLOG(j_.error()) << "AMMLiquidity::getOffer overflow " << errorMsg;
JLOG(j_.error()) << "AMMLiquidity::getOffer overflow " << e.what();
if (!view.rules().enabled(fixAMMOverflowOffer))
return maxOffer(balances, view.rules());
else
@@ -190,10 +187,7 @@ AMMLiquidity<TIn, TOut>::getOffer(ReadView const& view, std::optional<Quality> c
}
catch (std::exception const& e)
{
// Store e.what() in a local variable to prevent stack-use-after-scope
// when the exception's internal storage becomes invalid in coroutine context
std::string const errorMsg = e.what();
JLOG(j_.error()) << "AMMLiquidity::getOffer exception " << errorMsg;
JLOG(j_.error()) << "AMMLiquidity::getOffer exception " << e.what();
}
return std::nullopt;
}();