shim/ is an LD_PRELOAD guard around close/fclose/dup2/dup3: - before each close it resolves /proc/self/fd/N; - it reports, with a backtrace, a non-owner close of wallet.dat, database/log.* or blocks/*.dat, and every close that fails with EBADF (the second half of a double close); - FDGUARD_ABORT=1 aborts on the first hit; - run_tests.sh self-tests it (51 checks). repro/ runs a shimmed dragonxd on isolated regtest. Each run gets its own unprivileged network namespace (loopback only). The loads are: - rpc: a hammer with impatient/RST/half-open clients, work-queue bursts and long-polls; - p2p: TLS peers churned by disconnectnode, ban and kill, plus a raw TCP/TLS misbehaver; - tor: a fake control port; - mine: mining with blocknotify and autoshield. tools/tally.py groups the reports by closer. tools/scan_bdb.py finds BDB pages written into block files. With the wolfSSL CloseSocket macro in effect: - p2pmin (300 s) gives one EBADF double close per disconnect; - the full load (1200 s) gives 930 EBADF closes, 186 non-owner closes (37 of wallet/log/blk files) and a 632 KB db.log with BDB0060 PANIC; - RPC-only and Tor-only loads give none. After the fix, every count is 0 and db.log stays empty. The README has the commands and the numbers. Paths come from the environment (GOLDEN, BIN, RUNS, SHIM, ASMAP and the Sapling params). Run output goes to $RUNS, outside the tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 lines
1.4 KiB
Bash
Executable File
30 lines
1.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# RPC-driven P2P peer churn on the target (same mix as fdbug/p2p/rpcchurn.sh):
|
|
# disconnectnode / addnode onetry / setban+clearbanned / kill -9 + restart of helper2.
|
|
# usage: rpcchurn.sh <run dir> <seconds>
|
|
source "$REPRO/common.sh"
|
|
OUT=$1; DUR=${2:-300}
|
|
DD_T=$OUT/target; DD_H1=$OUT/helper1; DD_H2=$OUT/helper2
|
|
end=$(( $(date +%s) + DUR )); i=0; restarts=0
|
|
while [ "$(date +%s)" -lt "$end" ] && [ ! -e "$OUT/STOP" ]; do
|
|
i=$((i+1))
|
|
case $(( i % 5 )) in
|
|
0) clin "$DD_T" "$RPC_T" disconnectnode "127.0.0.1:$P2P_H1" >/dev/null 2>&1 ;;
|
|
1) clin "$DD_T" "$RPC_T" addnode "127.0.0.1:$P2P_H1" onetry >/dev/null 2>&1 ;;
|
|
2) clin "$DD_T" "$RPC_T" setban "127.0.0.1" add 1 >/dev/null 2>&1; sleep 0.3
|
|
clin "$DD_T" "$RPC_T" clearbanned >/dev/null 2>&1
|
|
clin "$DD_H2" "$RPC_H2" addnode "127.0.0.1:$P2P_T" onetry >/dev/null 2>&1 ;;
|
|
3) pid=$(cat "$DD_H2/regtest/hushd.pid" 2>/dev/null)
|
|
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
kill -9 "$pid" 2>/dev/null
|
|
for _ in $(seq 1 20); do kill -0 "$pid" 2>/dev/null || break; sleep 0.5; done
|
|
start_helper "$DD_H2" "$P2P_H2" "$RPC_H2" "$OUT/logs/helper2.txt"
|
|
waitrpc "$DD_H2" "$RPC_H2" 120 >/dev/null 2>&1
|
|
restarts=$((restarts+1))
|
|
fi ;;
|
|
4) clin "$DD_T" "$RPC_T" addnode "127.0.0.1:$P2P_H2" onetry >/dev/null 2>&1 ;;
|
|
esac
|
|
sleep 0.7
|
|
done
|
|
echo "rpcchurn: $i cycles, $restarts helper2 restarts"
|