From 683170bee30d6938fbaac9ad422d664259fc1bba Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 14 Oct 2019 10:16:02 +0200 Subject: [PATCH] Use careful byte-masking/shifting in Mg Input We really want to operate on byte and not int, the bytes are to be treated as unsigned, which gets wrecked by sign extension. Introduce an explicit mask(byte, byte) method and use it where we are potentially sign-extending. JIRA: CONTROLLER-1919 Change-Id: I0484f440c1589859fb268947f5a80a2b4969451e Signed-off-by: Robert Varga --- .../stream/AbstractMagnesiumDataInput.java | 20 ++++++++---- .../NormalizedNodeStreamReaderWriterTest.java | 31 +++++++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractMagnesiumDataInput.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractMagnesiumDataInput.java index d8302e5bcd..a51b121a4f 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractMagnesiumDataInput.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractMagnesiumDataInput.java @@ -258,7 +258,7 @@ abstract class AbstractMagnesiumDataInput extends AbstractNormalizedNodeDataInpu final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent); final int size; - switch (nodeHeader & MagnesiumNode.PREDICATE_MASK) { + switch (mask(nodeHeader, MagnesiumNode.PREDICATE_MASK)) { case MagnesiumNode.PREDICATE_ZERO: size = 0; break; @@ -434,7 +434,7 @@ abstract class AbstractMagnesiumDataInput extends AbstractNormalizedNodeDataInpu } private AugmentationIdentifier readAugmentationIdentifier(final byte header) throws IOException { - final int count = header & MagnesiumPathArgument.AID_COUNT_MASK; + final byte count = mask(header, MagnesiumPathArgument.AID_COUNT_MASK); switch (count) { case MagnesiumPathArgument.AID_COUNT_1B: return readAugmentationIdentifier(input.readUnsignedByte()); @@ -443,7 +443,7 @@ abstract class AbstractMagnesiumDataInput extends AbstractNormalizedNodeDataInpu case MagnesiumPathArgument.AID_COUNT_4B: return readAugmentationIdentifier(input.readInt()); default: - return readAugmentationIdentifier(count >>> MagnesiumPathArgument.AID_COUNT_SHIFT); + return readAugmentationIdentifier(rshift(count, MagnesiumPathArgument.AID_COUNT_SHIFT)); } } @@ -482,7 +482,7 @@ abstract class AbstractMagnesiumDataInput extends AbstractNormalizedNodeDataInpu private NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final byte header) throws IOException { final QName qname = readNodeIdentifier(header).getNodeType(); - switch (header & MagnesiumPathArgument.SIZE_MASK) { + switch (mask(header, MagnesiumPathArgument.SIZE_MASK)) { case MagnesiumPathArgument.SIZE_1B: return readNodeIdentifierWithPredicates(qname, input.readUnsignedByte()); case MagnesiumPathArgument.SIZE_2B: @@ -490,7 +490,7 @@ abstract class AbstractMagnesiumDataInput extends AbstractNormalizedNodeDataInpu case MagnesiumPathArgument.SIZE_4B: return readNodeIdentifierWithPredicates(qname, input.readInt()); default: - return readNodeIdentifierWithPredicates(qname, header >>> MagnesiumPathArgument.SIZE_SHIFT); + return readNodeIdentifierWithPredicates(qname, rshift(header, MagnesiumPathArgument.SIZE_SHIFT)); } } @@ -517,7 +517,7 @@ abstract class AbstractMagnesiumDataInput extends AbstractNormalizedNodeDataInpu } private static void verifyPathIdentifierOnly(final byte header) throws InvalidNormalizedNodeStreamException { - if ((header & MagnesiumPathArgument.SIZE_MASK) != 0) { + if (mask(header, MagnesiumPathArgument.SIZE_MASK) != 0) { throw new InvalidNormalizedNodeStreamException("Invalid path argument header " + header); } } @@ -845,4 +845,12 @@ abstract class AbstractMagnesiumDataInput extends AbstractNormalizedNodeDataInpu throw new InvalidNormalizedNodeStreamException("Invalid bits length " + size); } } + + private static byte mask(final byte header, final byte mask) { + return (byte) (header & mask); + } + + private static int rshift(final byte header, final byte shift) { + return (header & 0xFF) >>> shift; + } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java index 1e57eb4b7e..951170c7a1 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java @@ -9,11 +9,14 @@ package org.opendaylight.controller.cluster.datastore.node.utils.stream; import static org.junit.Assert.assertEquals; +import com.google.common.collect.ImmutableSet; import com.google.common.io.ByteStreams; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; @@ -28,6 +31,7 @@ import org.opendaylight.controller.cluster.datastore.util.TestModel; import org.opendaylight.yangtools.yang.common.Empty; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; @@ -293,6 +297,33 @@ public class NormalizedNodeStreamReaderWriterTest { assertEquals(expected, nnin.readNormalizedNode()); } + @Test + public void testAugmentationIdentifier() throws IOException { + final List qnames = new ArrayList<>(); + for (int i = 0; i < 257; ++i) { + qnames.add(QName.create(TestModel.TEST_QNAME, "a" + i)); + } + + for (int i = 0; i < qnames.size(); ++i) { + final AugmentationIdentifier expected = AugmentationIdentifier.create( + ImmutableSet.copyOf(qnames.subList(0, i))); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + try (NormalizedNodeDataOutput nnout = + NormalizedNodeInputOutput.newDataOutput(ByteStreams.newDataOutput(bos), + NormalizedNodeStreamVersion.SODIUM_SR1)) { + nnout.writePathArgument(expected); + } + + final byte[] bytes = bos.toByteArray(); + + NormalizedNodeDataInput nnin = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes)); + PathArgument arg = nnin.readPathArgument(); + assertEquals(expected, arg); + } + } + private static String largeString(final int pow) { StringBuilder sb = new StringBuilder("X"); for (int i = 0; i < pow; i++) { -- 2.36.6