Use careful byte-masking/shifting in Mg Input 99/85099/2
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 14 Oct 2019 08:16:02 +0000 (10:16 +0200)
committerRobert Varga <nite@hq.sk>
Mon, 14 Oct 2019 12:20:26 +0000 (12:20 +0000)
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 <robert.varga@pantheon.tech>
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractMagnesiumDataInput.java
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java

index d8302e5bcd1c6be22d1449d08e49d064d07a9fcf..a51b121a4fc73801b833568a641c1835007ba3c9 100644 (file)
@@ -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;
+    }
 }
index 1e57eb4b7ebbb240fed1b6b1e69e0e0fc0090c86..951170c7a1608a06cbc3f569b193264694f8d3f4 100644 (file)
@@ -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<QName> 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++) {