added maxDepth parameter to the parser

This commit is contained in:
Walter Oggioni
2019-07-18 19:22:58 +02:00
committed by Walter Oggioni
parent e295cf598e
commit 2e4588a280
5 changed files with 96 additions and 6 deletions

View File

@@ -0,0 +1,7 @@
package net.woggioni.worth.exception;
public class MaxDepthExceededException extends WorthException {
public MaxDepthExceededException(String msg) {
super(msg);
}
}

View File

@@ -1,6 +1,7 @@
package net.woggioni.worth.serialization;
import lombok.RequiredArgsConstructor;
import net.woggioni.worth.exception.MaxDepthExceededException;
import net.woggioni.worth.exception.NotImplementedException;
import net.woggioni.worth.utils.WorthUtils;
import net.woggioni.worth.value.*;
@@ -13,6 +14,8 @@ import java.io.Reader;
import java.nio.charset.Charset;
import java.util.ArrayDeque;
import static net.woggioni.worth.utils.WorthUtils.newThrowable;
public class ValueParser implements Parser {
protected final Value.Configuration cfg;
@@ -64,7 +67,16 @@ public class ValueParser implements Parser {
protected ValueParser(Value.Configuration cfg) {
this.cfg = cfg;
stack = new ArrayDeque<>();
stack = new ArrayDeque<>() {
@Override
public void push(StackLevel stackLevel) {
if(size() == cfg.maxDepth) {
throw newThrowable(MaxDepthExceededException.class,
"Objects is too deep, max allowed depth is %d", cfg.maxDepth);
}
super.push(stackLevel);
}
};
stack.push(new ArrayStackLevel());
}

View File

@@ -1,5 +1,6 @@
package net.woggioni.worth.xface;
import lombok.Builder;
import net.woggioni.worth.exception.TypeException;
import net.woggioni.worth.value.NullValue;
import net.woggioni.worth.value.ObjectValue;
@@ -85,11 +86,21 @@ public interface Value {
throw new TypeException("Not an object");
}
@Builder
class Configuration {
public ObjectValue.Implementation objectValueImplementation = ObjectValue.Implementation.valueOf(
@Builder.Default
public final ObjectValue.Implementation objectValueImplementation = ObjectValue.Implementation.valueOf(
System.getProperty(ObjectValue.class.getName() + ".implementation", "TreeMap"));
public boolean useReferences = Boolean.valueOf(
@Builder.Default
public final boolean useReferences = Boolean.valueOf(
System.getProperty(Value.class.getName() + ".useReferences", "false"));
@Builder.Default
public final int maxDepth =
Integer.parseInt(System.getProperty(Value.class.getName() + ".maxDepth", "1048576"));
}
Configuration configuration = new Configuration();
Configuration configuration = Configuration.builder().build();
}

View File

@@ -0,0 +1,59 @@
package net.woggioni.worth.serialization;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import net.woggioni.worth.antlr.JSONLexer;
import net.woggioni.worth.antlr.JSONListenerImpl;
import net.woggioni.worth.exception.MaxDepthExceededException;
import net.woggioni.worth.serialization.json.JSONParser;
import net.woggioni.worth.xface.Parser;
import net.woggioni.worth.xface.Value;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.junit.Test;
import java.io.InputStream;
import java.io.InputStreamReader;
public class JsonBombTest {
private InputStream infiniteJson() {
return new InputStream() {
int index = 0;
final String monomer = "{\"key\":[";
@Override
public int read() {
return (int) monomer.charAt(index++ % monomer.length());
}
};
}
@Test(expected = StackOverflowError.class)
@SneakyThrows
public void jackson() {
ObjectMapper om = new ObjectMapper();
om.readTree(infiniteJson());
}
@Test(expected = MaxDepthExceededException.class)
@SneakyThrows
public void worth() {
Value.Configuration cfg = Value.Configuration.builder().maxDepth(1024).build();
Parser parser = JSONParser.newInstance(cfg);
parser.parse(infiniteJson());
}
@Test(expected = OutOfMemoryError.class)
@SneakyThrows
public void antlr() {
CharStream inputStream = CharStreams.fromReader(new InputStreamReader(infiniteJson()));
JSONLexer lexer = new JSONLexer(inputStream);
CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);
net.woggioni.worth.antlr.JSONParser parser = new net.woggioni.worth.antlr.JSONParser(commonTokenStream);
JSONListenerImpl listener = new JSONListenerImpl();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(listener, parser.json());
}
}

View File

@@ -32,8 +32,9 @@ public class ObjectValueImplementationTest {
ObjectValue obj = ObjectValue.newInstance();
Assert.assertEquals(expectedClass, obj.getClass());
mapping.forEach(tuple -> {
Value.Configuration cfg = new Value.Configuration();
cfg.objectValueImplementation = tuple._1;
Value.Configuration cfg = Value.Configuration.builder()
.objectValueImplementation(tuple._1)
.build();
ObjectValue obj2 = ObjectValue.newInstance(cfg);
Assert.assertEquals(tuple._2, obj2.getClass());
});