Skip to content

Commit 9c085fe

Browse files
committed
fixed impossibility to use struct inside struct array to be read till end of stream
1 parent 200371a commit 9c085fe

File tree

2 files changed

+69
-18
lines changed

2 files changed

+69
-18
lines changed

jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiler.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,6 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie
240240
int extraFieldNumberAsInt = -1;
241241
int customTypeFieldIndex = -1;
242242

243-
// check that the field is not in the current structure which is a whole stream one
244-
if ((code & 0xF) != CODE_STRUCT_END && fieldUnrestrictedArrayOffset >= 0 && (structureStack.isEmpty() || structureStack.get(structureStack.size() - 1).startStructureOffset != fieldUnrestrictedArrayOffset)) {
245-
throw new JBBPCompilationException("Attempt to read after a 'till-the-end' field", token);
246-
}
247-
248243
final boolean extraFieldNumericDataAsExpression = ((code >>> 8) & EXT_FLAG_EXTRA_AS_EXPRESSION) != 0;
249244
final boolean fieldTypeDiff = ((code >>> 8) & EXT_FLAG_EXTRA_DIFF_TYPE) != 0;
250245

@@ -384,13 +379,21 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie
384379
}
385380
break;
386381
case CODE_STRUCT_START: {
387-
structureStack.add(new StructStackItem(namedFields.size() + ((code & JBBPCompiler.FLAG_NAMED) == 0 ? 0 : 1), startFieldOffset, code, token));
382+
final boolean arrayReadTillEnd = (code & FLAG_ARRAY) != 0 && (extraCode & EXT_FLAG_EXPRESSION_OR_WHOLESTREAM) != 0 && "_".equals(token.getArraySizeAsString());
383+
structureStack.add(new StructStackItem(namedFields.size() + ((code & JBBPCompiler.FLAG_NAMED) == 0 ? 0 : 1), startFieldOffset, arrayReadTillEnd, code, token));
388384
}
389385
break;
390386
case CODE_STRUCT_END: {
391387
if (structureStack.isEmpty()) {
392388
throw new JBBPCompilationException("Detected structure close tag without opening one", token);
393389
} else {
390+
if (fieldUnrestrictedArrayOffset >= 0) {
391+
final StructStackItem startOfStruct = structureStack.get(structureStack.size() - 1);
392+
if (startOfStruct.arrayToReadTillEndOfStream && fieldUnrestrictedArrayOffset != startOfStruct.startStructureOffset) {
393+
throw new JBBPCompilationException("Detected unlimited array of structures but there is already presented one", token);
394+
}
395+
}
396+
394397
currentClosedStructure = structureStack.remove(structureStack.size() - 1);
395398
offset += writePackedInt(out, currentClosedStructure.startStructureOffset);
396399
}
@@ -400,7 +403,11 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie
400403
throw new Error("Detected unsupported compiled code, notify the developer please [" + code + ']');
401404
}
402405

403-
if ((code & FLAG_ARRAY) != 0) {
406+
if ((code & FLAG_ARRAY) == 0) {
407+
if (structureStack.isEmpty() && (code & 0x0F) != CODE_STRUCT_END && fieldUnrestrictedArrayOffset >= 0) {
408+
throw new JBBPCompilationException("Detected field defined after unlimited array", token);
409+
}
410+
} else {
404411
if ((extraCode & EXT_FLAG_EXPRESSION_OR_WHOLESTREAM) != 0) {
405412
if ("_".equals(token.getArraySizeAsString())) {
406413
if (fieldUnrestrictedArrayOffset >= 0) {
@@ -635,18 +642,25 @@ private static final class StructStackItem {
635642
*/
636643
private final int namedFieldCounter;
637644

645+
/**
646+
* Flag shows that the structure is array which shoukd be read till end of stream
647+
*/
648+
private final boolean arrayToReadTillEndOfStream;
649+
638650
/**
639651
* The Constructor.
640652
*
641653
* @param namedFieldCounter the named field counter value for the structure
642654
* start
643655
* @param startStructureOffset the offset of the start structure byte-code
644656
* instruction
657+
* @param arrayToReadTillEnd if true then it is array to read till end
645658
* @param code the start byte code
646659
* @param token the token
647660
*/
648-
private StructStackItem(final int namedFieldCounter, final int startStructureOffset, final int code, final JBBPToken token) {
661+
private StructStackItem(final int namedFieldCounter, final int startStructureOffset, final boolean arrayToReadTillEnd, final int code, final JBBPToken token) {
649662
this.namedFieldCounter = namedFieldCounter;
663+
this.arrayToReadTillEndOfStream = arrayToReadTillEnd;
650664
this.startStructureOffset = startStructureOffset;
651665
this.code = code;
652666
this.token = token;

jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerTest.java

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,53 @@ public void testCompile_ErrorForWrongChar() throws Exception {
3939
}
4040
}
4141

42+
@Test
43+
public void testCompile_AllowedStructInsideStructWhichShouldBeReadTillEnd() throws Exception {
44+
JBBPCompiler.compile("a [_] { byte c;}");
45+
JBBPCompiler.compile("a [_] { b {byte c;}}");
46+
JBBPCompiler.compile("[_] { b [2] {byte c;}}");
47+
}
48+
49+
@Test
50+
public void testCompile_ErrorSituationsReadTillEnd() {
51+
assertThrows(JBBPCompilationException.class, new Executable() {
52+
@Override
53+
public void execute() throws Throwable {
54+
JBBPCompiler.compile("ubyte [_]; ubyte [_];");
55+
}
56+
});
57+
assertThrows(JBBPCompilationException.class, new Executable() {
58+
@Override
59+
public void execute() throws Throwable {
60+
JBBPCompiler.compile("ubyte [_]; a {byte;};");
61+
}
62+
});
63+
assertThrows(JBBPCompilationException.class, new Executable() {
64+
@Override
65+
public void execute() throws Throwable {
66+
JBBPCompiler.compile("byte;test [_] {byte;} int error;");
67+
}
68+
});
69+
assertThrows(JBBPCompilationException.class, new Executable() {
70+
@Override
71+
public void execute() throws Throwable {
72+
JBBPCompiler.compile("ubyte [_]; byte;");
73+
}
74+
});
75+
assertThrows(JBBPCompilationException.class, new Executable() {
76+
@Override
77+
public void execute() throws Throwable {
78+
JBBPCompiler.compile("a [_] { byte a; } b [_] { byte a;}");
79+
}
80+
});
81+
assertThrows(JBBPCompilationException.class, new Executable() {
82+
@Override
83+
public void execute() throws Throwable {
84+
JBBPCompiler.compile("a [_] { b [_] { byte a;}}");
85+
}
86+
});
87+
}
88+
4289
@Test
4390
public void testCompile_StructForWholeStreamAsSecondField() throws Exception {
4491
final JBBPCompiledBlock block = JBBPCompiler.compile("byte;test [_] {byte;}");
@@ -51,16 +98,6 @@ public void testCompile_StructForWholeStreamAsSecondField() throws Exception {
5198
assertEquals(1, block.getCompiledData()[5]);
5299
}
53100

54-
@Test
55-
public void testCompile_ErrorForFieldAfterWholeStreamArray() throws Exception {
56-
try {
57-
JBBPCompiler.compile("byte;test [_] {byte;} int error;");
58-
fail("Must throw IAE");
59-
} catch (JBBPCompilationException ex) {
60-
assertTrue(ex.getToken().toString().contains("int error"));
61-
}
62-
}
63-
64101
@Test
65102
public void testCompile_WholeStreamArrayInsideStructure() throws Exception {
66103
final JBBPCompiledBlock block = JBBPCompiler.compile("test {byte [_];}");

0 commit comments

Comments
 (0)