Skip to content

Stop poisoning the Joern REPL with a repeated importCpg - #3

Open
Braindea7 wants to merge 1 commit into
Hackbard:mainfrom
Braindea7:fix/joern-repl-poisoned-by-repeated-importcpg
Open

Stop poisoning the Joern REPL with a repeated importCpg#3
Braindea7 wants to merge 1 commit into
Hackbard:mainfrom
Braindea7:fix/joern-repl-poisoned-by-repeated-importcpg

Conversation

@Braindea7

Copy link
Copy Markdown

The Joern backend is limited to one usable query per lmc up, and it fails silently.

What happens

run_cpgql prefixes every query with importCpg(...). On a server that already has the CPG loaded, that import fails — and the REPL's own error renderer throws while formatting the failure:

java.lang.NullPointerException: Cannot invoke "java.lang.CharSequence.length()" because "raw" is null
  at fansi.Str$.apply(Fansi.scala:268)
  at replpp.Rendering.renderError(Rendering.scala:168)

From then on the REPL is dead — every further query fails too, with or without an import.

The silent part: the REST layer still answers success: true, so JoernClient.run hands back an empty result and lmc callers --engine joern reports {"1": []}. A zero hit that looks like an answer, which is the worst possible shape for a tool people use to judge blast radius.

Reproducing

Freshly started server, the same query twice:

result
1st query after lmc up val res2: Int = 2
2nd query, identical NullPointerException in stdout, success: true, empty result
via REST, importing once, then two queries without res3: Int = 2, res4: Int = 165

The third row isolates the cause: it is not "the second query", it is the repeated import.

The fix

  • run_cpgql runs the query first and only imports when the server says No projects loaded. A query against a server with no CPG fails cleanly and leaves the REPL intact — verified — so this path is safe. Costs one extra request on a cold start, none afterwards.
  • JoernClient.run treats a REPL error in stdout as a failure instead of reporting success with an empty result. This is what turns any future REPL problem into a visible error rather than a silent zero.

Measured

Against a real CPG (intranet2.0, 2.5M nodes, 44990 methods), three queries in a row on a freshly started server, both runs with the same 120s default timeout:

before:  success=true, result=''  on all three   (crash in stdout)
after:   '2' (49.5s, cold-start import) -> '165' (0.5s) -> '44990' (0.5s)

Known gap

If a different CPG is loaded (another worktree hash), the server does not answer No projects loaded — it answers the query against the wrong graph. That case is not addressed here and needs a separate check on the loaded project, which I did not want to guess at.

`run_cpgql` prefixed every query with `importCpg(...)`. On a server that
already has the CPG loaded that import fails -- and the REPL's own error
renderer throws while formatting the failure:

    java.lang.NullPointerException: Cannot invoke
      "java.lang.CharSequence.length()" because "raw" is null
      at fansi.Str$.apply(Fansi.scala:268)
      at replpp.Rendering.renderError(Rendering.scala:168)

From then on the REPL is dead: every further query fails too, with or
without an import. In effect the server was limited to one usable query
per `lmc up`.

Worse, it fails silently. The REST layer still answers success=true, so
`JoernClient.run` returned an empty `result` and `lmc callers --engine
joern` reported `{"1": []}` -- a zero hit that looks like an answer.

Two changes:

* `run_cpgql` runs the query first and only imports when the server says
  "No projects loaded". A query against a server with no CPG fails
  cleanly and leaves the REPL intact, so this path is safe; it costs one
  extra request on a cold start and none afterwards.
* `JoernClient.run` treats a REPL error in stdout as a failure instead of
  reporting success with an empty result.

Measured against intranet2.0 (2.5M nodes), three queries in a row on a
freshly started server, same 120s default timeout:

  before: success=true, result='' on all three (crash in stdout)
  after:  '2' (49.5s, cold-start import), '165' (0.5s), '44990' (0.5s)
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.

2 participants