Skip to content

Commit

Permalink
Fixing StackOverflow error
Browse files Browse the repository at this point in the history
  • Loading branch information
coheigea committed Nov 17, 2022
1 parent 325b51b commit cac53b5
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 6 deletions.
9 changes: 6 additions & 3 deletions src/main/java/org/codehaus/jettison/json/JSONArray.java
Expand Up @@ -179,8 +179,9 @@ public JSONArray(String string) throws JSONException {
/**
* Construct a JSONArray from a Collection.
* @param collection A Collection.
* @throws JSONException If there is a syntax error.
*/
public JSONArray(Collection collection) {
public JSONArray(Collection collection) throws JSONException {
this.myArrayList = (collection == null) ?
new ArrayList() :
new ArrayList(collection);
Expand Down Expand Up @@ -580,8 +581,9 @@ public JSONArray put(boolean value) {
* JSONArray which is produced from a Collection.
* @param value A Collection value.
* @return this.
* @throws JSONException If there is a syntax error.
*/
public JSONArray put(Collection value) {
public JSONArray put(Collection value) throws JSONException {
put(new JSONArray(value));
return this;
}
Expand Down Expand Up @@ -631,8 +633,9 @@ public JSONArray put(long value) {
* JSONObject which is produced from a Map.
* @param value A Map value.
* @return this.
* @throws JSONException If there is a syntax error.
*/
public JSONArray put(Map value) {
public JSONArray put(Map value) throws JSONException {
put(new JSONObject(value));
return this;
}
Expand Down
40 changes: 37 additions & 3 deletions src/main/java/org/codehaus/jettison/json/JSONObject.java
Expand Up @@ -84,6 +84,13 @@
*/
public class JSONObject implements Serializable {

/**
* The default recursion depth limit to prevent stack overflow issues on deeply nested structures.
*/
final static int DEFAULT_RECURSION_DEPTH_LIMIT = 500;

static int RECURSION_DEPTH_LIMIT = DEFAULT_RECURSION_DEPTH_LIMIT;

/**
* JSONObject.NULL is equivalent to the value that JavaScript calls null,
* whilst Java's null is equivalent to the value that JavaScript calls
Expand Down Expand Up @@ -257,8 +264,17 @@ public JSONObject(JSONTokener x) throws JSONException {
* Construct a JSONObject from a Map.
* @param map A map object that can be used to initialize the contents of
* the JSONObject.
* @throws JSONException If there is a syntax error.
*/
public JSONObject(Map map) {
public JSONObject(Map map) throws JSONException {
this(map, 0);
}

private JSONObject(Map map, int recursionDepth) throws JSONException {

if (recursionDepth > RECURSION_DEPTH_LIMIT) {
throw new JSONException("JSONObject has reached recursion depth limit of " + RECURSION_DEPTH_LIMIT);
}
this.myHashMap = (map == null) ?
new LinkedHashMap<Object,Object>() :
new LinkedHashMap<Object,Object>(map);
Expand All @@ -268,8 +284,8 @@ public JSONObject(Map map) {
if (v instanceof Collection) {
myHashMap.put(entry.getKey(), new JSONArray((Collection) v));
}
if (v instanceof Map) {
myHashMap.put(entry.getKey(), new JSONObject((Map) v));
if (v instanceof Map && v != map) {
myHashMap.put(entry.getKey(), new JSONObject((Map) v, recursionDepth + 1));
}
}
}
Expand Down Expand Up @@ -1319,6 +1335,23 @@ static String valueToString(Object value, int indentFactor, int indent, boolean
return quote(value.toString(), escapeForwardSlash);
}

/**
* Set the new recursion depth limit to prevent stack overflow issues on deeply nested structures. The default
* value is 500
* @param newRecursionDepthLimit the new recursion depth limit to set
*/
public void setRecursionDepthLimit(int newRecursionDepthLimit) {
RECURSION_DEPTH_LIMIT = newRecursionDepthLimit;
}

/**
* Get the new recursion depth limit to prevent stack overflow issues on deeply nested structures. The default
* value is 500
* @return the recursion depth limit
*/
public int getRecursionDepthLimit() {
return RECURSION_DEPTH_LIMIT;
}

/**
* Write the contents of the JSONObject as JSON text to a writer.
Expand Down Expand Up @@ -1396,4 +1429,5 @@ public void setEscapeForwardSlashAlways(boolean escapeForwardSlashAlways) {
public Map toMap() {
return Collections.unmodifiableMap(myHashMap);
}

}
25 changes: 25 additions & 0 deletions src/test/java/org/codehaus/jettison/json/JSONObjectTest.java
Expand Up @@ -2,6 +2,11 @@

import junit.framework.TestCase;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JSONObjectTest extends TestCase {
public void testEquals() throws Exception {
JSONObject aJsonObj = new JSONObject("{\"x\":\"y\"}");
Expand Down Expand Up @@ -148,4 +153,24 @@ public void testMalformedArray() throws Exception {
}
}

// https://github.com/jettison-json/jettison/issues/52
public void testIssue52() throws Exception {
Map<String,Object> map = new HashMap<>();
map.put("t",map);
new JSONObject(map);
}

// https://github.com/jettison-json/jettison/issues/52
public void testIssue52Recursive() throws Exception {
try {
Map<String, Object> map = new HashMap<>();
Map<String, Object> map2 = new HashMap<>();
map.put("t", map2);
map2.put("t", map);
new JSONObject(map);
} catch (JSONException e) {
assertTrue(e.getMessage().contains("JSONObject has reached recursion depth limit"));
// expected
}
}
}

0 comments on commit cac53b5

Please sign in to comment.