Skip to content

HHH-19429 Fix potential ConcurrentModificationException in AbstractSqmPath #10655

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

bwaldvogel
Copy link
Contributor

@bwaldvogel bwaldvogel commented Jul 29, 2025

Add a concurrency test that reliably reproduces the ConcurrentModificationException inside AbstractSqmPath.resolvePath when multiple threads execute a query. See HHH-19429 for more details.

We fix the potential ConcurrentModificationException by switching from HashMap to ConcurrentHashMap in AbstractSqmPath.

Please let me know what I need to adjust to match Hibernate’s project rules and conventions.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license
and can be relicensed under the terms of the LGPL v2.1 license in the future at the maintainers' discretion.
For more information on licensing, please check here.


@beikov
Copy link
Member

beikov commented Jul 29, 2025

Thanks for attempting to fix this problem and providing a PR. It would IMO be better though to avoid the mutation in the first place i.e. BaseSqmToSqlAstConverter should IMO not mutate the SQM tree.

@bwaldvogel
Copy link
Contributor Author

@beikov: Thanks, I tried to address your comment in 9803134. I might have missed the point though. Please let me know if I've taken a wrong turn.

Here’s my reasoning behind the change:

Lazily initializing the reusablePaths map is inherently a data race. I guess this was done to avoid the costs of the HashMap if it’s not needed? My suggestion is to pre-initialize it to avoid the data race but use a zero initial size for the ConcurrentHashMap to avoid the memory overhead. This might cause many resizes though and might be a bad idea.

As far as I understood, we need some kind of locking / synchronization mechanism at least somewhere in the code path between QuerySqmImpl.executeUpdate and AbstractSqmPath.resolvePath. I might missed the point where you think that locking/synchronization should happen?

@beikov
Copy link
Member

beikov commented Jul 30, 2025

Thanks, but you're missing the point. BaseSqmToSqlAstConverter should not cause mutations in the first place. We will have to figure out which call sites in BaseSqmToSqlAstConverter currently do cause mutations and replace them, such that it is thread safe by e.g. allocating the SqmBasicValuedSimplePath or EntityDiscriminatorSqmPath directly.

As far as I can see, problematic call sites in BaseSqmToSqlAstConverter are:

  • sqmStatement.getRoot().get( versionMapping.getPartName() ) in addVersionedAssignment
  • sqmStatement.getTarget().get( versionAttributeName ) in visitInsertionTargetPaths
  • 2x temporalPath.get( ZONE_OFFSET_NAME ) in transformDurationArithmetic
  • lhs.type() in createTreatTypeRestriction

@bwaldvogel
Copy link
Contributor Author

bwaldvogel commented Jul 30, 2025

@beikov Ok, I kind of expected that I missed the point. Unfortunately I guess I’m way too unfamiliar with the Hibernate codebase to make a useful contribution in this case.
Should I rather close this MR or should I rework to only add the unit test?

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