Skip to content

Fix NPE when copying a namespace set with a root sub-namespace#3881

Merged
unp1 merged 1 commit into
mainfrom
fix/namespaceset-null-parent-copy
Jul 2, 2026
Merged

Fix NPE when copying a namespace set with a root sub-namespace#3881
unp1 merged 1 commit into
mainfrom
fix/namespaceset-null-parent-copy

Conversation

@unp1

@unp1 unp1 commented Jul 1, 2026

Copy link
Copy Markdown
Member

Intended Change

Applying a splitting taclet interactively (e.g. dragging a formula into an
instantiation field and pressing Apply) could crash with a
NullPointerException:

java.lang.NullPointerException: Cannot invoke "org.key_project.logic.Namespace.copy()" because "v" is null
    at de.uka.ilkd.key.logic.NamespaceSet.lambda$copy$0(NamespaceSet.java:106)
    at de.uka.ilkd.key.logic.NamespaceSet.copy(NamespaceSet.java:106)
    at de.uka.ilkd.key.proof.Goal.adaptNamespacesNewGoals(Goal.java:715)
    at de.uka.ilkd.key.proof.Goal.apply(Goal.java:683)
    ...

Root cause. NamespaceSet.getParent() built its map by storing each
namespace's parent as the value:

namespaces.forEach((a, b) -> newSpaces.put(a, b.parent()));   // b.parent() may be null

A sub-namespace without an enclosing layer has no parent, so b.parent() is
null and the resulting map holds a null value. copy() (and likewise
copyWithParent() / getCompression()) then call v.copy() on that value and
throw. For the second and later goals of a splitting rule,
Goal.adaptNamespacesNewGoals does
localNamespaces.getParent().copy().copyWithParent(), which is where it blew up.

Fix. getParent() now substitutes an empty namespace for a missing parent
layer, so the "the map holds no null values" invariant that the other map
operations rely on keeps holding.

Type of pull request

  • Bug fix (non-breaking change which fixes an issue)
  • There are changes to the (Java) code

Ensuring quality

  • I made sure that introduced/changed code is well documented (javadoc and inline comments).
  • I added new test case(s) for new functionality (NamespaceSetTest.getParentOfRootNamespacesIsCopyable, which fails with the original NPE and passes with the fix).
  • I have tested the feature as follows: :key.core compiles and passes spotless; the new regression test is green (and verified red without the fix).
  • I have checked that runtime performance has not deteriorated (the change only avoids inserting a null map value).

Additional information and contact(s)

Created with AI tooling support

The contributions within this pull request are licensed under GPLv2 (only) for inclusion in KeY.

NamespaceSet.getParent() built its map by putting each namespace's parent
(b.parent()) as the value. A sub-namespace without an enclosing layer has no
parent, so b.parent() is null and the map ended up holding a null value. copy()
(and copyWithParent()/getCompression()) then call v.copy() on it and throw a
NullPointerException.

This surfaced when a splitting taclet is applied interactively: for the second
and later goals, Goal.adaptNamespacesNewGoals does
localNamespaces.getParent().copy().copyWithParent(), which hit the null. The
regression came in with generalizing NamespaceSet onto a Map (e8bc655) — the
previous fixed typed fields could not carry a null entry.

getParent() now substitutes an empty namespace for a missing parent layer, so
the "map holds no null values" invariant the other map operations rely on keeps
holding. Adds a regression test.

Created with AI tooling support
@unp1
unp1 marked this pull request as ready for review July 1, 2026 19:05
@unp1 unp1 added the 🐞 Bug label Jul 1, 2026
@unp1 unp1 added this to the v3.0.0 milestone Jul 1, 2026
@unp1 unp1 self-assigned this Jul 1, 2026
@unp1
unp1 enabled auto-merge July 1, 2026 19:36
@unp1 unp1 added the P:HIGH label Jul 2, 2026
@unp1
unp1 added this pull request to the merge queue Jul 2, 2026
Merged via the queue into main with commit b3add45 Jul 2, 2026
36 checks passed
@unp1
unp1 deleted the fix/namespaceset-null-parent-copy branch July 2, 2026 21:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants