mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
fix(cpg): the closure-defect exclusion stops at Joern 4.0.625, where upstream fixed it
joern#6281 is closed as fixed in v4.0.625 (verified here on the reproducer). The version is read off the jar beside the launcher; below 4.0.625 the miscompiled file is still excluded, at or above it nothing is, and an install whose version cannot be read keeps the workaround. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
b6cccd1444
commit
9f881b433e
@@ -128,6 +128,34 @@ _INTERPRETERS: dict[str, str] = {"php": "php"}
|
||||
# other 99.8%, which is the difference between a scan and no scan at all. They are reported as `unparsed`,
|
||||
# so the coverage section names them rather than implying they were clean.
|
||||
_CLOSURE = re.compile(r"\bfunction\s*\(")
|
||||
|
||||
# The release that fixes the miscompile (joernio/joern#6281, same root cause as #6269, fixed by #6270).
|
||||
# At or above it the exclusion below is a loss with nothing to buy, so it is not applied.
|
||||
CLOSURE_DEFECT_FIXED_IN = (4, 0, 625)
|
||||
_JOERN_JAR = re.compile(r"^io\.joern\.joern-cli-(\d+)\.(\d+)\.(\d+)\.jar$")
|
||||
|
||||
|
||||
def joern_version() -> tuple[int, int, int] | None:
|
||||
"""The installed Joern's version, read off the jar beside the launcher; ``None`` when it cannot be told.
|
||||
|
||||
The launcher is a shell script with no `--version`, and every release ships `lib/io.joern.joern-cli-X.Y.Z.jar`
|
||||
next to it. Unknown is unknown: a caller gating a workaround on this keeps the workaround.
|
||||
"""
|
||||
launcher = shutil.which("joern")
|
||||
if launcher is None:
|
||||
return None
|
||||
lib = Path(launcher).resolve().parent / "lib"
|
||||
try:
|
||||
names = [entry.name for entry in lib.iterdir()]
|
||||
except OSError:
|
||||
return None
|
||||
for name in names:
|
||||
match = _JOERN_JAR.match(name)
|
||||
if match:
|
||||
return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
|
||||
return None
|
||||
|
||||
|
||||
_GLOBAL_IN_BODY = re.compile(r"\bglobal\s+\$")
|
||||
FRONTEND_BUILD_ATTEMPTS = 4
|
||||
|
||||
@@ -344,6 +372,9 @@ class JoernBackend:
|
||||
"""
|
||||
if language.lower() != "php":
|
||||
return ()
|
||||
version = joern_version()
|
||||
if version is not None and version >= CLOSURE_DEFECT_FIXED_IN:
|
||||
return () # fixed upstream; nothing to exclude and every file to keep
|
||||
found: list[str] = []
|
||||
for path in sorted(root.rglob("*.php")):
|
||||
if not path.is_file():
|
||||
|
||||
@@ -1042,3 +1042,34 @@ def test_a_build_that_fails_on_both_launchers_leaves_no_scratch_behind(tmp_path:
|
||||
monkeypatch.setattr("shutil.which", lambda name: f"/opt/bin/{name}")
|
||||
assert JoernBackend(runner=runner).build(tmp_path, language="javascript") is None
|
||||
assert list(scratch_root.iterdir()) == [], "the failed build's scratch directory is gone"
|
||||
|
||||
|
||||
def test_the_closure_exclusion_stops_at_the_release_that_fixed_it(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""joern#6281 is fixed in v4.0.625. Below it the miscompiled file is excluded (the whole graph is the
|
||||
alternative); at or above it nothing is excluded, because a loss with nothing to buy is only a loss.
|
||||
An install whose version cannot be read keeps the exclusion: unknown is not "fixed"."""
|
||||
from openultrasast.cpg.backend import JoernBackend, joern_version
|
||||
|
||||
(tmp_path / "bad.php").write_text('<?php\nfunction f($n) {\n h("p", function($p) { global $g; return $p . $g; });\n}\n')
|
||||
|
||||
def install(version: str) -> Path:
|
||||
home = tmp_path / f"joern-{version}"
|
||||
(home / "lib").mkdir(parents=True)
|
||||
(home / "lib" / f"io.joern.joern-cli-{version}.jar").write_bytes(b"")
|
||||
(home / "joern").write_text("#!/bin/sh\n")
|
||||
return home / "joern"
|
||||
|
||||
old, new = install("4.0.623"), install("4.0.625")
|
||||
backend = JoernBackend(runner=lambda c, **k: None)
|
||||
|
||||
monkeypatch.setattr("shutil.which", lambda name: str(old) if name == "joern" else None)
|
||||
assert joern_version() == (4, 0, 623)
|
||||
assert [Path(n).name for n in backend._files_with_frontend_defect(tmp_path, "php")] == ["bad.php"]
|
||||
|
||||
monkeypatch.setattr("shutil.which", lambda name: str(new) if name == "joern" else None)
|
||||
assert joern_version() == (4, 0, 625)
|
||||
assert backend._files_with_frontend_defect(tmp_path, "php") == ()
|
||||
|
||||
monkeypatch.setattr("shutil.which", lambda name: "/opt/bin/joern")
|
||||
assert joern_version() is None
|
||||
assert [Path(n).name for n in backend._files_with_frontend_defect(tmp_path, "php")] == ["bad.php"], "unknown keeps the workaround"
|
||||
|
||||
Reference in New Issue
Block a user