Skip to content

Fix robustness bugs, harden CI, support python 3.10-3.14, bump to 1.0.1 - #8

Merged
tomhea merged 3 commits into
mainfrom
claude/wonderful-matsumoto-973f98
Jun 10, 2026
Merged

tomhea merged 3 commits into
mainfrom
claude/wonderful-matsumoto-973f98

Conversation

@tomhea

@tomhea tomhea commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Pre-release hardening pass over the whole codebase, following a full security/bug review.

Compiler driver (c2fj_main.py)

  • Replace os.system + assert with subprocess.run(check=True) — the make invocation no longer vanishes under python -O (the call lived inside the assert), paths with spaces/shell metacharacters are passed safely (no shell), and failures raise RuntimeError instead of AssertionError.
  • No more module-global mutation — make vars are built per call, so sequential/concurrent c2fj() calls can't leak SINGLE_C_FILE/ELF_OUT_PATH into each other.
  • --finish-after elf|fj|fjm now requires --build-dir — previously the outputs were written into a temporary directory and silently deleted.
  • Quote the per-file variables in Makefile_single_c_generic so paths with spaces survive recipe expansion (covered by a new integration test).

RISC-V translation (riscv_instructions.py, riscv_to_fj.py)

  • Remove the pc_changed global; jal_op returns whether the pc changed and write_op tracks it locally.
  • write_rv32m_op raises InvalidOpcode on unmatched funct3 instead of writing nothing.
  • Plumb error_on_unimplemented_op through create_fj_files_from_riscv_elf (was a dead parameter).
  • Fix the invalid u_type return annotation.

Linker script

  • Also collect plain *(.text) input sections — objects built without -ffunction-sections (e.g. libgcc) were placed as orphan sections by heuristic.

Packaging

  • Version 1.0.0 → 1.0.1.
  • License id fixed to valid SPDX BSD-2-Clause (was BSD-2-Clause-Simplified, so the PyPI license classifier was wrong).
  • Python support is now exactly 3.10–3.14 (>=3.10,<3.15), classifiers updated accordingly.
  • Dependencies updated: pyelftools>=0.33, pytest^9, pytest-xdist^3.8 (all verified compatible with the new python range; flipjump>=1.3.0 unchanged — 1.3.0 is the latest).

CI

  • tests.yml: runs on push to main too, tests a 3.10–3.14 matrix, all actions pinned to commit SHAs (the previous pmeier/pytest-results-action@main was a mutable-branch supply-chain risk).
  • poetry-publish.yml: publishing is now gated on the tests passing, builds with poetry and publishes via pinned pypa/gh-action-pypi-publish. A comment notes the recommended follow-up migration to PyPI Trusted Publishing (needs one-time PyPI-side setup).

Repo hygiene & docs

  • gitattributes.txt → .gitattributes (it had no effect under the old name); removed the stray empty CMakeLists.
  • README: fixed --unify_fj → --unify-fj, outdated python3 c2fj.py usage → c2fj, stated supported python versions, and added a Known Limitations section (no EOF, div-by-zero exits with an error, no fence support).

Tests added

  • tests/test_riscv_instructions.py — pure-python unit tests for instruction encoding: inc_pc emission for ALU/jump/branch/syscall ops, pc-state isolation between ops, invalid-op fallback vs. raise, sign_extend/fj_hex.
  • tests/test_c2fj.py — new driver tests: failing make raises RuntimeError, make vars aren't mutated, finish_after without build_dir raises, compiling from a directory with spaces, and two sequential compilations (c-file then Makefile) in one process.

Test plan

  • 21 new unit/driver tests pass locally (Windows, py3.11)
  • Full integration suite (needs riscv64 gcc + picolibc) passes on the CI matrix 3.10–3.14

🤖 Generated with Claude Code

tomhea and others added 3 commits June 10, 2026 14:13
Compiler driver:
- Replace os.system + assert with subprocess.run(check=True): the make
  call no longer disappears under `python -O`, paths with spaces and
  shell metacharacters are passed safely, and failures raise a
  RuntimeError instead of an AssertionError.
- Stop mutating the module-level C2FJ_MAKE_VARS; build the make vars
  per call so sequential/concurrent c2fj() calls don't leak state.
- Quote the per-file variables in Makefile_single_c_generic so paths
  with spaces survive the recipe expansion.
- Raise a clear ValueError when --finish-after elf/fj/fjm is used
  without --build-dir (the outputs used to be silently deleted with
  the temporary build directory).

riscv instructions:
- Remove the pc_changed global; jal_op now returns whether the pc was
  changed, and write_op tracks it locally.
- Make write_rv32m_op raise InvalidOpcode on unmatched funct3, fix the
  u_type annotation, and plumb error_on_unimplemented_op through
  create_fj_files_from_riscv_elf.

Linker script:
- Also collect plain *(.text) input sections (objects built without
  -ffunction-sections were placed as orphan sections).

Packaging & CI:
- Bump version to 1.0.1, fix the license id to the valid SPDX
  BSD-2-Clause, support exactly python 3.10-3.14, and update the
  dependency floors (pyelftools>=0.33, pytest^9, pytest-xdist^3.8).
- Tests workflow: run on push to main too, test on a 3.10-3.14 matrix,
  pin all actions to commit SHAs, drop the mutable @main action ref.
- Publish workflow: gate publishing on the tests passing, build with
  poetry and publish with pypa/gh-action-pypi-publish (pinned), with a
  note about migrating to PyPI Trusted Publishing.
- Rename gitattributes.txt to .gitattributes so it takes effect, and
  remove the stray empty CMakeLists file.

Docs & tests:
- README: fix the --unify-fj flag name and the c2fj usage line, state
  the supported python versions, and document the known limitations
  (no EOF, div-by-zero exits, no fence).
- Add unit tests for the riscv instruction encoding (inc_pc behavior,
  syscall jals, invalid-op fallback) and driver tests for the new
  error paths, path-with-spaces compilation, and make-vars isolation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Make tests.yml reusable (workflow_call) and call it from the publish
  workflow, so releases are gated on the full python 3.10-3.14 matrix
  instead of a duplicated single-version test job.
- Cache pip in the tests workflow (keyed on pyproject.toml).
- Raise a dedicated MakeFailedError (RuntimeError subclass) instead of
  a bare RuntimeError when the make step fails.
- Plumb error_on_unimplemented_op through compile_riscv_to_fj and
  c2fj(), completing the previously half-plumbed parameter.
- Quote the c2fj-provided paths in the README example Makefile, in
  line with the generic single-c Makefile.
- Extract the duplicated bad-C-file setup in tests into a helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tomhea
tomhea merged commit 2f37b4c into main Jun 10, 2026
6 checks passed
@tomhea
tomhea deleted the claude/wonderful-matsumoto-973f98 branch June 10, 2026 16:45
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