From: Martin Ciglan Date: Tue, 16 Jun 2015 14:12:51 +0000 (+0200) Subject: Bug 2721: StackOverflowError for leafref FIX X-Git-Tag: release/beryllium~413 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=6504adf7743cea027f1ab3d1cdabfeaf832c243d;p=yangtools.git Bug 2721: StackOverflowError for leafref FIX Leafref XPath needs to be checked whether it references itself in order to detect incoming StackOverflowError and throw appropriate exception if necessary. Change-Id: Iacfa1a9f9d85f947e590b1d6412c9c482b417dbf Signed-off-by: Martin Ciglan --- diff --git a/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java b/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java index 274ba77e07..501b6c324a 100644 --- a/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java +++ b/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java @@ -11,6 +11,7 @@ import static org.opendaylight.yangtools.binding.generator.util.BindingGenerator import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule; + import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import com.google.common.io.BaseEncoding; @@ -53,6 +54,8 @@ import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTy import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder; import org.opendaylight.yangtools.yang.binding.BindingMapping; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; @@ -82,12 +85,15 @@ import org.opendaylight.yangtools.yang.model.util.Int16; import org.opendaylight.yangtools.yang.model.util.Int32; import org.opendaylight.yangtools.yang.model.util.Int64; import org.opendaylight.yangtools.yang.model.util.Int8; +import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl; +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; import org.opendaylight.yangtools.yang.model.util.StringType; import org.opendaylight.yangtools.yang.model.util.Uint16; import org.opendaylight.yangtools.yang.model.util.Uint32; import org.opendaylight.yangtools.yang.model.util.Uint64; import org.opendaylight.yangtools.yang.model.util.Uint8; import org.opendaylight.yangtools.yang.model.util.UnionType; +import org.opendaylight.yangtools.yang.parser.util.YangValidationException; public final class TypeProviderImpl implements TypeProvider { private static final Pattern NUMBERS_PATTERN = Pattern.compile("[0-9]+\\z"); @@ -236,6 +242,49 @@ public final class TypeProviderImpl implements TypeProvider { return gtob.toInstance(); } + private boolean isLeafRefSelfReference(final LeafrefTypeDefinition leafref, final SchemaNode parentNode) { + final SchemaNode leafRefValueNode; + final RevisionAwareXPath leafRefXPath = leafref.getPathStatement(); + final RevisionAwareXPath leafRefStrippedXPath = new RevisionAwareXPathImpl(leafRefXPath.toString() + .replaceAll("\\[(.*?)\\]", ""), leafRefXPath.isAbsolute()); + + ///// skip leafrefs in augments - they're checked once augments are resolved + final Iterator iterator = parentNode.getPath().getPathFromRoot().iterator(); + boolean isAugmenting = false; + DataNodeContainer current = null; + DataSchemaNode dataChildByName; + + while (iterator.hasNext() && !isAugmenting) { + final QName next = iterator.next(); + if (current == null) { + dataChildByName = schemaContext.getDataChildByName(next); + } else { + dataChildByName = current.getDataChildByName(next); + } + if (dataChildByName != null) { + isAugmenting = dataChildByName.isAugmenting(); + } else { + return false; + } + if (dataChildByName instanceof DataNodeContainer) { + current = (DataNodeContainer) dataChildByName; + } + } + if (isAugmenting) { + return false; + } + ///// + + Module parentModule = getParentModule(parentNode); + if (!leafRefStrippedXPath.isAbsolute()) { + leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule, + parentNode, leafRefStrippedXPath); + } else { + leafRefValueNode = SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, leafRefStrippedXPath); + } + return (leafRefValueNode != null) ? leafRefValueNode.equals(parentNode) : false; + } + /** * Returns JAVA Type for instances of the type * LeafrefTypeDefinition or @@ -248,6 +297,10 @@ public final class TypeProviderImpl implements TypeProvider { private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition typeDefinition, final SchemaNode parentNode) { if (typeDefinition instanceof LeafrefTypeDefinition) { final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition; + if (isLeafRefSelfReference(leafref, parentNode)) { + throw new YangValidationException("Leafref " + leafref.toString() + " is referencing itself, incoming" + + " StackOverFlowError detected."); + } return provideTypeForLeafref(leafref, parentNode); } else if (typeDefinition instanceof IdentityrefTypeDefinition) { final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition; diff --git a/code-generator/binding-type-provider/src/test/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImplTest.java b/code-generator/binding-type-provider/src/test/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImplTest.java index f1ddfbcabe..1742adccee 100644 --- a/code-generator/binding-type-provider/src/test/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImplTest.java +++ b/code-generator/binding-type-provider/src/test/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImplTest.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertTrue; import com.google.common.base.Optional; import java.io.File; +import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; @@ -22,11 +23,16 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTypeBuilderImpl; +import org.opendaylight.yangtools.sal.binding.model.api.Type; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair; import org.opendaylight.yangtools.yang.model.util.BinaryType; @@ -40,12 +46,67 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBui import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.opendaylight.yangtools.yang.parser.util.YangValidationException; public class TypeProviderImplTest { @Rule public ExpectedException expException = ExpectedException.none(); + @Test (expected = YangValidationException.class) + public void testLeafRefRelativeSelfReference() throws Exception { + File relative = new File(getClass().getResource("/leafref/leafref-relative-invalid.yang").toURI()); + + final YangParserImpl yangParser = new YangParserImpl(); + final SchemaContext schemaContext = yangParser.parseFiles(Arrays.asList(relative)); + final Module moduleRelative = schemaContext.findModuleByNamespace(new URI("urn:xml:ns:yang:lrr")).iterator().next(); + final TypeProviderImpl typeProvider = new TypeProviderImpl(schemaContext); + + DataSchemaNode leafref = ((ListSchemaNode) moduleRelative.getDataChildByName("neighbor")).getDataChildByName("neighbor-id"); + LeafSchemaNode leaf = (LeafSchemaNode) leafref; + TypeDefinition leafType = leaf.getType(); + Type leafrefResolvedType = typeProvider.javaTypeForSchemaDefinitionType(leafType, leaf); + } + + @Test (expected = YangValidationException.class) + public void testLeafRefAbsoluteSelfReference() throws Exception { + File relative = new File(getClass().getResource("/leafref/leafref-absolute-invalid.yang").toURI()); + + final YangParserImpl yangParser = new YangParserImpl(); + final SchemaContext schemaContext = yangParser.parseFiles(Arrays.asList(relative)); + final Module moduleRelative = schemaContext.findModuleByNamespace(new URI("urn:xml:ns:yang:lra")).iterator().next(); + final TypeProviderImpl typeProvider = new TypeProviderImpl(schemaContext); + + DataSchemaNode leafref = ((ListSchemaNode) moduleRelative.getDataChildByName("neighbor")).getDataChildByName("neighbor-id"); + LeafSchemaNode leaf = (LeafSchemaNode) leafref; + TypeDefinition leafType = leaf.getType(); + Type leafrefResolvedType = typeProvider.javaTypeForSchemaDefinitionType(leafType, leaf); + } + + @Test + public void testLeafRefRelativeAndAbsoluteValidReference() throws URISyntaxException { + File valid = new File(getClass().getResource("/leafref/leafref-valid.yang").toURI()); + + final YangParserImpl yangParser = new YangParserImpl(); + final SchemaContext schemaContext = yangParser.parseFiles(Arrays.asList(valid)); + final Module moduleValid = schemaContext.findModuleByNamespace(new URI("urn:xml:ns:yang:lrv")).iterator().next(); + final TypeProviderImpl typeProvider = new TypeProviderImpl(schemaContext); + + DataSchemaNode leafrefRel = ((ListSchemaNode) moduleValid.getDataChildByName("neighbor")).getDataChildByName + ("neighbor-id"); + LeafSchemaNode leafRel = (LeafSchemaNode) leafrefRel; + TypeDefinition leafTypeRel = leafRel.getType(); + Type leafrefRelResolvedType = typeProvider.javaTypeForSchemaDefinitionType(leafTypeRel, leafRel); + assertNotNull(leafrefRelResolvedType); + + DataSchemaNode leafrefAbs = ((ListSchemaNode) moduleValid.getDataChildByName("neighbor")).getDataChildByName + ("neighbor2-id"); + LeafSchemaNode leafAbs = (LeafSchemaNode) leafrefAbs; + TypeDefinition leafTypeAbs = leafAbs.getType(); + Type leafrefAbsResolvedType = typeProvider.javaTypeForSchemaDefinitionType(leafTypeAbs, leafAbs); + assertNotNull(leafrefAbsResolvedType); + } + @Test public void testMethodsOfTypeProviderImpl() throws URISyntaxException { final YangParserImpl yangParser = new YangParserImpl(); diff --git a/code-generator/binding-type-provider/src/test/resources/leafref/leafref-absolute-invalid.yang b/code-generator/binding-type-provider/src/test/resources/leafref/leafref-absolute-invalid.yang new file mode 100644 index 0000000000..97d1503aee --- /dev/null +++ b/code-generator/binding-type-provider/src/test/resources/leafref/leafref-absolute-invalid.yang @@ -0,0 +1,16 @@ +module leafref-absolute-invalid { + namespace "urn:xml:ns:yang:lra"; + prefix lra; + revision "2015-02-25"; + + list neighbor { + description + "List of neighbors."; + leaf neighbor-id { + type leafref { + path "/lra:neighbor/lra:neighbor-id"; + } + description "Neighbor."; + } + } +} \ No newline at end of file diff --git a/code-generator/binding-type-provider/src/test/resources/leafref/leafref-relative-invalid.yang b/code-generator/binding-type-provider/src/test/resources/leafref/leafref-relative-invalid.yang new file mode 100644 index 0000000000..a933ae49ba --- /dev/null +++ b/code-generator/binding-type-provider/src/test/resources/leafref/leafref-relative-invalid.yang @@ -0,0 +1,16 @@ +module leafref-relative-invalid { + namespace "urn:xml:ns:yang:lrr"; + prefix lrr; + revision "2015-02-25"; + + list neighbor { + description + "List of neighbors."; + leaf neighbor-id { + type leafref { + path "../../neighbor/neighbor-id"; + } + description "Neighbor."; + } + } +} \ No newline at end of file diff --git a/code-generator/binding-type-provider/src/test/resources/leafref/leafref-valid.yang b/code-generator/binding-type-provider/src/test/resources/leafref/leafref-valid.yang new file mode 100644 index 0000000000..fdfa25ced7 --- /dev/null +++ b/code-generator/binding-type-provider/src/test/resources/leafref/leafref-valid.yang @@ -0,0 +1,26 @@ +module leafref-valid { + namespace "urn:xml:ns:yang:lrv"; + prefix lrv; + revision "2015-02-25"; + + list neighbor { + description + "List of neighbors."; + leaf neighbor-id { + type leafref { + path "../../neighbor/mystring"; + } + description "Neighbor."; + } + + leaf neighbor2-id { + type leafref { + path "/lrv:neighbor/lrv:mystring"; + } + } + + leaf mystring { + type string; + } + } +} \ No newline at end of file