From 99136db02113062d78a24b1bcb906d71efc36297 Mon Sep 17 00:00:00 2001 From: Abhinav Tarigoppula Date: Sun, 27 Sep 2026 22:58:14 +0530 Subject: [PATCH] sendpfast: report a missing tcpreplay instead of UnboundLocalError When tcpreplay could not be started, Popen raised before cmd was bound and the finally block's cmd.communicate() raised UnboundLocalError. ContextManagerSubprocess then logged "execution failed" with that error instead of "Could not execute tcpreplay, is it installed?". AI-Assisted: yes (Claude Code) --- scapy/sendrecv.py | 16 +++++++++------- test/regression.uts | 12 ++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py index 279e76d82fb..4919c1b8846 100644 --- a/scapy/sendrecv.py +++ b/scapy/sendrecv.py @@ -580,6 +580,7 @@ def sendpfast(x: _PacketIterable, argv.append(f) wrpcap(f, x) results = None + cmd = None with ContextManagerSubprocess(conf.prog.tcpreplay): try: cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, @@ -593,13 +594,14 @@ def sendpfast(x: _PacketIterable, os.unlink(f) raise finally: - stdout, stderr = cmd.communicate() - if stderr: - log_runtime.warning(stderr.decode()) - if parse_results: - results = _parse_tcpreplay_result(stdout, stderr, argv) - elif conf.verb > 2: - log_runtime.info(stdout.decode()) + if cmd is not None: + stdout, stderr = cmd.communicate() + if stderr: + log_runtime.warning(stderr.decode()) + if parse_results: + results = _parse_tcpreplay_result(stdout, stderr, argv) + elif conf.verb > 2: + log_runtime.info(stdout.decode()) if os.path.exists(f): os.unlink(f) return results diff --git a/test/regression.uts b/test/regression.uts index a64d48d73a6..2b84ecfcb90 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -2007,6 +2007,18 @@ except Exception: conf.interactive = old_interactive assert True += sendpfast - tcpreplay not installed +* A missing tcpreplay must be reported as such, not hidden by an UnboundLocalError + +old_tcpreplay = conf.prog.tcpreplay +conf.prog.tcpreplay = "/nonexistent/tcpreplay" +try: + with mock.patch("scapy.utils.log_runtime.error") as log_error: + assert sendpfast(Ether() / IP()) is None + assert "is it installed?" in log_error.call_args[0][0] +finally: + conf.prog.tcpreplay = old_tcpreplay + ############ ############ + Generator tests