ant-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mitch Gitman (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (IVY-1347) StackOverflowError when using <extends> with no location specified
Date Tue, 28 Aug 2012 23:09:07 GMT

    [ https://issues.apache.org/jira/browse/IVY-1347?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13443634#comment-13443634
] 

Mitch Gitman commented on IVY-1347:
-----------------------------------

The attached patch addresses two separate sets of bugs:
* One set that was introduced with some changes that were made to my series of patches for
issues IVY-1359, IVY-1363, IVY-1364.
* Another bug that went unaddressed by a solution to IVY-1347 that was a rationale for the
preceding changes.

KEEPING TRACK OF PARENT-SPECIFIC MODULE-INHERITANCE-REPOSITORY RESOLVER
When Maarten Coene merged from trunk into the 2.3.x branch some otherwise worthwhile refinements
to the work I'd done to have XmlModuleDescriptorParser correctly locate source parent modules
on the filesystem, he removed the following line:            IvyContext.getContext().getSettings().addResolver(parentModuleResolver);

This line was necessary for the resolve-parent-from-source-location mechanism to work in a
normal and predictable way. Without it, I would see error output like the following on a regular
basis:
 [ivy:resolve] :: problems summary ::
 [ivy:resolve] :::: ERRORS
 [ivy:resolve]       unknown resolver module-inheritance-repository-com.foo#bootstrap-parent;1.0
 [ivy:resolve]       unknown resolver module-inheritance-repository-com.foo#bootstrap-parent;1.0
 [ivy:resolve]       unknown resolver module-inheritance-repository-com.foo#bootstrap-parent;1.0

At the risk of sounding like a broken record, as I'd noted before with a previous modification
of this feature, it violates any reasonable contract to be reporting errors for non-error
behaviors that happen in the normal course of things. Simple principle: crying wolf about
nonexistent errors is itself an error.

Worse, right after the error gets reported, something insidious happens. Because the caller,
DefaultRepositoryCacheManager, can't find the correct resolver, it goes and either finds or
creates another one:
                    DependencyResolver resolver = settings.getResolver(resolverName);
                    if (resolver == null) {
                        Message.debug("/tresolver not found: " + resolverName
                            + " => trying to use the one configured for " + mrid);
                        resolver = settings.getResolver(depMD.getResolvedModuleRevisionId());

This second resolver, a ChainResolver, is different from the original FileSystemResolver that
was created. So the FileSystemResolver we go to the trouble to create in the method checkParentModuleOnFilesystem
is never actually used to located the parent module.

Therefore, I have restored the line that adds the parent-specific FileSystemResolver to IvySettings.

Now, Maarten told me the reason he removed that line was that, with it still there, he would
still have the StackOverflowError associated with IVY-1347:
https://issues.apache.org/jira/browse/IVY-1347

I was not able to reproduce this failure, even though I'm using Windows as Maarten is. 

CHCEKING FOR MISLEADING PARENT SOURCE LOCATION
However, I noticed something suspicious about the particular test project that was attached
to the bug. See:
ivy-2.3.x/test/repositories/IVY-1347

This test case contains two source modules, childtwo and childone. The ivy.xml for childtwo
indicates that its parent is foo#parent. Since no location is specified, the default location,
the ivy.xml one directory above, is used:
    <info organisation="foo" module="childtwo" revision="1.0" status="integration">
        <extends organisation="foo" module="parent" revision="1.0"/>
    </info>

The problem is, the ivy.xml at that location is the one for the childone module, not parent.
As a result, Ivy is getting tricked into treating childOne as the parent of childTwo when
it's not. 

When you get into XmlModuleDescriptorParser.resolveParentFromModuleInheritanceRepository,
the resolver named module-inheritance-repository-foo#parent;1.0 has for its only ivyPattern
ivy-2.3.x/test/repositories/IVY-1347/childone/ivy.xml.

Then, within the resolveParentFromModuleInheritanceRepository call, you get to the following
line in Repository.findResourceUsingPattern:
                String resourceName = IvyPatternHelper.substitute(pattern, mrid, artifact);
At this point, the values are:
pattern = ivy-2.3.x/test/repositories/IVY-1347/childone/ivy.xml
mrid = foo#parent;1.0
artifact = foo#parent;1.0!ivy.xml(ivy)
resourceName = ivy-2.3.x/test/repositories/IVY-1347/childone/ivy.xml

You see the unkosher mixing of parent and childone. And findResourceUsingPattern indeed returns
a ResolvedResource of:
ivy-2.3.x/test/repositories/IVY-1347/childone/ivy.xml (1.0)

Then in BasicResolver.getDependency, the ResolvedModuleResource rmr becomes foo#parent;1.0.

My sense is the only reason this test isn't blowing up is that there's nothing in the parent
to merge. I also believe that Maarten's experiencing the StackOverflowError had something
to do with Ivy trying to resolve this invalid combination.

Now, with the attached patch, Ivy ignores the false positive, and no purported source-located
parent resolver gets added to the Ivy settings. Instead, the parent has to be found in the
regular repository.

To accomplish this, I've added a method isExpectedParentInLocation to XmlModuleDescriptorParser.
If that method returns false, resolveParentFromModuleInheritanceRepository is not called.


The isExpectedParentInLocation implementation relies on a new class, MinimalParentParser,
that I've added as a static class in XmlModuleDescriptorParser. This parser parses just enough
of the parent ivy.xml to find the organisation/module/revision combination. From here, the
Parser in XmlModuleDescriptorParser checks if the ModuleRevisionId in the parent ivy.xml matches
the ModuleRevisionId in the extends element of the child ivy.xml. This includes obtaining
a VersionMatcher and calling accept on it, so that a desired revision like "latest.integration"
in the extends will match something like "1.0" in the parent:
                    VersionMatcher versionMatcher = settings.getVersionMatcher();
                    if (versionMatcher.accept(expectedParentMrid, actualParentMrid)) {
                        return true;
                    }

This solution required adding a getVersionMatcher() method to the ParserSettings interface.

NOTE: I've created this patch only for the 2.3.x branch, but not for trunk.
                
> StackOverflowError when using <extends> with no location specified
> ------------------------------------------------------------------
>
>                 Key: IVY-1347
>                 URL: https://issues.apache.org/jira/browse/IVY-1347
>             Project: Ivy
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 2.3.0-RC1
>            Reporter: Matt Hurne
>            Assignee: Maarten Coene
>            Priority: Critical
>              Labels: testcase
>             Fix For: 2.3.0
>
>         Attachments: IVY-1347-1363.patch, IVY-1347.zip
>
>
> When using {{<extends>}} without specifying a {{location}}, we end up with a {{StackOverflowError}}.
 For example:
> {noformat}
> ...
>     <info organisation="foo" module="bar" revision="1.0" status="integration">
>         <extends organisation="foo" module="parent" revision="1.0.0" />
>     </info>
> ...
> {noformat}
> {noformat}
> [ivy:buildlist] :: Apache Ivy 2.3.0-rc1 - 20120416000235 :: http://ant.apache.org/ivy/
::
> [ivy:buildlist] :: loading settings :: file = D:\foo\ivysettings.xml
> BUILD FAILED
> java.lang.StackOverflowError
>         at java.net.URL.set(URL.java:683)
>         at java.net.URLStreamHandler.setURL(URLStreamHandler.java:521)
>         at java.net.URLStreamHandler.setURL(URLStreamHandler.java:571)
>         at sun.net.www.protocol.jar.Handler.parseURL(Handler.java:76)
>         at java.net.URL.<init>(URL.java:596)
>         at java.net.URL.<init>(URL.java:464)
>         at sun.misc.URLClassPath$JarLoader.checkResource(URLClassPath.java:674)
>         at sun.misc.URLClassPath$JarLoader.getResource(URLClassPath.java:759)
>         at sun.misc.URLClassPath$JarLoader.findResource(URLClassPath.java:735)
>         at sun.misc.URLClassPath.findResource(URLClassPath.java:146)
>         at java.net.URLClassLoader$2.run(URLClassLoader.java:385)
>         at java.security.AccessController.doPrivileged(Native Method)
>         at java.net.URLClassLoader.findResource(URLClassLoader.java:382)
>         at java.lang.ClassLoader.getResource(ClassLoader.java:1003)
>         at java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:1193)
>         at javax.xml.parsers.SecuritySupport$4.run(SecuritySupport.java:96)
>         at java.security.AccessController.doPrivileged(Native Method)
>         at javax.xml.parsers.SecuritySupport.getResourceAsStream(SecuritySupport.java:89)
>         at javax.xml.parsers.FactoryFinder.findJarServiceProvider(FactoryFinder.java:250)
>         at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:223)
>         at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:128)
>         at org.apache.ivy.util.XMLHelper.newSAXParser(XMLHelper.java:57)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:120)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:96)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:86)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.parse(XmlModuleDescriptorParser.java:276)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser.parseDescriptor(XmlModuleDescriptorParser.java:116)
>         at org.apache.ivy.plugins.resolver.RepositoryResolver.findResourceUsingPattern(RepositoryResolver.java:109)
>         at org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findResourceUsingPatterns(AbstractPatternsBasedResolver.java:96)
>         at org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findIvyFileRef(AbstractPatternsBasedResolver.java:66)
>         at org.apache.ivy.plugins.resolver.BasicResolver.getDependency(BasicResolver.java:228)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.resolveParentFromModuleInheritanceRepository(XmlModuleDescriptorParser.java:684)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.extendsStarted(XmlModuleDescriptorParser.java:438)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.startElement(XmlModuleDescriptorParser.java:327)
>         at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
>         at org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
>         at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
>         at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown
Source)
>         at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
Source)
>         at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
>         at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
>         at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
>         at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
>         at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
>         at org.apache.xerces.jaxp.SAXParserImpl.parse(Unknown Source)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:133)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:96)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:86)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.parse(XmlModuleDescriptorParser.java:276)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser.parseDescriptor(XmlModuleDescriptorParser.java:116)
>         at org.apache.ivy.plugins.resolver.RepositoryResolver.findResourceUsingPattern(RepositoryResolver.java:109)
>         at org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findResourceUsingPatterns(AbstractPatternsBasedResolver.java:96)
>         at org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findIvyFileRef(AbstractPatternsBasedResolver.java:66)
>         at org.apache.ivy.plugins.resolver.BasicResolver.getDependency(BasicResolver.java:228)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.resolveParentFromModuleInheritanceRepository(XmlModuleDescriptorParser.java:684)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.extendsStarted(XmlModuleDescriptorParser.java:438)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.startElement(XmlModuleDescriptorParser.java:327)
>         at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
>         at org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
>         at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
>         at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown
Source)
>         at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
Source)
>         at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
>         at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
>         at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
>         at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
>         at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
>         at org.apache.xerces.jaxp.SAXParserImpl.parse(Unknown Source)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:133)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:96)
>         at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:86)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.parse(XmlModuleDescriptorParser.java:276)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser.parseDescriptor(XmlModuleDescriptorParser.java:116)
>         at org.apache.ivy.plugins.resolver.RepositoryResolver.findResourceUsingPattern(RepositoryResolver.java:109)
>         at org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findResourceUsingPatterns(AbstractPatternsBasedResolver.java:96)
>         at org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findIvyFileRef(AbstractPatternsBasedResolver.java:66)
>         at org.apache.ivy.plugins.resolver.BasicResolver.getDependency(BasicResolver.java:228)
>         at org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.resolveParentFromModuleInheritanceRepository(XmlModuleDescriptorParser.java:684)
> ...
> {noformat}

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Mime
View raw message