Bug 565522 - EquinoxClassLoader returns wrong resource content
Summary: EquinoxClassLoader returns wrong resource content
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: Framework (show other bugs)
Version: 4.16   Edit
Hardware: All All
: P3 major (vote)
Target Milestone: 4.17 M3   Edit
Assignee: Thomas Watson CLA
QA Contact:
URL:
Whiteboard:
Keywords: regression
Depends on:
Blocks:
 
Reported: 2020-07-24 09:10 EDT by Marcus Klein CLA
Modified: 2020-07-27 11:47 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marcus Klein CLA 2020-07-24 09:10:17 EDT
We're using org.eclipse.osgi 3.15.300 Equinox OSGi runtime for our OSGi based application. We want to load resources from a fragment but the EquinoxClassLoader returns the wrong resource content due to a coding error in org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalEntry(String, ClasspathEntry[], int, int[])


To reproduce consider the following construct with some bundle and a fragment attached to it. I will only list here the parts that cause the issue:

Bundle-SymbolicName: some.bundle
Bundle-ClassPath: .,
 lib/resource.jar

$ jar tf lib/resource.jar
META-INF/services/some.bundle.Factory

Now the fragment:

Bundle-SymbolicName: some.fragment
Fragment-Host: some.bundle
Bundle-ClassPath: .,
 lib/resource.jar

$ jar tf lib/resource.jar
META-INF/services/some.bundle.Factory

Both files some.bundle.Factory in both resource.jar have different content. Getting the URLs for the resource 'META-INF/services/some.bundle.Factory' works as expected and the result is something like the following:

bundleresource://16.fwk1625901537/META-INF/services/some.bundle.Factory
bundleresource://16.fwk1625901537:2/META-INF/services/some.bundle.Factory

Doing then 'url.openStream()' on both URLs results then in two times the content of the file from the bundle and not one from the bundle and one from the fragment.

The reason for that is a coding error in org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalEntry(String, ClasspathEntry[], int, int[])

This method is called for the second URL with parameters
- /META-INF/services/some.bundle.Factory
- ClasspathEntry[] contains the . classpath and lib/resource.jar of the BUNDLE
- classPathIndex: 2
- currIndex[0]: 0
This is the call to the method for the bundle classpath entries and not for the fragment classpath entries.
'result = cpEntry.findEntry(path)' finds an entry and result gets the value of ZipBundleEntry of the lib/resource.jar of the bundle. In the following if statement the classPathIndex does not match. After having both classpath entries of the bundle iterated the execution reaches the last line of the method and result still has the ZipBundleEntry value, which is then return although null should have been returned as the classPathIndex didn't match.

Essential for this behaviour is, that the resource.jar in the Bundle-Classpath entry is the last entry. Then the behavior of the ClasspathManager.findLocalEntry() method is wrong and it returns a found result (due to same name) but with wrong classPathIndex.

To fix this issue, the last line of the method should be
return null;
Comment 1 Marcus Klein CLA 2020-07-24 09:11:33 EDT
Our workaround is now to have the lib/resource.jar Bundle-Classpath entry not to be the last entry but instead the '.' entry.
Comment 2 Marcus Klein CLA 2020-07-24 09:28:22 EDT
org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalResourceImpl(String, ClasspathEntry[], Module, int, int[])
has last line reading
    return null;
Comment 3 Thomas Watson CLA 2020-07-27 11:21:42 EDT
This is a regression introduced by the fix in bug 537701.
Comment 4 Eclipse Genie CLA 2020-07-27 11:29:58 EDT
New Gerrit change created: https://git.eclipse.org/r/c/equinox/rt.equinox.framework/+/166901