Skip to content

Quality cleanup: no shared-gadget mutation, faster chain build, style#18

Merged
ricardojrdez merged 1 commit into
masterfrom
quality-cleanup
Jun 23, 2026
Merged

Quality cleanup: no shared-gadget mutation, faster chain build, style#18
ricardojrdez merged 1 commit into
masterfrom
quality-cleanup

Conversation

@ricardojrdez

Copy link
Copy Markdown
Member

Resolves the maintainability items raised in the post-merge code review (no behaviour change for users; output is identical).

No shared-Gadget mutation

Operation.filter_gadgets previously wrote .op/.dst/.src and side effects onto the input Gadget objects. Because the same gadget list is filtered for several operations of a chain, the last match could overwrite annotations on a shared object. It now annotates a copy via dataclasses.replace, which also gives each match fresh side-effect sets.

Faster ROP-chain construction

_build_per_comb_gadgets used to re-filter, re-sort and re-prune the full per-operation gadget lists for every register combination — O(combinations × gadgets). It now:

  • sorts each operation's list once up front, and
  • memoises the filter/prune result per (step, req_dst, req_src), since different combinations frequently request the same concrete registers for a step.

Output is unchanged (same filtering, sort order and pruning).

Encapsulation & style

  • ArchitectureSingleton.reset() added to clear the global state cleanly (used by the test fixtures instead of poking the private attribute).
  • isinstance(...) instead of type(...) == ... (operation.py, yaml_parser.py).
  • Imports moved above the module constants in gadfinder.py.
  • Lower bounds pinned for pyelftools / pyyaml / macholib in requirements.txt.

Tests

  • New filter_gadgets no-mutation regression test.
  • New test_ropchain.py (concrete, two-step, generic-register and not-found cases) to guard the chain-build refactor.
  • 59 tests pass locally (3.11 and 3.13); end-to-end output verified unchanged on /bin/ls and a 32-bit busybox.

🤖 Generated with Claude Code

- operation: filter_gadgets annotates a copy (dataclasses.replace) instead
  of mutating the shared input Gadget objects, removing the cross-operation
  aliasing hazard; replace() also gives each match fresh side-effect sets
- ropchain: _build_per_comb_gadgets sorts each operation's gadget list once
  and memoises the filter/prune result per (step, dst, src), avoiding the
  previous O(combinations x gadgets) re-filter+re-sort
- arch: add ArchitectureSingleton.reset() to encapsulate the global state
  (used by the test fixtures instead of poking the private attribute)
- style: isinstance() instead of type() == ... (operation, yaml parser);
  move imports above module constants in gadfinder; pin lower bounds for
  pyelftools/pyyaml/macholib in requirements.txt

Tests: add filter_gadgets no-mutation regression and a ropchain search
suite (concrete, two-step, generic-register and not-found cases) to guard
the chain-build refactor. 59 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ricardojrdez ricardojrdez merged commit 1f1325a into master Jun 23, 2026
3 checks passed
@ricardojrdez ricardojrdez deleted the quality-cleanup branch June 23, 2026 17:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant