Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 356306 - NPE when invoking Platform.getInstallLocation() from multiple threads
Summary: NPE when invoking Platform.getInstallLocation() from multiple threads
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Runtime (show other bugs)
Version: 3.6   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: 3.8   Edit
Assignee: DJ Houghton CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 347887 357211 (view as bug list)
Depends on:
Blocks: 391900
  Show dependency tree
 
Reported: 2011-08-31 07:28 EDT by Rumen Georgiev CLA
Modified: 2012-10-15 07:37 EDT (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rumen Georgiev CLA 2011-08-31 07:28:59 EDT
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"
Comment 1 Thomas Watson CLA 2011-08-31 09:20:49 EDT
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.
Comment 2 Thomas Watson CLA 2011-08-31 09:28:09 EDT
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)
Comment 3 DJ Houghton CLA 2011-08-31 09:47:36 EDT
Tom and I talked about this and we'll do option 2.
Comment 5 Dani Megert CLA 2011-09-12 10:10:34 EDT
Looks like this fix is not good, see bug 357211.
Comment 6 DJ Houghton CLA 2011-09-12 11:06:07 EDT
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.
Comment 7 DJ Houghton CLA 2011-09-12 11:07:42 EDT
*** Bug 357211 has been marked as a duplicate of this bug. ***
Comment 9 DJ Houghton CLA 2011-09-21 13:33:27 EDT
*** Bug 347887 has been marked as a duplicate of this bug. ***