Skip to content
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

StringLiteral.getLiteralValue is not thread-safe #3424

Open
martinlippert opened this issue Dec 9, 2024 · 9 comments
Open

StringLiteral.getLiteralValue is not thread-safe #3424

martinlippert opened this issue Dec 9, 2024 · 9 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@martinlippert
Copy link

It looks like StringLiteral.getLiteralValue is throwing IllegalStateExceptions in some cases when used from multiple threads, most likely due to the internal scanner object being used in a stateful way.

@jukzi
Copy link
Contributor

jukzi commented Dec 9, 2024

Please paste the Exception Stacktrace and why it is used in multiple threads

@martinlippert
Copy link
Author

Example stack traces can be found here: spring-projects/sts4#1434 - but this comes from the Spring Tools using JDT Core to parse and analyze source code, so the stack traces have no origins in JDT or Eclipse itself.

We use the AST over there to implement content-assist, do additional validations, and extract index information from a Spring perspective.

@jukzi
Copy link
Contributor

jukzi commented Dec 9, 2024

That reference only shows a IllegalArgumentException, not a IllegalStateException , also the line number does not match master.
The IllegalArgumentException complains tokenType!=TerminalTokens.TokenNameStringLiteral

I don't see a connection to concurrent use. You should be able to set a breakpoint to find the sourcecode in question that cannot be parsed.

@martinlippert
Copy link
Author

That reference only shows a IllegalArgumentException, not a IllegalStateException , also the line number does not match master. The IllegalArgumentException complains tokenType!=TerminalTokens.TokenNameStringLiteral

You are right, my bad, it is an IllegalArgumentException, not an IllegalStateException. The line numbers are from using JDT Core 3.39.

I don't see a connection to concurrent use. You should be able to set a breakpoint to find the sourcecode in question that cannot be parsed.

I am not yet convinced about this not being related to concurrent use, but let me try to dig deeper here. Always hard to reproduce those things, but let me see what I can find out with our hints here. Thanks so much for looking into this so quickly and for providing the feedback here.

@jukzi
Copy link
Contributor

jukzi commented Jan 2, 2025

This issue still has not enough information to process.

@martinlippert
Copy link
Author

martinlippert commented Jan 2, 2025

@jukzi I am on it and will provide more details / information as soon as possible... :-)

@martinlippert
Copy link
Author

I created a code snippet to reproduce this issue with concurrent calls to getLiteralValue:

ASTParser parser = ASTParser.newParser(AST.JLS21);
parser.setSource("\"hello\\nworld\"".toCharArray());
parser.setKind(ASTParser.K_EXPRESSION);
ASTNode ast = parser.createAST(null);

final StringLiteral literal = (StringLiteral) ast;

ExecutorService executorService = Executors.newFixedThreadPool(10);
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
	CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
		try {
			literal.getLiteralValue();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}, executorService);
	futures.add(future);
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
executorService.shutdown();

This should result in a few exceptions being thrown due to issues within getLiteralValue due to concurrent access to it.

Looking at the implementation of getLiteralValue it seems that the scanner object is the culprit. It is used to scan the escaped value in a stateful way, but calls to getLiteralValue always use the same scanner object.

jukzi added a commit to jukzi/eclipse.jdt.core that referenced this issue Jan 3, 2025
org.eclipse.jdt.core.dom.StringLiteral.getLiteralValue() unsynchronized
use of shared org.eclipse.jdt.core.dom.AST.scanner

reproducer for
eclipse-jdt#3424
@jukzi
Copy link
Contributor

jukzi commented Jan 3, 2025

was already reported in https://bugs.eclipse.org/bugs/show_bug.cgi?id=508586

@jukzi jukzi added help wanted Extra attention is needed and removed needinfo Further information is requested labels Jan 3, 2025
@jukzi
Copy link
Contributor

jukzi commented Jan 3, 2025

as per https://bugs.eclipse.org/bugs/show_bug.cgi?id=508586#c14 the scanner should be cloned. @martinlippert can you contribute a fix?

@jukzi jukzi added the bug Something isn't working label Jan 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants