Skip to content

Raise JavaNotFoundError when the java executable cannot be run - #53

Merged
twizmwazin merged 1 commit into
masterfrom
feature/javanotfound
Aug 23, 2026
Merged

twizmwazin merged 1 commit into
masterfrom
feature/javanotfound

Conversation

@zardus

@zardus zardus commented Aug 22, 2026 •

Copy link
Copy Markdown
Member

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

With JAVA_HOME unset, _get_java_home() locates a JVM by running java -XshowSettings:properties. With no usable java on PATH, subprocess.run raises FileNotFoundError, which escapes Lifter() rather than the JavaNotFoundError the same function raises a few lines below — so a caller that handles the typed error still cannot tell a missing JVM from a defect in the input. A corpus of roughly 19,000 units was filed as analysis errors on that.

The call now raises JavaNotFoundError from the original error, catching OSError rather than FileNotFoundError so that a java which is present but not executable is the same condition. It does not make a jar analysable — that still needs a reachable JVM and a filename Soot accepts by suffix — only reportable.

The regression clears the environment, points PATH at an empty directory, and asserts that Lifter() on the existing simple1.jar fixture raises JavaNotFoundError.

Validation: #53 (comment)

@zardus

zardus commented Aug 22, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Validation record for head d3833fc against baseline 2c70c83289cecaa7f1ecc2b8f2b24bf9406fe93f.

  • Regression: pytest tests/test_pysoot.py::TestPySoot::test_no_java_on_path — with only pysoot/lifter.py reverted to the baseline it fails with FileNotFoundError: [Errno 2] No such file or directory: 'java' raised at pysoot/lifter.py:106; on head it passes
  • Focused: pytest tests — 7 passed, 2 skipped, with a JVM present (openjdk 25.0.4), so the new test does not depend on the host lacking Java
  • Lint/type: pre-commit run --all-files — ruff check and ruff format pass; merge-base-relative pylint 9.55 -> 9.57 for pysoot/lifter.py and 9.17 -> 9.24 for tests/test_pysoot.py; pyright badness unchanged or lower on both
  • Workspace gate: nix develop --command run-all-tests.sh --jobs 2 in the ANGR_FEATURE=javanotfound feature shell with all nine repositories adopted, so no suite was skipped — all 13 suites passed (workspace, test-inputs, pre-commit, feature-instances, archinfo 17, pypcode 46 + 187 subtests, pyvex 64, pysoot 7 + 2 skipped, cle 202 + 9 skipped, claripy 331 + 1 skipped, angr 2471 + 46 skipped + 2 xfailed + 260 subtests, angr Rust 35, angr-management 533), ending in All selected angr workspace test suites passed. Revisions under test: angr 0c293dc0d, angr-management 1de55253, archinfo da171ca, binaries 12d67ec, claripy c0b78b21, cle b58ea02, pypcode 559aacd, pysoot d3833fc, pyvex 90e9094
  • Flake ruled out: an earlier gate run at the default --jobs 4, on a host also carrying an unrelated 6-worker batch job, failed angr-management tests/test_mcp_server.py::TestMCPLoadBinary::test_load_uses_default_analysis_settings_without_prompting with RuntimeError: The MCP server did not start within 10.0 seconds. Run alone it passes 5 of 5 in about 2.5s against that 10s budget, and the whole angr-management suite then passed at --jobs 2; it is a startup timeout under load, not a regression, and nothing in this diff is reachable from it
  • Scope: subprocess.run at pysoot/lifter.py:106 is the only external-process invocation in the package — one import subprocess, one call site — and soot_manager starts the JVM in-process through JPype, so no sibling call site carries this defect

Caveats: test_android1 skipped (no Android SDK) and test_textcrunchr1 skipped (binaries-private absent), both pre-existing. Python 3.12.13 on Linux.

@angr-bot

Copy link
Copy Markdown
Member

Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/pysoot_53

@twizmwazin

Copy link
Copy Markdown
Member

@zardus rebase

_get_java_home() falls back to running "java -XshowSettings:properties"
when JAVA_HOME is unset. On a host with no usable java, subprocess.run
raises FileNotFoundError, which escaped Lifter() instead of the
JavaNotFoundError the same function raises when no java.home is reported,
so a caller could not tell a missing JVM from a defect in its input.

Catch OSError rather than FileNotFoundError: a java that exists but is
not executable is the same condition, and narrowing to the one errno
observed would leave the rest of that class escaping as this one did.
@zardus
zardus force-pushed the feature/javanotfound branch from d3833fc to 397e186 Compare August 23, 2026 19:55
@zardus

zardus commented Aug 23, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Rebased onto master at 397e18615, now that #52 has landed.

The only conflict was in tests/test_pysoot.py, and it was adjacency rather than substance: #52 and this branch each add tests and each extend the same two import lines. Both sides are kept — the imports are merged into from pysoot.errors import JavaNotFoundError, UnsupportedClassFileVersionError and from pysoot.lifter import Lifter, _check_class_file_versions, and all three tests survive. git range-diff across the rebase shows the commit's content otherwise unchanged. pysoot/lifter.py merged cleanly: #52's class-file-version check and this branch's except OSError -> JavaNotFoundError sit in different functions.

Full suite on the rebased head: pytest tests/test_pysoot.py — 9 passed, 2 skipped, with a JDK on JAVA_HOME. That includes #52's test_unsupported_class_file_version against the simple1_java17.jar fixture from angr/binaries#187, and this branch's test_no_java_on_path.

@twizmwazin
twizmwazin merged commit 4b449bf into master Aug 23, 2026
28 checks passed
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.

3 participants