fix(a3): resolve shift buffer race condition with call-unique tokens, atomic write, and automatic GC (100% PASS)
This commit is contained in:
+43
-7
@@ -450,13 +450,40 @@ except Exception:
|
||||
exit 1
|
||||
fi
|
||||
buf="$(echo "$2" | tr -cd 'A-Za-z0-9_.-')"
|
||||
if [ -z "$buf" ]; then buf="tmp_buffer"; else buf="buf_$buf"; fi
|
||||
if [ -z "$buf" ]; then
|
||||
echo "Error: -b name contains no usable characters" >&2
|
||||
exit 1
|
||||
fi
|
||||
buf="buf_$buf"
|
||||
shift 2
|
||||
;;
|
||||
*) text="$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
echo -n "$text" > "$wrapper_dir/$buf"
|
||||
# A-3 GC: unique buffer names mean an abandoned buffer (SIGINT/SIGTERM/
|
||||
# timeout between set-buffer and delete-buffer) is never overwritten, so
|
||||
# it would leak forever. Sweep here -- at creation time, the moment new
|
||||
# garbage can appear -- rather than from a separate reaper.
|
||||
#
|
||||
# SAFETY: the age threshold must comfortably exceed the lifetime of a LIVE
|
||||
# buffer, or the sweep would delete a buffer awaiting its paste and
|
||||
# re-create the silent loss A-3 exists to remove. A live buffer lives from
|
||||
# set-buffer to delete-buffer (sub-second in practice, bounded by the
|
||||
# blocking `agent send`), so 60 minutes is ~4 orders of magnitude of slack.
|
||||
# Failures are ignored: garbage collection must never break an injection.
|
||||
#
|
||||
# The '.buf_sks_*' arm is not redundant: F2's atomic write stages through
|
||||
# a DOT-prefixed temp ('.buf_sks_....tmp'), which 'buf_sks_*' cannot match.
|
||||
# Without it a temp orphaned by SIGKILL between write and rename would leak
|
||||
# forever, exactly like the buffers this sweep exists to reclaim.
|
||||
find "$wrapper_dir" \( -name 'buf_sks_*' -o -name '.buf_sks_*' \) \
|
||||
-mmin +${MAM_BUFFER_GC_MINUTES:-60} -delete 2>/dev/null || true
|
||||
_tmp="$wrapper_dir/.$buf.$$.tmp"
|
||||
if ! { echo -n "$text" > "$_tmp" && mv -f "$_tmp" "$wrapper_dir/$buf"; }; then
|
||||
rm -f "$_tmp"
|
||||
echo "Error: failed to write buffer $buf" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
paste-buffer)
|
||||
buf="tmp_buffer"
|
||||
@@ -465,7 +492,11 @@ except Exception:
|
||||
case "$1" in
|
||||
-b)
|
||||
buf="$(echo "$2" | tr -cd 'A-Za-z0-9_.-')"
|
||||
if [ -z "$buf" ]; then buf="tmp_buffer"; else buf="buf_$buf"; fi
|
||||
if [ -z "$buf" ]; then
|
||||
echo "Error: -b name contains no usable characters" >&2
|
||||
exit 1
|
||||
fi
|
||||
buf="buf_$buf"
|
||||
shift 2
|
||||
;;
|
||||
-t)
|
||||
@@ -492,7 +523,11 @@ except Exception:
|
||||
case "$1" in
|
||||
-b)
|
||||
buf="$(echo "$2" | tr -cd 'A-Za-z0-9_.-')"
|
||||
if [ -z "$buf" ]; then buf="tmp_buffer"; else buf="buf_$buf"; fi
|
||||
if [ -z "$buf" ]; then
|
||||
echo "Error: -b name contains no usable characters" >&2
|
||||
exit 1
|
||||
fi
|
||||
buf="buf_$buf"
|
||||
shift 2
|
||||
;;
|
||||
*) shift ;;
|
||||
@@ -1706,9 +1741,10 @@ send_keys_safe() {
|
||||
sleep 2
|
||||
done
|
||||
|
||||
_sks_herdr set-buffer -b "sks_$job_id" "$text"
|
||||
_sks_herdr paste-buffer -b "sks_$job_id" -t "$sess"
|
||||
_sks_herdr delete-buffer -b "sks_$job_id" 2>/dev/null || true
|
||||
local sks_buf="sks_${sess}_${job_id}_$$_${RANDOM}_$(date +%s%N 2>/dev/null || date +%s)"
|
||||
_sks_herdr set-buffer -b "$sks_buf" "$text"
|
||||
_sks_herdr paste-buffer -b "$sks_buf" -t "$sess"
|
||||
_sks_herdr delete-buffer -b "$sks_buf" 2>/dev/null || true
|
||||
if [[ "$sess" =~ "agy" ]]; then
|
||||
_sks_herdr send-keys -t "$sess" C-m
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user