This is an automated email from the ASF dual-hosted git repository.
slawrence pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git
The following commit(s) were added to refs/heads/main by this push:
new 9b8bff780 Fix overflow in DataLoc positions
9b8bff780 is described below
commit 9b8bff7807ba0574aaa2e319df71028808110661
Author: Steve Lawrence <[email protected]>
AuthorDate: Mon Feb 6 15:38:48 2023 -0500
Fix overflow in DataLoc positions
Multiple values in the DataLoc improperly convert from long to int,
which could lead to overflows when bit positions grow to larger than
Int.MaxValue. This leads to assertions on DataLoc calculations that are
expeced to only be positive. This fixes the calculations so we keep bit
positions as a long type to avoid these overflows. Also removes some
unnecessary math.max calls since we know certain calculations will
always be positive.
DAFFODIL-2785
---
.../main/scala/org/apache/daffodil/cli/Main.scala | 2 +-
.../daffodil/runtime1/processors/DataLoc.scala | 34 ++++++++------
.../daffodil/runtime1/processors/TestDataLoc.scala | 54 ++++++++++++++++++++++
3 files changed, 75 insertions(+), 15 deletions(-)
diff --git a/daffodil-cli/src/main/scala/org/apache/daffodil/cli/Main.scala
b/daffodil-cli/src/main/scala/org/apache/daffodil/cli/Main.scala
index dfd09e8ae..987d5802e 100644
--- a/daffodil-cli/src/main/scala/org/apache/daffodil/cli/Main.scala
+++ b/daffodil-cli/src/main/scala/org/apache/daffodil/cli/Main.scala
@@ -829,7 +829,7 @@ object Main {
// not streaming mode, and there is more data available,
// so show left over data warning
val Dump = new DataDumper
- val bitsAlreadyConsumed = loc.bitPos0b % 8
+ val bitsAlreadyConsumed = (loc.bitPos0b % 8).toInt
val firstByteString = if (bitsAlreadyConsumed != 0) {
val bitsToDisplay = 8 - bitsAlreadyConsumed
val pbp = inStream.inputSource.position + 1
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataLoc.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataLoc.scala
index 1966ccae2..dd8ca4c28 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataLoc.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataLoc.scala
@@ -49,24 +49,30 @@ class DataLoc(
Assert.usage(bitLimit1b.isEmpty || bitLimit1b.get >= 0)
Assert.usage(bitPos1b >= 1)
- val bitPos0b = math.max(bitPos1b - 1, 0).toInt
- val bitLimit0b = if (bitLimit1b.isDefined) MaybeULong(bitLimit1b.get - 1)
else MaybeULong.Nope
- val lengthInBits = if (bitLimit0b.isDefined) math.max(bitLimit0b.get -
bitPos0b, 0) else 256L
+ val bitPos0b: Long = bitPos1b - 1
+ val bitLimit0b: MaybeULong = if (bitLimit1b.isDefined)
MaybeULong(bitLimit1b.get - 1) else MaybeULong.Nope
+ val lengthInBits: Long = if (bitLimit0b.isDefined) (bitLimit0b.get -
bitPos0b) else 256L
// The dump region is the identified data for this data loc
- lazy val regionStartBitPos0b = bitPos0b
- lazy val regionLengthInBits = lengthInBits
- lazy val regionEndPos0b = lengthInBits + bitPos0b
+ private lazy val regionStartBitPos0b = bitPos0b
+ private lazy val regionLengthInBits = lengthInBits
+ private lazy val regionEndPos0b = lengthInBits + bitPos0b
// The dump rounds down and up to boundaries of 16 bytes (128 bits)
- lazy val dumpStartBitPos0b = (regionStartBitPos0b >> 7) << 7
- lazy val dumpEndBitPos0b = (math.ceil(regionEndPos0b / 128.0) * 128).toInt
- lazy val dumpLengthInBits = dumpEndBitPos0b - dumpStartBitPos0b
-
- lazy val (bytePos0b, lengthInBytes, endBytePos0b) =
Dump.convertBitsToBytesUnits(bitPos0b, lengthInBits)
- lazy val bytePos1b = bytePos0b + 1
- lazy val (dumpStartBytePos0b, dumpLengthInBytes, dumpEndBytePos0b) =
Dump.convertBitsToBytesUnits(dumpStartBitPos0b, dumpLengthInBits)
- lazy val (regionStartBytePos0b, regionLengthInBytes, regionEndBytePos0b) =
Dump.convertBitsToBytesUnits(regionStartBitPos0b, regionLengthInBits)
+ private lazy val dumpStartBitPos0b = (regionStartBitPos0b >> 7) << 7
+ private lazy val dumpEndBitPos0b = (math.ceil(regionEndPos0b / 128.0) *
128).toLong
+ private lazy val dumpLengthInBits = dumpEndBitPos0b - dumpStartBitPos0b
+
+ lazy val bytePos1b: Long = bytePos0b + 1
+
+ lazy val (bytePos0b: Long, lengthInBytes: Int, endBytePos0b: Long) =
+ Dump.convertBitsToBytesUnits(bitPos0b, lengthInBits)
+
+ private lazy val (dumpStartBytePos0b, dumpLengthInBytes, dumpEndBytePos0b) =
+ Dump.convertBitsToBytesUnits(dumpStartBitPos0b, dumpLengthInBits)
+
+ private lazy val (regionStartBytePos0b, regionLengthInBytes,
regionEndBytePos0b) =
+ Dump.convertBitsToBytesUnits(regionStartBitPos0b, regionLengthInBits)
def dump(rep: Option[Representation], prestate: DataLocation, state:
ParseOrUnparseState): String = {
diff --git
a/daffodil-runtime1/src/test/scala/org/apache/daffodil/runtime1/processors/TestDataLoc.scala
b/daffodil-runtime1/src/test/scala/org/apache/daffodil/runtime1/processors/TestDataLoc.scala
new file mode 100644
index 000000000..856494fc4
--- /dev/null
+++
b/daffodil-runtime1/src/test/scala/org/apache/daffodil/runtime1/processors/TestDataLoc.scala
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.processors
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+import org.apache.daffodil.lib.util.Maybe
+import org.apache.daffodil.lib.util.MaybeULong
+
+class TestDataLoc {
+
+ @Test def test_no_bitPos_overflow_01() = {
+ val dl = new DataLoc(
+ Int.MaxValue.toLong + 2,
+ MaybeULong.Nope,
+ Left(null),
+ Maybe.Nope,
+ )
+ assertEquals(2147483649L, dl.bitPos1b)
+ assertEquals(2147483648L, dl.bitPos0b)
+ assertEquals(268435457L, dl.bytePos1b)
+ assertEquals(268435456L, dl.bytePos0b)
+ }
+
+ @Test def test_no_bitPos_overflow_02() = {
+ val dl = new DataLoc(
+ ((Int.MaxValue.toLong + 1) * 8) + 1,
+ MaybeULong.Nope,
+ Left(null),
+ Maybe.Nope,
+ )
+ assertEquals(17179869185L, dl.bitPos1b)
+ assertEquals(17179869184L, dl.bitPos0b)
+ assertEquals(2147483649L, dl.bytePos1b)
+ assertEquals(2147483648L, dl.bytePos0b)
+ }
+
+}