Skip to content

Fix StackOverflowError due to non-commuting TransitionFunctionImpl.combineWith - #281

Merged
swissiety merged 3 commits into
secure-software-engineering:developfrom
marcus-h:fixStackOverflowError
Sep 23, 2026
Merged

swissiety merged 3 commits into
secure-software-engineering:developfrom
marcus-h:fixStackOverflowError

Conversation

@marcus-h

Copy link
Copy Markdown
    Fix StackOverflowError due to non-commuting TransitionFunctionImpl.combineWith
    
    According to the theory, the combineWith operation of the
    TransitionFunctionImpl class has to be, among other things, commuative. This
    can result in a StackOverflowError (see
    VectorTest.testNoStackOverflowDueToNonCommutativeCombineWith for a reproducer).
    Excerpt from the stack trace:
    
            ...
            at wpds.impl.PostStar.update(PostStar.java:335)
            at wpds.impl.PostStar$HandleNormalListener.onOutTransitionAdded(PostStar.java:227)
            at wpds.impl.WeightedPAutomaton.addWeightForTransition(WeightedPAutomaton.java:329)
            at sync.pds.solver.SyncPDSSolver$4.addWeightForTransition(SyncPDSSolver.java:194)
            at wpds.impl.PostStar.update(PostStar.java:335)
            at wpds.impl.PostStar$HandleNormalListener.onOutTransitionAdded(PostStar.java:227)
            at wpds.impl.WeightedPAutomaton.addWeightForTransition(WeightedPAutomaton.java:329)
            at sync.pds.solver.SyncPDSSolver$4.addWeightForTransition(SyncPDSSolver.java:194)
            at wpds.impl.PostStar.update(PostStar.java:335)
            at wpds.impl.PostStar$HandleNormalListener.onOutTransitionAdded(PostStar.java:227)
            at wpds.impl.WeightedPAutomaton.addWeightForTransition(WeightedPAutomaton.java:329)
            at sync.pds.solver.SyncPDSSolver$4.addWeightForTransition(SyncPDSSolver.java:194)
            at wpds.impl.PostStar.update(PostStar.java:335)
            at wpds.impl.PostStar$HandleNormalListener.onOutTransitionAdded(PostStar.java:227)
            at wpds.impl.WeightedPAutomaton.addWeightForTransition(WeightedPAutomaton.java:329)
            at sync.pds.solver.SyncPDSSolver$4.addWeightForTransition(SyncPDSSolver.java:194)
            at wpds.impl.PostStar.update(PostStar.java:335)
            ...
    
    When combining the two paths in doSth, a new TransitionFunctionImpl is created
    where the statement sequences are merged but the stateChangeStatement from one
    of the path is used. The latter causes the
    PostStar.update <-> WeightedPAutomaton.addWeightForTransition "ping-pong".
    In order to fix this, store stateChangeStatement(s) from both paths in a set.
    
    Implementation note: a LinkedHashSet is used so the getStateChangeStatement()
    can be easily implemented (whether the method itself is "meaningful" is
    debatable, though).

…mbineWith

According to the theory, the combineWith operation of the
TransitionFunctionImpl class has to be, among other things, commuative. This
can result in a StackOverflowError (see
VectorTest.testNoStackOverflowDueToNonCommutativeCombineWith for a reproducer).
Excerpt from the stack trace:

	...
	at wpds.impl.PostStar.update(PostStar.java:335)
	at wpds.impl.PostStar$HandleNormalListener.onOutTransitionAdded(PostStar.java:227)
	at wpds.impl.WeightedPAutomaton.addWeightForTransition(WeightedPAutomaton.java:329)
	at sync.pds.solver.SyncPDSSolver$4.addWeightForTransition(SyncPDSSolver.java:194)
	at wpds.impl.PostStar.update(PostStar.java:335)
	at wpds.impl.PostStar$HandleNormalListener.onOutTransitionAdded(PostStar.java:227)
	at wpds.impl.WeightedPAutomaton.addWeightForTransition(WeightedPAutomaton.java:329)
	at sync.pds.solver.SyncPDSSolver$4.addWeightForTransition(SyncPDSSolver.java:194)
	at wpds.impl.PostStar.update(PostStar.java:335)
	at wpds.impl.PostStar$HandleNormalListener.onOutTransitionAdded(PostStar.java:227)
	at wpds.impl.WeightedPAutomaton.addWeightForTransition(WeightedPAutomaton.java:329)
	at sync.pds.solver.SyncPDSSolver$4.addWeightForTransition(SyncPDSSolver.java:194)
	at wpds.impl.PostStar.update(PostStar.java:335)
	at wpds.impl.PostStar$HandleNormalListener.onOutTransitionAdded(PostStar.java:227)
	at wpds.impl.WeightedPAutomaton.addWeightForTransition(WeightedPAutomaton.java:329)
	at sync.pds.solver.SyncPDSSolver$4.addWeightForTransition(SyncPDSSolver.java:194)
	at wpds.impl.PostStar.update(PostStar.java:335)
	...

When combining the two paths in doSth, a new TransitionFunctionImpl is created
where the statement sequences are merged but the stateChangeStatement from one
of the path is used. The latter causes the
PostStar.update <-> WeightedPAutomaton.addWeightForTransition "ping-pong".
In order to fix this, store stateChangeStatement(s) from both paths in a set.

Implementation note: a LinkedHashSet is used so the getStateChangeStatement()
can be easily implemented (whether the method itself is "meaningful" is
debatable, though).

@swissiety swissiety left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment thread idealPDS/src/main/java/typestate/TransitionFunctionImpl.java Outdated
Address review: storing every TransitionFunctionImpl's state change
statement in a LinkedHashSet costs a set per weight, although only
combineWith ever produces more than one statement. TransitionFunctionImpl
keeps its single Statement field again, and the new package-private
CombinedTransitionFunctionImpl holds the set.

combineWith only builds a combined function when the merged set has at
least two statements, so combining a function with itself still yields
an equal plain TransitionFunctionImpl. A combined function compares its
statements as a set, ignoring the order in which they were combined.
Combining with ONE (in either order) keeps the combined statements.

@swissiety swissiety left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

@swissiety
swissiety merged commit bbd8b51 into secure-software-engineering:develop Sep 23, 2026
9 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.

2 participants