From 629a5873d65d259a2fde942cc6787f10df8c0862 Mon Sep 17 00:00:00 2001 From: Guus der Kinderen Date: Tue, 2 Jul 2024 12:22:14 +0200 Subject: [PATCH] fixes #191 and #192: Guard against stack overflow This adds a quick and dirty guard against a stack overflow condition when serializing and deserializing severely nested data. --- .../main/java/com/owlike/genson/Genson.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/genson/src/main/java/com/owlike/genson/Genson.java b/genson/src/main/java/com/owlike/genson/Genson.java index cf42fd09..bee303c9 100644 --- a/genson/src/main/java/com/owlike/genson/Genson.java +++ b/genson/src/main/java/com/owlike/genson/Genson.java @@ -269,6 +269,7 @@ public void serialize(Object object, ObjectWriter writer, Context ctx) { * writer instance you also must ensure to call close on it when you are done. */ public void serialize(Object object, Type type, ObjectWriter writer, Context ctx) { + recursionCheck(ctx); Serializer ser = provideConverter(type); try { ser.serialize(object, writer, ctx); @@ -377,6 +378,8 @@ public T deserialize(GenericType type, Reader reader, Class T deserialize(GenericType type, ObjectReader reader, Context ctx) { + recursionCheck(ctx); + Deserializer deser = provideConverter(type.getType()); try { return deser.deserialize(reader, ctx); @@ -420,6 +423,7 @@ public T deserializeInto(Reader reader, T object) { * @return the object enriched with the properties from the stream. */ public T deserializeInto(ObjectReader reader, T object, Context ctx) { + recursionCheck(ctx); BeanDescriptor bd = (BeanDescriptor) getBeanDescriptorProvider().provide(object.getClass(), this); bd.deserialize(object, reader, ctx); return object; @@ -475,6 +479,7 @@ public T next() { if (!hasNext()) throw new NoSuchElementException(); reader.next(); try { + recursionCheck(ctx); return converter.deserialize(reader, ctx); } catch (Exception e) { throw new JsonBindingException("Could not deserialize to type " + type.getRawClass(), e); @@ -616,4 +621,25 @@ public RuntimePropertyFilter runtimePropertyFilter() { public static class Builder extends GensonBuilder { } + + /** + * Updates a counter in the provided context, initializing it to 0 if the counter does not yet exist, throwing a + * runtime exception when a threshold has been reached. + * + * This intends to guard against excessive recursion, causing stack overflow errors. + * + * @param ctx The context on which to maintain a counter + * @throws IllegalStateException When the counter on the context has been increased too often. + */ + public void recursionCheck(Context ctx) { + Integer recursionDepth = ctx.get("recursion-depth", Integer.class); + if (recursionDepth == null) { + recursionDepth = 0; + } + if (recursionDepth >= 1000) { // Arbitrary value to guard against stack-overflow. + throw new IllegalStateException("Max depth limit reached. Unable to recursively deserialize object."); + } + recursionDepth++; + ctx.store("recursion-depth", recursionDepth); + } }