| Summary: | NPE when invoking Platform.getInstallLocation() from multiple threads | ||
|---|---|---|---|
| Product: | [Eclipse Project] Platform | Reporter: | Rumen Georgiev <rumen.georgiev> |
| Component: | Runtime | Assignee: | DJ Houghton <dj.houghton> |
| Status: | RESOLVED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | abuehler, daniel_megert, john.arthorne, markus.kell.r, remy.suen, rumen.georgiev, tjwatson |
| Version: | 3.6 | ||
| Target Milestone: | 3.8 | ||
| Hardware: | PC | ||
| OS: | Windows 7 | ||
| Whiteboard: | |||
| Bug Depends on: | |||
| Bug Blocks: | 391900 | ||
Rumen, thanks for the bug report and great analysis!
I see many identical issues in InternalPlatform all around initializing a service tracker and then opening it:
org.eclipse.core.internal.runtime.InternalPlatform.getEnvironmentInfoService()
org.eclipse.core.internal.runtime.InternalPlatform.getFrameworkLog()
org.eclipse.core.internal.runtime.InternalPlatform.getBundleAdmin()
org.eclipse.core.internal.runtime.InternalPlatform.getDebugOptions()
org.eclipse.core.internal.runtime.InternalPlatform.getContentTypeManager()
org.eclipse.core.internal.runtime.InternalPlatform.getPreferencesService()
org.eclipse.core.internal.runtime.InternalPlatform.getBundleGroupProviders()
>org.eclipse.core.internal.runtime.InternalPlatform.getUserLocation()
>org.eclipse.core.internal.runtime.InternalPlatform.getConfigurationLocation()
>org.eclipse.core.internal.runtime.InternalPlatform.getInstallLocation()
>org.eclipse.core.internal.runtime.InternalPlatform.getInstanceLocation()
These last 4 are for trackers that are never closed on stop. I think this is an oversight, but we would have to ensure that other parts of the code are not expecting to get a location object from InternalPlatform after InternalPlatform.stop(BundleContext) is called. But at a minimum this will cause issues if we ever supported the core.runtime bundle being stopped and restarted because these trackers would be left non null but would be trying to use an invalid BundleContext.
I see at least two options for fixing this bug 1) add synchronization to all these methods 2) construct all the trackers in start(BundleContext) Tom and I talked about this and we'll do option 2. Fixed in master. http://git.eclipse.org/c/platform/eclipse.platform.runtime.git/commit/?id=f295d953913532ad08a9ff4853dd1c5a2129de73 Looks like this fix is not good, see bug 357211. There is a timing issue. With the new code we are registering some services (in this case the legacy preference service) before we open the service trackers. I have a fix in hand that I've tested works. I will release for the next i-build. *** Bug 357211 has been marked as a duplicate of this bug. *** Fixed in master. http://git.eclipse.org/c/platform/eclipse.platform.runtime.git/commit/?id=04e4a5d855e69373ee8ad2af57b0f1b8d1c9a7cc *** Bug 347887 has been marked as a duplicate of this bug. *** |
Build Identifier: I20100608-0911 When getInstallLocation() is invoked from multiple concurrent threads it may return "null". The problem seems to be missing synchronization in the org.eclipse.core.internal.runtime.InternalPlatform. When multiple thread s invoke getInstallLocation() and it was not called since the platform start-up, there is a chance that the first thread creates ServiceTracker and invoke open() and just before calling getService(), another thread assigns new ServiceTracker instance to the "installLocation" field, so the first thread ends up calling getService() on a tracker that is not tracking services (open() has not been called). This leads to "null" returned by the method. This is the same for most of the methods in org.eclipse.core.internal.runtime.InternalPlatform. The problem occurred in a code that executes on project open. This code does the following: manager = IResource.getPathVariableManager() manager.getURIValue("someVariableName") So when multiple projects are opened at the same time, multiple threads execute the snippet above and sometimes the described race condition happens. Here's a stack trace of the exception we get: java.lang.NullPointerException at org.eclipse.core.internal.resources.projectvariables.EclipseHomeProjectVariable.getValue(EclipseHomeProjectVariable.java:38) at org.eclipse.core.internal.resources.ProjectVariableProviderManager$Descriptor.getValue(ProjectVariableProviderManager.java:58) at org.eclipse.core.internal.resources.ProjectPathVariableManager.internalGetValue(ProjectPathVariableManager.java:151) at org.eclipse.core.internal.resources.ProjectPathVariableManager.getURIValue(ProjectPathVariableManager.java:110) ... Reproducible: Always Steps to Reproduce: the problem easily can be reproduced with breakpoints and running two concurrent threads that invokes Platform.getInstallLocation(). 1. Install breakpoint at org.eclipse.core.internal.runtime.InternalPlatform.getInstallLocation() at line 356 "installLocation = new ServiceTracker(context, filter, null);" 2. Run two threads that invokes Platform.getInstallLocation() 3. Start debug and wait to suspend both threads at installed breakpoint. 4. In the first thread perform "Step Over" to line 359 "return (Location) installLocation.getService();" 5. In second thread perform "Step Over" to line 357 "installLocation.open();" 6. Go back to first thread and perform "Step Over" to invoke installLocation.getService() 7. method will return "null"