Error "SEQUENCE OF has no maximum length." when has maximum length
My ASN.1 file is as follows:
OCI2 DEFINITIONS ::=
BEGIN
Blake3hash ::= OCTET STRING (SIZE(32))
Version ::= INTEGER {
v1(0)
}
-- Nanoseconds since Epoch
Timestamp ::= INTEGER (0..MAX)
File ::= SEQUENCE {
contents [0] Blake3hash OPTIONAL,
mode [1] BIT STRING {
rusr (0),
wusr (1),
xusr (2),
rgrp (3),
wgrp (4),
xgrp (5),
roth (6),
woth (7),
xoth (8),
suid (9),
sgid (10),
svtx (11)
},
uid [2] INTEGER (0..MAX),
gid [3] INTEGER (0..MAX),
atime [4] Timestamp OPTIONAL,
btime [5] Timestamp OPTIONAL,
ctime [6] Timestamp OPTIONAL,
mtime [7] Timestamp OPTIONAL
}
Children ::= CHOICE {
nodes [0] SEQUENCE OF Node (SIZE(0..256)),
hashes [1] SEQUENCE OF Blake3hash (SIZE(0..256))
}
Node ::= SEQUENCE {
prefix [0] UTF8String (SIZE(1..4096)),
file [1] File OPTIONAL,
nodes [2] Children
}
Root ::= SEQUENCE {
version [0] Version DEFAULT v1,
child [1] CHOICE {
node Node,
hash Blake3hash
}
}
END
I get the error:
$ asn1tools generate_c_source hello.asn1
error: OCI2.Children.nodes: SEQUENCE OF has no maximum length.
Is this due to the recursion nature of the data structure?
Hi Sargun,
you have a minor issue in the definition of your SEQUENCE OF. The size of an array is indicated after SEQUENCE, not after the array item type.
So change
Children ::= CHOICE {
nodes [0] SEQUENCE OF Node (SIZE(0..256)),
hashes [1] SEQUENCE OF Blake3hash (SIZE(0..256))
}
to
Children ::= CHOICE {
nodes [0] SEQUENCE (SIZE(0..256)) OF Node,
hashes [1] SEQUENCE (SIZE(0..256)) OF Blake3hash
}
and you should be fine.
Thanks, but now I'm running into the recursion problem. I just saw in the docs:
Recursive types are not supported.
Is there any ways to work around this, or is there a way to limit recursion in the spec?
See error:
(venv) sargun:oci2 sargun$ asn1tools generate_c_source --namespace oer --generate-fuzzer -f hello.asn1
error: maximum recursion depth exceeded in comparison
Spec:
OCI2 DEFINITIONS ::=
BEGIN
Blake3hash ::= OCTET STRING (SIZE(32))
Version ::= INTEGER {
v1(0)
} (0..18446744073709551615)
-- Nanoseconds since Epoch
Timestamp ::= SEQUENCE {
seconds [0] INTEGER (0..18446744073709551615),
nsec [1] INTEGER (0..18446744073709551615)
}
File ::= SEQUENCE {
contents [0] Blake3hash OPTIONAL,
mode [1] BIT STRING {
rusr (0),
wusr (1),
xusr (2),
rgrp (3),
wgrp (4),
xgrp (5),
roth (6),
woth (7),
xoth (8),
suid (9),
sgid (10),
svtx (11)
} (SIZE(24)),
uid [2] INTEGER (0..18446744073709551615),
gid [3] INTEGER (0..18446744073709551615),
atime [4] Timestamp OPTIONAL,
btime [5] Timestamp OPTIONAL,
ctime [6] Timestamp OPTIONAL,
mtime [7] Timestamp OPTIONAL
}
Children ::= CHOICE {
nodes [0] SEQUENCE (SIZE(0..256)) OF Node,
hashes [1] SEQUENCE (SIZE(0..256)) OF Blake3hash
}
-- TODO: Use UTF8 strings here
Node ::= SEQUENCE {
prefix [0] OCTET STRING (SIZE(1..4096)),
file [1] File OPTIONAL,
nodes [2] Children
}
Root ::= SEQUENCE {
version [0] Version DEFAULT v1,
child [1] CHOICE {
node Node,
hash Blake3hash
}
}
END
Unfortunately, it is not possible to declare recursive structures in C when not using pointers (which is the case in the C code generator since it avoids dynamic memory usage).
What you can do is declare each level of recursion explicitly by defining a dedicated type for each level, so do something like this:
Children1 ::= CHOICE {
nodes [0] SEQUENCE (SIZE(0..256)) OF Node2,
hashes [1] SEQUENCE (SIZE(0..256)) OF Blake3hash
}
Children2 ::= SEQUENCE (SIZE(0..256)) OF Blake3hash
Node1 ::= SEQUENCE {
prefix [0] OCTET STRING (SIZE(1..4096)),
file [1] File OPTIONAL,
nodes [2] Children1
}
Node2 ::= SEQUENCE {
prefix [0] OCTET STRING (SIZE(1..4096)),
file [1] File OPTIONAL,
nodes [2] Children2
}
Root ::= SEQUENCE {
version [0] Version DEFAULT v1,
child [1] CHOICE {
node Node1,
hash Blake3hash
}
}
I know that this results in ugly copy-pasta, but it will work.
It's lots of work, but I recently designed pbtools which generates C code for Google Protocol Buffers. It supports recursive schemas. The same design could be applied to the asn1tools C code generator, but as said, it's a ton of work.