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

NPE in OnClassCondition.resolveOutcomesThreaded following thread interruption because firstHalf is null #41709

Closed
claussenj opened this issue Aug 7, 2024 · 4 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@claussenj
Copy link

This is a follow-up of issue #41492.

We have now deployed Spring Boot 3.3.2 in the affected environment and the original problem addressed in the issue above still exists even though the code change is in place: We get the NPE "because "firstHalf" is null" and the process exits but the original exception is not logged.

When running with -XX:ActiveProcessorCount=1 I have found an InterruptedException from kafka while processing some event. The stack trace does not fit, but I take the idea: What if an InterruptedException is thrown ThreadedOutcomesResolver.resolveOutcomes()? Then line 166 is hit and still a NPE can occur because this.outcomes is not initialized.

best regards
Jens

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 7, 2024
@snicoll
Copy link
Member

snicoll commented Aug 8, 2024

@claussenj I am surprised the original fix did not work. Is there a way for us to reproduce the issue? Can you share a small sample with instructions?

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Aug 8, 2024
@claussenj
Copy link
Author

Hi Stephane @snicoll,
I have tried to reproduce and construct a local example, but without success. Even more strange, today the issue was not even reproducible in the affected environment. Not sure what is going on. Let's close this issue for now. If it comes back I'll open a new one after my vacation.
regards
Jens

@snicoll snicoll closed this as not planned Won't fix, can't repro, duplicate, stale Aug 8, 2024
@snicoll
Copy link
Member

snicoll commented Aug 8, 2024

Thanks for following-up.

If it comes back I'll open a new one after my vacation.

Please don't, and rather add a comment here and we can reopen this one.

@snicoll snicoll removed status: waiting-for-feedback We need additional information before we can continue status: waiting-for-triage An issue we've not yet triaged labels Aug 8, 2024
@philwebb philwebb added the status: invalid An issue that we don't feel is valid label Aug 16, 2024
@claussenj
Copy link
Author

claussenj commented Oct 22, 2024

Hello Team,
finally the issue has indeed come back and we have made good progress analyzing it. Let me know if we can reopen this one or should I open a new one?

  • Spring Boot Version 3.3.4

Here are the details:

  1. A -javaagent calls Thread.currentThread().interrupt() on the main thread. You may argue that this should not happen, and indeed we are chasing this aspect of the problem as well.
  2. The resulting InterruptedException is handled here:
  3. When the InterruptedException is caught then ThreadedOutcomesResolver.outcomes is null
  4. When ThreadedOutcomesResults.outcomes is null then firstHalf is null here

As a temp workaround we set ThreadedOutcomesResolver.outcomes to an empty array when the InterruptedException is caught. Maythe the same should also take place when an exception is caught in the thread

Here are the exceptions:

java.lang.InterruptedException
at java.base/java.lang.Object.wait(Native Method)
at java.base/java.lang.Thread.join(Thread.java:1313)
at java.base/java.lang.Thread.join(Thread.java:1381)
at org.springframework.boot.autoconfigure.condition.OnClassCondition$ThreadedOutcomesResolver.resolveOutcomes(OnClassCondition.java:169)
at org.springframework.boot.autoconfigure.condition.OnClassCondition.resolveOutcomesThreaded(OnClassCondition.java:70)
at org.springframework.boot.autoconfigure.condition.OnClassCondition.getOutcomes(OnClassCondition.java:53)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.match(FilteringSpringBootCondition.java:49)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$ConfigurationClassFilter.filter(AutoConfigurationImportSelector.java:366)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry(AutoConfigurationImportSelector.java:131)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup.process(AutoConfigurationImportSelector.java:430)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping.getImports(ConfigurationClassParser.java:813)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:743)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:714)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:183)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:417)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:290)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:349)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:118)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:789)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:607)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
at com.sap.crun.perfmon.Application.main(Application.java:39)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)

Exception finally leading to crash (same as before):
"java.lang.NullPointerException: Cannot read the array length because \"firstHalf\" is null"
"\tat org.springframework.boot.autoconfigure.condition.OnClassCondition.resolveOutcomesThreaded(OnClassCondition.java:73)"
"\tat org.springframework.boot.autoconfigure.condition.OnClassCondition.getOutcomes(OnClassCondition.java:53)"
"\tat org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.match(FilteringSpringBootCondition.java:49)"
"\tat org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$ConfigurationClassFilter.filter(AutoConfigurationImportSelector.java:366)"
"\tat org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry(AutoConfigurationImportSelector.java:131)"
"\tat org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup.process(AutoConfigurationImportSelector.java:430)"
"\tat org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping.getImports(ConfigurationClassParser.java:813)"
"\tat org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:743)"
"\tat org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:714)"
"\tat org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:183)"
"\tat org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:417)"
"\tat org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:290)"
"\tat org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:349)"
"\tat org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:118)"
"\tat org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:789)"
"\tat org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:607)"
"\tat org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)"
"\tat org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)"
"\tat org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)"
"\tat org.springframework.boot.SpringApplication.run(SpringApplication.java:335)"
"\tat org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)"
"\tat org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)"
"\tat com.sap.crun.perfmon.Application.main(Application.java:39)"
"\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)"
"\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)"
"\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)"
"\tat java.base/java.lang.reflect.Method.invoke(Method.java:569)"
"\tat org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102)"
"\tat org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)"
"\tat org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)"]}

Let me know if any other details are needed.

regards
Jens

@wilkinsona wilkinsona reopened this Oct 22, 2024
@wilkinsona wilkinsona added status: waiting-for-triage An issue we've not yet triaged and removed status: invalid An issue that we don't feel is valid labels Oct 22, 2024
@wilkinsona wilkinsona changed the title 3.3.2 NPE during auto-configuration in OnClassCondition.resolveOutcomesThreaded because firstHalf is null NPE in OnClassCondition.resolveOutcomesThreaded following thread interruption because firstHalf is null Oct 24, 2024
@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 24, 2024
@wilkinsona wilkinsona added this to the 3.2.x milestone Oct 24, 2024
@wilkinsona wilkinsona self-assigned this Oct 24, 2024
@wilkinsona wilkinsona modified the milestones: 3.2.x, 3.2.12 Oct 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants