Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: byte array elements propageted to int as signed values (0xFF -> -1 instead of 255) #1095

Open
Mingun opened this issue Mar 18, 2024 · 0 comments

Comments

@Mingun
Copy link

Mingun commented Mar 18, 2024

The problem, similar to #1093, in Java with test tests\formats\expr_bytes_ops.ksy:

meta:
  id: expr_bytes_ops
seq:
  - id: one
    size: 3
instances:
  two:
    value: '[0x41, 0xff, 0x4b]'

  one_size:
    value: one.size
  one_first:
    value: one.first
  one_mid:
    value: one[1]
  one_last:
    value: one.last
  one_min:
    value: one.min
  one_max:
    value: one.max

  two_size:
    value: two.size
  two_first:
    value: two.first
  two_mid:
    value: two[1]
  two_last:
    value: two.last
  two_min:
    value: two.min
  two_max:
    value: two.max

The failure is:

java.lang.AssertionError: expected [255] but found [-1]
	at org.testng.Assert.fail(Assert.java:94)
	at org.testng.Assert.failNotEquals(Assert.java:513)
	at org.testng.Assert.assertEqualsImpl(Assert.java:135)
	at org.testng.Assert.assertEquals(Assert.java:116)
	at org.testng.Assert.assertEquals(Assert.java:389)
	at org.testng.Assert.assertEquals(Assert.java:399)
	at io.kaitai.struct.spec.CommonSpec.assertIntEquals(CommonSpec.java:36)
	at io.kaitai.struct.spec.TestExprBytesOps.testExprBytesOps(TestExprBytesOps.java:17)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:607)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:86)
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:643)
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
	at org.testng.TestRunner.privateRun(TestRunner.java:782)
	at org.testng.TestRunner.run(TestRunner.java:632)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
	at org.testng.SuiteRunner.run(SuiteRunner.java:268)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
	at org.testng.TestNG.run(TestNG.java:1064)
	at org.testng.TestNG.privateMain(TestNG.java:1385)
	at org.testng.TestNG.main(TestNG.java:1354)

The generated code is:

// Autogenerated from KST: please remove this line if doing any edits by hand!

package io.kaitai.struct.spec;

import io.kaitai.struct.testformats.ExprBytesOps;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
public class TestExprBytesOps extends CommonSpec {

    @Test
    public void testExprBytesOps() throws Exception {
        ExprBytesOps r = ExprBytesOps.fromFile(SRC_DIR + "nav_parent_switch.bin");

        assertIntEquals(r.oneSize(), 3);
        assertIntEquals(r.oneFirst(), 1);
        assertIntEquals(r.oneMid(), 66);
        assertIntEquals(r.oneLast(), 255);
        assertEquals(Long.toString(r.oneLast(), 10), "255");
        assertIntEquals(r.oneMin(), 1);
        assertIntEquals(r.oneMax(), 255);
        assertEquals(Long.toString(r.oneMax(), 10), "255");
        assertIntEquals(r.twoSize(), 3);
        assertIntEquals(r.twoFirst(), 65);
        assertIntEquals(r.twoMid(), 255);
        assertEquals(Long.toString(r.twoMid(), 10), "255");
        assertIntEquals(r.twoLast(), 75);
        assertIntEquals(r.twoMin(), 65);
        assertIntEquals(r.twoMax(), 255);
        assertEquals(Long.toString(r.twoMax(), 10), "255");
    }
}

The type of all value instances here, except *_size, is deduced as Int1Type(false) (i.e. u1) which is rendered in Java as int.

byte in Java is signed, when you assign byte value to an int variable or return it from the int method, the sign is propagated. 0xFF (byte) becomes 0xFFFFFFFF (int) which is -1. To get 255 we need to mask value: byte & 0xFF. There is a question, where this conversion should be applied? Obviously, it should not be applied there:

instances:
  array:
    value: [1, 2, 3]
  array2:
    value: [array.first, array.last, array.min, array.max, array[1]]

I think, we need a dedicated type for "element of byte array" to use in such expressions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant