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 d8302e5..a51b121 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 1e57eb4..951170c 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++) {

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.