kaitai-io / kaitai_struct

Kaitai Struct: declarative language to generate binary data parsers in C++ / C# / Go / Java / JavaScript / Lua / Nim / Perl / PHP / Python / Ruby
https://kaitai.io
3.97k stars 192 forks source link

ksc: invalid parent type #89

Closed koczkatamas closed 6 months ago

koczkatamas commented 7 years ago

Compilation of the executable/java_class.ksy file fails for cpp_stl, csharp and java.

The problem is that the attribute type referenced from field_info and method_info, but the parent of attribute becomes field_info, so method_info cannot pass this as constructor argument.

GreyCat commented 7 years ago

With the advent of casting, I believe this problem is solved. Please check if it works now.

generalmimon commented 6 months ago

The problem is that the attribute type referenced from field_info and method_info, but the parent of attribute becomes field_info, so method_info cannot pass this as constructor argument.

I was able to reproduce this problem on KSC 0.6 (running on JDK 11) with java_class.ksy at KSF commit aea1656 dated Jan 19, 2017 (which matches the date this issue was filed):

$ ls -la
total 0
drwxr-xr-x 1 WDAGUtilityAccount 197121 0 Mar 14 20:47 ./
drwxr-xr-x 1 WDAGUtilityAccount 197121 0 Mar 14 20:40 ../

$ curl -fsSLO https://github.com/kaitai-io/kaitai_struct_formats/raw/aea1656b169e8161227f713aba13a9d1f260f08f/executable/java_class.ksy

$ curl -fsSLO https://github.com/kaitai-io/kaitai_struct_compiler/releases/download/0.6/kaitai-struct-compiler-0.6.zip

$ sha256sum kaitai-struct-compiler-0.6.zip
6f4fb84e6d09928e47f1e19c4b4d48d2cc2695db1a8482d3047845ebbaa6113f *kaitai-struct-compiler-0.6.zip

$ unzip -q kaitai-struct-compiler-0.6.zip

$ java -version
java version "11.0.22" 2024-01-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.22+9-LTS-219)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.22+9-LTS-219, mixed mode)

$ kaitai-struct-compiler-0.6/bin/kaitai-struct-compiler --version
kaitai-struct-compiler 0.6

$ kaitai-struct-compiler-0.6/bin/kaitai-struct-compiler --outdir out-ksc0.6 -t java java_class.ksy

$ ls -lR out-ksc0.6/
out-ksc0.6/:
total 0
drwxr-xr-x 1 WDAGUtilityAccount 197121 0 Mar 14 20:50 src/

out-ksc0.6/src:
total 24
-rw-r--r-- 1 WDAGUtilityAccount 197121 20663 Mar 14 20:50 JavaClass.java

$ git -c advice.detachedHead=false clone --depth 1 -b 0.6 -- https://github.com/kaitai-io/kaitai_struct_java_runtime.git runtime-0.6
Cloning into 'runtime-0.6'...
remote: Enumerating objects: 14, done.
remote: Counting objects: 100% (14/14), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 14 (delta 1), reused 8 (delta 0), pack-reused 0
Receiving objects: 100% (14/14), 8.56 KiB | 1.71 MiB/s, done.
Resolving deltas: 100% (1/1), done.

$ find runtime-0.6/ -type f -iname '*.java'
runtime-0.6/src/main/java/io/kaitai/struct/KaitaiStream.java
runtime-0.6/src/main/java/io/kaitai/struct/KaitaiStruct.java

$ javac -version
javac 11.0.22

$ javac -d out-ksc0.6/bin out-ksc0.6/src/JavaClass.java runtime-0.6/src/main/java/io/kaitai/struct/*.java
out-ksc0.6\src\JavaClass.java:446: error: incompatible types: MethodInfo cannot be converted to FieldInfo
                this.attributes.add(new Attribute(this._io, this, _root));
                                                            ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

On KSC 0.7, it is no longer reproducible - the generated JavaClass.java source file compiles fine with javac:

Same procedure as before, but this time with kaitai-struct-compiler-0.7 ```console $ curl -fsSLO https://github.com/kaitai-io/kaitai_struct_compiler/releases/download/0.7/kaitai-struct-compiler-0.7.zip $ sha256sum kaitai-struct-compiler-0.7.zip 2fdd2646ea019bbf55be5bc27f24b037a7152514dbafbb7cfcdaf27a1d190045 *kaitai-struct-compiler-0.7.zip $ unzip -q kaitai-struct-compiler-0.7.zip $ kaitai-struct-compiler-0.7/bin/kaitai-struct-compiler --version kaitai-struct-compiler 0.7 $ kaitai-struct-compiler-0.7/bin/kaitai-struct-compiler --outdir out-ksc0.7 -t java java_class.ksy $ ls -lR out-ksc0.7/ out-ksc0.7/: total 0 drwxr-xr-x 1 WDAGUtilityAccount 197121 0 Mar 14 21:06 src/ out-ksc0.7/src: total 20 -rw-r--r-- 1 WDAGUtilityAccount 197121 20167 Mar 14 21:06 JavaClass.java $ git -c advice.detachedHead=false clone --depth 1 -b 0.7 -- https://github.com/kaitai-io/kaitai_struct_java_runtime.git runtime-0.7 Cloning into 'runtime-0.7'... remote: Enumerating objects: 14, done. remote: Counting objects: 100% (14/14), done. remote: Compressing objects: 100% (9/9), done. remote: Total 14 (delta 1), reused 9 (delta 0), pack-reused 0 Receiving objects: 100% (14/14), 8.72 KiB | 1.74 MiB/s, done. Resolving deltas: 100% (1/1), done. $ find runtime-0.7/ -type f -iname '*.java' runtime-0.7/src/main/java/io/kaitai/struct/KaitaiStream.java runtime-0.7/src/main/java/io/kaitai/struct/KaitaiStruct.java $ javac -d out-ksc0.7/bin out-ksc0.7/src/JavaClass.java runtime-0.7/src/main/java/io/kaitai/struct/*.java $ ls -l out-ksc0.7/ total 4 drwxr-xr-x 1 WDAGUtilityAccount 197121 0 Mar 14 21:07 bin/ drwxr-xr-x 1 WDAGUtilityAccount 197121 0 Mar 14 21:06 src/ $ file out-ksc0.7/bin/JavaClass.class out-ksc0.7/bin/JavaClass.class: compiled Java class data, version 55.0 (Java SE 11) ```

The diff between JavaClass.java generated by KSC 0.6 and KSC 0.7 looks like this:

Diff between out-ksc0.6/src/JavaClass.java and out-ksc0.7/src/JavaClass.java ```diff $ git diff --no-index out-ksc{0.6,0.7}/src/JavaClass.java warning: in the working copy of 'out-ksc0.7/src/JavaClass.java', LF will be replaced by CRLF the next time Git touches it diff --git a/out-ksc0.6/src/JavaClass.java b/out-ksc0.7/src/JavaClass.java index 080821b..4e173a8 100644 --- a/out-ksc0.6/src/JavaClass.java +++ b/out-ksc0.7/src/JavaClass.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.nio.charset.Charset; public class JavaClass extends KaitaiStruct { public static JavaClass fromFile(String fileName) throws IOException { @@ -202,7 +203,7 @@ public Utf8CpInfo(KaitaiStream _io, ConstantPoolEntry _parent, JavaClass _root) } private void _read() { this.strLen = this._io.readU2be(); - this.value = this._io.readStrByteLimit(strLen(), "UTF-8"); + this.value = new String(this._io.readBytes(strLen()), Charset.forName("UTF-8")); } private int strLen; private String value; @@ -258,13 +259,13 @@ public Attribute(KaitaiStream _io) { _read(); } - public Attribute(KaitaiStream _io, FieldInfo _parent) { + public Attribute(KaitaiStream _io, KaitaiStruct _parent) { super(_io); this._parent = _parent; _read(); } - public Attribute(KaitaiStream _io, FieldInfo _parent, JavaClass _root) { + public Attribute(KaitaiStream _io, KaitaiStruct _parent, JavaClass _root) { super(_io); this._parent = _parent; this._root = _root; @@ -279,12 +280,12 @@ private void _read() { private long attributeLength; private byte[] info; private JavaClass _root; - private JavaClass.FieldInfo _parent; + private KaitaiStruct _parent; public int attributeNameIndex() { return attributeNameIndex; } public long attributeLength() { return attributeLength; } public byte[] info() { return info; } public JavaClass _root() { return _root; } - public JavaClass.FieldInfo _parent() { return _parent; } + public KaitaiStruct _parent() { return _parent; } } public static class ClassCpInfo extends KaitaiStruct { public static ClassCpInfo fromFile(String fileName) throws IOException { @@ -362,13 +363,13 @@ public ConstantPoolEntry(KaitaiStream _io) { _read(); } - public ConstantPoolEntry(KaitaiStream _io, KaitaiStruct _parent) { + public ConstantPoolEntry(KaitaiStream _io, JavaClass _parent) { super(_io); this._parent = _parent; _read(); } - public ConstantPoolEntry(KaitaiStream _io, KaitaiStruct _parent, JavaClass _root) { + public ConstantPoolEntry(KaitaiStream _io, JavaClass _parent, JavaClass _root) { super(_io); this._parent = _parent; this._root = _root; @@ -403,7 +404,7 @@ private void _read() { private MethodRefCpInfo methodRefCpInfo; private InterfaceMethodRefCpInfo interfaceMethodRefCpInfo; private JavaClass _root; - private KaitaiStruct _parent; + private JavaClass _parent; public TagEnum tag() { return tag; } public Utf8CpInfo utf8CpInfo() { return utf8CpInfo; } public ClassCpInfo classCpInfo() { return classCpInfo; } @@ -412,7 +413,7 @@ private void _read() { public MethodRefCpInfo methodRefCpInfo() { return methodRefCpInfo; } public InterfaceMethodRefCpInfo interfaceMethodRefCpInfo() { return interfaceMethodRefCpInfo; } public JavaClass _root() { return _root; } - public KaitaiStruct _parent() { return _parent; } + public JavaClass _parent() { return _parent; } } public static class MethodInfo extends KaitaiStruct { public static MethodInfo fromFile(String fileName) throws IOException { ```

Indeed, we can actually see two changes in derived _parent types:

  1. The _parent type of Attribute changed from FieldInfo to KaitaiStruct. This fixed the problem in question, because it allows the attribute type to be used not only from the field_info type:

     field_info:
       seq:
         # ...
         - id: attributes
           type: attribute
           repeat: expr
           repeat-expr: attributes_count

    ... but also from the method_info type:

     method_info:
       seq:
         # ...
         - id: attributes
           type: attribute
           repeat: expr
           repeat-expr: attributes_count
  2. The _parent type of ConstantPoolEntry changed from KaitaiStruct to JavaClass - this is correct as well, since the constant_pool_entry is only used from the top-level seq, so its _parent type should be java_class:

    meta:
     id: java_class
     endian: be
     file-extension: class
    seq:
     # ...
     - id: constant_pool
       type: constant_pool_entry
       repeat: expr
       repeat-expr: constant_pool_count - 1

I can confirm that this has not regressed since KSC 0.7 - the same java_class.ksy is still compiled to valid Java code when using KSC 0.10.

generalmimon commented 6 months ago

As explained in the previous comment, this issue is resolved.