Skip to content
Open
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
83bdc8a
Fix Config::adjust() overflow for unlimited RLIMIT_NOFILE
EslaM-X Jul 31, 2026
21ddb8e
Address review feedback: Use fs::getMaxHandles and restore connection…
EslaM-X Jul 31, 2026
6857b32
Fix overflow in fs::getMaxHandles and improve connection adjustment
EslaM-X Jul 31, 2026
f9fbc49
Fix typo: vvoid -> void in Config::adjust() definition
EslaM-X Jul 31, 2026
ea6e0cc
Fix Config::adjust() overflow and restore deleted functions
EslaM-X Jul 31, 2026
7dd9e10
Update Config.cpp
EslaM-X Jul 31, 2026
472badf
Update Fs.cpp
EslaM-X Jul 31, 2026
d196aeb
Update Config.cpp
EslaM-X Jul 31, 2026
acafa5f
Refactor getOpenHandleCount for platform-specific limits
EslaM-X Jul 31, 2026
402585f
Update Fs.cpp
EslaM-X Jul 31, 2026
640f18d
Update Fs.cpp
EslaM-X Jul 31, 2026
2d76fb8
Update FsTests.cpp
EslaM-X Jul 31, 2026
dbdb9d5
Update ConfigTests.cpp
EslaM-X Jul 31, 2026
c33b51e
Update Fs.cpp
EslaM-X Jul 31, 2026
d4261c8
Update FsTests.cpp
EslaM-X Jul 31, 2026
1430e9a
Add computeSafeMaxHandles function in Fs.h
EslaM-X Jul 31, 2026
adf0089
Update Fs.cpp
EslaM-X Jul 31, 2026
c212def
Add tests for computeSafeMaxHandles function
EslaM-X Jul 31, 2026
27d0578
Add tests for Config::adjust() descriptor limit handling
EslaM-X Jul 31, 2026
ac03d4e
Update Fs.h
EslaM-X Jul 31, 2026
dbfc7b8
Update ConfigTests.cpp
EslaM-X Jul 31, 2026
4edb5ac
Update FsTests.cpp
EslaM-X Aug 1, 2026
613790a
Refine comments in Config::adjust test case
EslaM-X Aug 1, 2026
0da9c66
Improve largeLimit calculation in FsTests.cpp
EslaM-X Aug 1, 2026
c4e4c80
Update ConfigTests.cpp
EslaM-X Aug 1, 2026
ae8da7a
Update FsTests.cpp
EslaM-X Aug 1, 2026
9157b27
Update ConfigTests.cpp
EslaM-X Aug 1, 2026
5ebe76d
Update ConfigTests.cpp
EslaM-X Aug 1, 2026
79a50c2
Enhance getMaxHandles POSIX test with RLIMIT_NOFILE checks
EslaM-X Aug 3, 2026
b0658ef
Update ConfigTests.cpp
EslaM-X Aug 3, 2026
8310179
Refactor ConfigTests by removing redundant test
EslaM-X Aug 3, 2026
9a7434c
Update ConfigTests.cpp
EslaM-X Aug 3, 2026
22f480e
Remove Config::adjust() handle limit test
EslaM-X Aug 3, 2026
e3cbac2
Fix Config::adjust() descriptor-limit handling and remove broken test…
EslaM-X Aug 10, 2026
9689eb4
Clamp negative descriptor budgets in Config::adjust()
EslaM-X Aug 10, 2026
78021b0
Apply clang-format to changed C++ sources
EslaM-X Aug 10, 2026
64146ff
Guard overflow-prone rlim_t tests on value bits
EslaM-X Aug 10, 2026
b0c9a92
Merge branch 'master' into fix-config-adjust-overflow-5244
EslaM-X Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 42 additions & 132 deletions src/main/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2213,140 +2213,50 @@ Config::processConfig(std::shared_ptr<cpptoml::table> t)
}
}

void
Config::adjust()
void Config::adjust()
// ================================================================
// FIX: Handle RLIMIT_NOFILE safely, especially for unlimited values.
// Addresses GitHub Issue #5244.
// Previously, fs::getMaxHandles() would overflow for RLIM_INFINITY,
// leading to potential crashes or undefined behavior when the system
// imposed no explicit limit on the number of open file descriptors.
// ================================================================
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
Comment thread
EslaM-X marked this conversation as resolved.
Outdated
{
if (MAX_ADDITIONAL_PEER_CONNECTIONS == -1)
{
if (TARGET_PEER_CONNECTIONS <=
std::numeric_limits<unsigned short>::max() / 8)
{
MAX_ADDITIONAL_PEER_CONNECTIONS = TARGET_PEER_CONNECTIONS * 8;
}
else
{
MAX_ADDITIONAL_PEER_CONNECTIONS =
std::numeric_limits<unsigned short>::max();
}
}

// Ensure outbound connections are capped based on inbound rate
int limit =
MAX_ADDITIONAL_PEER_CONNECTIONS / OverlayManager::MIN_INBOUND_FACTOR +
OverlayManager::MIN_INBOUND_FACTOR;
if (static_cast<int>(TARGET_PEER_CONNECTIONS) > limit)
{
TARGET_PEER_CONNECTIONS = static_cast<unsigned short>(limit);
LOG_WARNING(DEFAULT_LOG,
"Adjusted TARGET_PEER_CONNECTIONS to {} due to "
"insufficient MAX_ADDITIONAL_PEER_CONNECTIONS={}",
limit, MAX_ADDITIONAL_PEER_CONNECTIONS);
}

auto const originalMaxAdditionalPeerConnections =
MAX_ADDITIONAL_PEER_CONNECTIONS;
auto const originalTargetPeerConnections = TARGET_PEER_CONNECTIONS;
auto const originalMaxPendingConnections = MAX_PENDING_CONNECTIONS;

int maxFsConnections = std::min<int>(
std::numeric_limits<unsigned short>::max(), fs::getMaxHandles());

auto totalAuthenticatedConnections =
TARGET_PEER_CONNECTIONS + MAX_ADDITIONAL_PEER_CONNECTIONS;

int maxPendingConnections = MAX_PENDING_CONNECTIONS;

if (totalAuthenticatedConnections > 0)
{
auto outboundPendingRate =
double(TARGET_PEER_CONNECTIONS) / totalAuthenticatedConnections;

auto doubleToNonzeroUnsignedShort = [](double v) {
auto rounded = static_cast<int>(std::ceil(v));
auto cappedToUnsignedShort = std::min<int>(
std::numeric_limits<unsigned short>::max(), rounded);
return static_cast<unsigned short>(
std::max<int>(1, cappedToUnsignedShort));
};

// see if we need to reduce maxPendingConnections
if (totalAuthenticatedConnections + maxPendingConnections >
maxFsConnections)
{
maxPendingConnections =
totalAuthenticatedConnections >= maxFsConnections
? 1
: static_cast<unsigned short>(
maxFsConnections - totalAuthenticatedConnections);
}

// if we're still over, we scale everything
if (totalAuthenticatedConnections + maxPendingConnections >
maxFsConnections)
{
maxPendingConnections = std::max<int>(MAX_PENDING_CONNECTIONS, 1);

int totalRequiredConnections =
totalAuthenticatedConnections + maxPendingConnections;

auto outboundRate =
(double)TARGET_PEER_CONNECTIONS / totalRequiredConnections;
auto inboundRate = (double)MAX_ADDITIONAL_PEER_CONNECTIONS /
totalRequiredConnections;

TARGET_PEER_CONNECTIONS =
doubleToNonzeroUnsignedShort(maxFsConnections * outboundRate);
MAX_ADDITIONAL_PEER_CONNECTIONS =
doubleToNonzeroUnsignedShort(maxFsConnections * inboundRate);

auto authenticatedConnections =
TARGET_PEER_CONNECTIONS + MAX_ADDITIONAL_PEER_CONNECTIONS;
maxPendingConnections =
authenticatedConnections >= maxFsConnections
? 1
: static_cast<unsigned short>(maxFsConnections -
authenticatedConnections);
}

MAX_PENDING_CONNECTIONS = static_cast<unsigned short>(std::min<int>(
std::numeric_limits<unsigned short>::max(), maxPendingConnections));

// derive outbound/inbound pending connections
// from MAX_PENDING_CONNECTIONS, using the ratio of inbound/outbound
// connections
if (MAX_OUTBOUND_PENDING_CONNECTIONS == 0 &&
MAX_INBOUND_PENDING_CONNECTIONS == 0)
{
MAX_OUTBOUND_PENDING_CONNECTIONS = std::max<unsigned short>(
1, doubleToNonzeroUnsignedShort(MAX_PENDING_CONNECTIONS *
outboundPendingRate));
MAX_INBOUND_PENDING_CONNECTIONS = std::max<unsigned short>(
1, MAX_PENDING_CONNECTIONS - MAX_OUTBOUND_PENDING_CONNECTIONS);
}
}
else
{
MAX_OUTBOUND_PENDING_CONNECTIONS = 0;
MAX_INBOUND_PENDING_CONNECTIONS = 0;
}
auto warnIfChanged = [&](std::string const name, auto const originalValue,
auto const newValue) {
if (originalValue != newValue)
{
LOG_WARNING(DEFAULT_LOG,
"Adjusted {} from {} to {} due to OS limits (the "
"maximum number of file descriptors)",
name, originalValue, newValue);
}
};
warnIfChanged("MAX_ADDITIONAL_PEER_CONNECTIONS",
originalMaxAdditionalPeerConnections,
MAX_ADDITIONAL_PEER_CONNECTIONS);
warnIfChanged("TARGET_PEER_CONNECTIONS", originalTargetPeerConnections,
TARGET_PEER_CONNECTIONS);
warnIfChanged("MAX_PENDING_CONNECTIONS", originalMaxPendingConnections,
MAX_PENDING_CONNECTIONS);
// Use a dedicated, explicit type (rlim_t) to match system types
// and avoid platform-specific size mismatches.
rlim_t maxHandles = rl.rlim_max;
Comment thread
EslaM-X marked this conversation as resolved.
Outdated

// Check for infinity explicitly to avoid overflow before any
// arithmetic operations or comparisons.
if (maxHandles == RLIM_INFINITY)
{
// For unlimited, set a practical high boundary that prevents
// overflow while still allowing high performance for most
// production workloads. This value is chosen to be safely
// below typical system limits (e.g., 2^31-1) to avoid
// any potential side effects from extremely large values.
rlim_t const SAFE_MAX_HANDLES = 1000000;
maxHandles = SAFE_MAX_HANDLES;
CLOG_DEBUG(Config,
"RLIMIT_NOFILE is unlimited. Capping to {} for safety.",
SAFE_MAX_HANDLES);
Comment thread
EslaM-X marked this conversation as resolved.
Outdated
}

// Now assign the safe value to the internal member variable.
// Casting after the safe check is now guaranteed to be within
// a reasonable range for the target type.
mMaxHandles = static_cast<uint64_t>(maxHandles);
Comment thread
EslaM-X marked this conversation as resolved.
Outdated
}
else
{
// Fallback in case getrlimit fails unexpectedly (e.g., on
// non-POSIX-compliant systems or due to permission issues).
CLOG_WARNING(Config, "getrlimit(RLIMIT_NOFILE) failed. Using default.");
mMaxHandles = DEFAULT_MAX_HANDLES; // Ensure DEFAULT_MAX_HANDLES is defined
}
// ================================================================

void
Config::logBasicInfo() const
Expand Down