You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by "Steve Lawrence (Jira)" <ji...@apache.org> on 2021/11/01 13:53:00 UTC

[jira] [Commented] (DAFFODIL-2574) Cast error when multiplying two unsignedBytes

    [ https://issues.apache.org/jira/browse/DAFFODIL-2574?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17436848#comment-17436848 ] 

Steve Lawrence commented on DAFFODIL-2574:
------------------------------------------

NumericOps.scala has a large number of objects that implement addition, subtraction, multiplication, division, and integer division. For example, the one that multiplies two unsigned bytes looks like this:

{code:scala}
case object TimesUnsignedByte extends NumericOp {
 def operate(v1: JNumber, v2: JNumber): JNumber = { asShort(v1) * asShort(v2) }
}
{code}

So it converts both operands to a Short (since that is our internal representation of an xs:unsignedByte), multiplies them, and then returns the value.

The issue though is that in Scala (and Java) multiplying two Short's together results in an Int. So this function returns an Int, even though all our logic expects it to return a Short. We likely have the same issue for all mathematical operations for types with underlying representations smaller than an Int (i.e. xs:short, xs:byte, xs:unsignedByte) . For these objects in NumericOps.scala, we need to manually convert the result of the operation to the expected type.

Also, I think we shouldn't even need the casting of the parameters anymore (e.g. asShort)--our DPath logic should already insert the correct conversions prior to calling this function. So I would expect this object and other ones with the same issue to be updated to look something like this:

{code:scala}
case object TimesUnsignedByte extends NumericOp {
 def operate(v1: JNumber, v2: JNumber): JNumber = { (v1.asInstanceOf[JShort] * v2.asInstanceOf[JShort]).toShort }
}
{code}

So we directly cast the JNumber's to the expected underlying representation, do the operation, and then convert the resulting Int back to the expected type.

> Cast error when multiplying two unsignedBytes
> ---------------------------------------------
>
>                 Key: DAFFODIL-2574
>                 URL: https://issues.apache.org/jira/browse/DAFFODIL-2574
>             Project: Daffodil
>          Issue Type: Bug
>          Components: General
>    Affects Versions: 3.1.0
>            Reporter: Kyle Rosales
>            Priority: Major
>             Fix For: 3.2.0
>
>         Attachments: shortCastBug.tdml
>
>
> Ran into an issue when trying to multiple two elements of type unsignedByte together in a `dfdl:occursCount`. It is causing a cast exception trying to convert java.lang.integer to a java.lang.short. I was able to work around it by casing once of the bytes as an integer ` dfdl:occursCount="\{ ../value1 * xs:unsignedInt(../value2) }”`. Attached is a tdml demonstrating the error.
> {code:java}
> org.apache.daffodil.exceptions.Abort: Invariant broken. Runtime.scala - Leaked exception: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Short
> java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Short
> at org.apache.daffodil.infoset.DataValue$.getShort$extension(DataValue.scala:76)
> at org.apache.daffodil.dpath.UnsignedByteToLong$.computeValue(ConverterOps3.scala:94)
> at org.apache.daffodil.dpath.UnsignedByteToLong$.computeValue(ConverterOps3.scala:93)
> {code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)