From 2908adf1e7951798bb9e45b6b539145b948ac417 Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Fri, 11 Oct 2024 17:29:05 +0200 Subject: [PATCH] Fix registering commandline subparsers multiple times for Python 3.11 Python 3.11 added a sanity check to argparse to prevent registering the same subparser multiple times. argparse.ArgumentError: argument command: conflicting subparser: cyclic Avoid importing the command twice. `python -m pwnlib.commandline.cyclic` failed on Python 3.11 triggered in CI when running the commandline tools while collecting coverage. --- pwnlib/commandline/asm.py | 2 +- pwnlib/commandline/checksec.py | 2 +- pwnlib/commandline/common.py | 16 +++++++++++++--- pwnlib/commandline/constgrep.py | 2 +- pwnlib/commandline/cyclic.py | 2 +- pwnlib/commandline/debug.py | 2 +- pwnlib/commandline/disablenx.py | 2 +- pwnlib/commandline/disasm.py | 2 +- pwnlib/commandline/elfdiff.py | 2 +- pwnlib/commandline/elfpatch.py | 2 +- pwnlib/commandline/errno.py | 2 +- pwnlib/commandline/hex.py | 2 +- pwnlib/commandline/libcdb.py | 2 +- pwnlib/commandline/main.py | 12 ++---------- pwnlib/commandline/phd.py | 2 +- pwnlib/commandline/pwnstrip.py | 2 +- pwnlib/commandline/scramble.py | 2 +- pwnlib/commandline/shellcraft.py | 2 +- pwnlib/commandline/template.py | 2 +- pwnlib/commandline/unhex.py | 2 +- pwnlib/commandline/update.py | 2 +- pwnlib/commandline/version.py | 2 +- 22 files changed, 35 insertions(+), 33 deletions(-) diff --git a/pwnlib/commandline/asm.py b/pwnlib/commandline/asm.py index 03c51a6a2..b130228ae 100644 --- a/pwnlib/commandline/asm.py +++ b/pwnlib/commandline/asm.py @@ -137,4 +137,4 @@ def main(args): args.output.write(b'\n') if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/checksec.py b/pwnlib/commandline/checksec.py index da0d7b49d..57227bd01 100644 --- a/pwnlib/commandline/checksec.py +++ b/pwnlib/commandline/checksec.py @@ -38,4 +38,4 @@ def main(args): e = ELF(f.name) if __name__ == '__main__': - common.main(__file__) + common.main(__file__, main) diff --git a/pwnlib/commandline/common.py b/pwnlib/commandline/common.py index 75edfdcb8..3ce0a0fad 100644 --- a/pwnlib/commandline/common.py +++ b/pwnlib/commandline/common.py @@ -25,8 +25,18 @@ def context_arg(arg): prog='pwn') parser_commands = parser.add_subparsers(dest='command') -def main(file=sys.argv[0]): - import pwnlib.commandline.main +def main(file=sys.argv[0], command_main=None): name = os.path.splitext(os.path.basename(file))[0] + if command_main is None: + import importlib + command_main = importlib.import_module('pwnlib.commandline.%s' % name).main sys.argv.insert(1, name) - pwnlib.commandline.main.main() + entrypoint({name: command_main}) + +def entrypoint(commands): + if len(sys.argv) < 2: + parser.print_usage() + sys.exit() + args = parser.parse_args() + with context.local(log_console = sys.stderr): + commands[args.command](args) diff --git a/pwnlib/commandline/constgrep.py b/pwnlib/commandline/constgrep.py index d9341f5c4..ace70f4ed 100644 --- a/pwnlib/commandline/constgrep.py +++ b/pwnlib/commandline/constgrep.py @@ -133,4 +133,4 @@ def main(args): print('(%s) == %s' % (' | '.join(k for v, k in good), args.constant)) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/cyclic.py b/pwnlib/commandline/cyclic.py index ff012a359..c7a5060f6 100644 --- a/pwnlib/commandline/cyclic.py +++ b/pwnlib/commandline/cyclic.py @@ -107,4 +107,4 @@ def main(args): out.write(b'\n') if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/debug.py b/pwnlib/commandline/debug.py index fe5fca6f5..15593f915 100644 --- a/pwnlib/commandline/debug.py +++ b/pwnlib/commandline/debug.py @@ -102,4 +102,4 @@ def main(args): gdb.debug(target, gdbscript=gdbscript, sysroot=args.sysroot).interactive() if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/disablenx.py b/pwnlib/commandline/disablenx.py index 29839c0f8..14a7d6531 100644 --- a/pwnlib/commandline/disablenx.py +++ b/pwnlib/commandline/disablenx.py @@ -24,4 +24,4 @@ def main(args): ELF(e.path) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/disasm.py b/pwnlib/commandline/disasm.py index b304393d2..3cf60b148 100644 --- a/pwnlib/commandline/disasm.py +++ b/pwnlib/commandline/disasm.py @@ -110,4 +110,4 @@ def main(args): print(disasm(dat, vma=safeeval.const(args.address))) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/elfdiff.py b/pwnlib/commandline/elfdiff.py index 48afef09f..2ea307ad9 100644 --- a/pwnlib/commandline/elfdiff.py +++ b/pwnlib/commandline/elfdiff.py @@ -59,4 +59,4 @@ def main(a): print(diff(x, y)) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/elfpatch.py b/pwnlib/commandline/elfpatch.py index 10a5adc24..ee8584a9e 100644 --- a/pwnlib/commandline/elfpatch.py +++ b/pwnlib/commandline/elfpatch.py @@ -34,4 +34,4 @@ def main(a): getattr(sys.stdout, 'buffer', sys.stdout).write(elf.get_data()) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/errno.py b/pwnlib/commandline/errno.py index d3a05e37a..2090fbbe2 100644 --- a/pwnlib/commandline/errno.py +++ b/pwnlib/commandline/errno.py @@ -46,4 +46,4 @@ def main(args): print(os.strerror(value)) if __name__ == '__main__': - common.main(__file__) + common.main(__file__, main) diff --git a/pwnlib/commandline/hex.py b/pwnlib/commandline/hex.py index d538af246..d36291054 100644 --- a/pwnlib/commandline/hex.py +++ b/pwnlib/commandline/hex.py @@ -50,4 +50,4 @@ def main(args): print(encoded) if __name__ == '__main__': - common.main(__file__) + common.main(__file__, main) diff --git a/pwnlib/commandline/libcdb.py b/pwnlib/commandline/libcdb.py index 30ee47f07..d6523b627 100644 --- a/pwnlib/commandline/libcdb.py +++ b/pwnlib/commandline/libcdb.py @@ -248,4 +248,4 @@ def main(args): log.indented('%25s = %#x', symbol, translate_offset(exe.symbols[symbol], args, exe)) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/main.py b/pwnlib/commandline/main.py index 5cfbdd5b7..9382c43c7 100644 --- a/pwnlib/commandline/main.py +++ b/pwnlib/commandline/main.py @@ -1,7 +1,5 @@ from __future__ import absolute_import -import sys - from pwnlib.commandline import asm from pwnlib.commandline import checksec from pwnlib.commandline import common @@ -23,8 +21,7 @@ from pwnlib.commandline import unhex from pwnlib.commandline import update from pwnlib.commandline import version -from pwnlib.commandline.common import parser -from pwnlib.context import context +from pwnlib.commandline.common import parser as parser commands = { 'asm': asm.main, @@ -50,12 +47,7 @@ } def main(): - if len(sys.argv) < 2: - parser.print_usage() - sys.exit() - args = parser.parse_args() - with context.local(log_console = sys.stderr): - commands[args.command](args) + common.entrypoint(commands) if __name__ == '__main__': main() diff --git a/pwnlib/commandline/phd.py b/pwnlib/commandline/phd.py index 7f3891e0f..1be34d969 100644 --- a/pwnlib/commandline/phd.py +++ b/pwnlib/commandline/phd.py @@ -109,4 +109,4 @@ def main(args): pass if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/pwnstrip.py b/pwnlib/commandline/pwnstrip.py index fcc8df171..b7601b605 100644 --- a/pwnlib/commandline/pwnstrip.py +++ b/pwnlib/commandline/pwnstrip.py @@ -53,4 +53,4 @@ def main(args): args.output.write(result) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/scramble.py b/pwnlib/commandline/scramble.py index 8b5043be4..4d4b31cda 100644 --- a/pwnlib/commandline/scramble.py +++ b/pwnlib/commandline/scramble.py @@ -110,4 +110,4 @@ def main(args): if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/shellcraft.py b/pwnlib/commandline/shellcraft.py index 9f5fe36ae..ce8e70e22 100644 --- a/pwnlib/commandline/shellcraft.py +++ b/pwnlib/commandline/shellcraft.py @@ -352,4 +352,4 @@ def main(args): args.out.write(code) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/template.py b/pwnlib/commandline/template.py index 5cd6c7341..44456441c 100644 --- a/pwnlib/commandline/template.py +++ b/pwnlib/commandline/template.py @@ -122,5 +122,5 @@ def main(args): except OSError: pass if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/unhex.py b/pwnlib/commandline/unhex.py index a254e6b3f..99dad8efd 100644 --- a/pwnlib/commandline/unhex.py +++ b/pwnlib/commandline/unhex.py @@ -30,4 +30,4 @@ def main(args): raise if __name__ == '__main__': - common.main(__file__) + common.main(__file__, main) diff --git a/pwnlib/commandline/update.py b/pwnlib/commandline/update.py index 38ef19a76..2670c0c31 100644 --- a/pwnlib/commandline/update.py +++ b/pwnlib/commandline/update.py @@ -30,4 +30,4 @@ def main(a): subprocess.check_call(result, shell=False) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main) diff --git a/pwnlib/commandline/version.py b/pwnlib/commandline/version.py index 9b820160d..ad25a7570 100644 --- a/pwnlib/commandline/version.py +++ b/pwnlib/commandline/version.py @@ -29,4 +29,4 @@ def main(a): log.info("Pwntools v%s" % version) if __name__ == '__main__': - pwnlib.commandline.common.main(__file__) + pwnlib.commandline.common.main(__file__, main)