Skip to content

Commit

Permalink
Resolving issue #743
Browse files Browse the repository at this point in the history
- Recursive depth issue found in JSONObject
- Recursive depth issue found in JSONArray
  • Loading branch information
sk02241994 committed Nov 3, 2023
1 parent 783d298 commit 9b090d1
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 10 deletions.
29 changes: 22 additions & 7 deletions src/main/java/org/json/JSONArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,18 @@ public JSONArray(String source) throws JSONException {
* A Collection.
*/
public JSONArray(Collection<?> collection) {
this(collection, 0);
}

protected JSONArray(Collection<?> collection, int recursionDepth) {
if (recursionDepth > JSONObject.RECURSION_DEPTH_LIMIT) {
throw new JSONException("JSONArray has reached recursion depth limit of " + JSONObject.RECURSION_DEPTH_LIMIT);
}
if (collection == null) {
this.myArrayList = new ArrayList<Object>();
} else {
this.myArrayList = new ArrayList<Object>(collection.size());
this.addAll(collection, true);
this.addAll(collection, true, recursionDepth);
}
}

Expand Down Expand Up @@ -205,7 +212,7 @@ public JSONArray(Object array) throws JSONException {
throw new JSONException(
"JSONArray initial value should be a string or collection or array.");
}
this.addAll(array, true);
this.addAll(array, true, 0);
}

/**
Expand Down Expand Up @@ -1779,13 +1786,15 @@ public boolean isEmpty() {
* @param wrap
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
* {@code false} to add the items directly
* @param recursionDepth
* variable to keep the count of how nested the object creation is happening.
*
*/
private void addAll(Collection<?> collection, boolean wrap) {
private void addAll(Collection<?> collection, boolean wrap, int recursionDepth) {
this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size());
if (wrap) {
for (Object o: collection){
this.put(JSONObject.wrap(o));
this.put(JSONObject.wrap(o, recursionDepth + 1));
}
} else {
for (Object o: collection){
Expand Down Expand Up @@ -1815,6 +1824,10 @@ private void addAll(Iterable<?> iter, boolean wrap) {
}
}

private void addAll(Object array, boolean wrap) throws JSONException {
this.addAll(array, wrap, 0);
}

/**
* Add an array's elements to the JSONArray.
*
Expand All @@ -1825,19 +1838,21 @@ private void addAll(Iterable<?> iter, boolean wrap) {
* @param wrap
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
* {@code false} to add the items directly
* @param recursionDepth
* Variable to keep the count of how nested the object creation is happening.
*
* @throws JSONException
* If not an array or if an array value is non-finite number.
* @throws NullPointerException
* Thrown if the array parameter is null.
*/
private void addAll(Object array, boolean wrap) throws JSONException {
private void addAll(Object array, boolean wrap, int recursionDepth) throws JSONException {
if (array.getClass().isArray()) {
int length = Array.getLength(array);
this.myArrayList.ensureCapacity(this.myArrayList.size() + length);
if (wrap) {
for (int i = 0; i < length; i += 1) {
this.put(JSONObject.wrap(Array.get(array, i)));
this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1));
}
} else {
for (int i = 0; i < length; i += 1) {
Expand All @@ -1850,7 +1865,7 @@ private void addAll(Object array, boolean wrap) throws JSONException {
// JSONArray
this.myArrayList.addAll(((JSONArray)array).myArrayList);
} else if (array instanceof Collection) {
this.addAll((Collection<?>)array, wrap);
this.addAll((Collection<?>)array, wrap, recursionDepth);
} else if (array instanceof Iterable) {
this.addAll((Iterable<?>)array, wrap);
} else {
Expand Down
26 changes: 23 additions & 3 deletions src/main/java/org/json/JSONObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public String toString() {
* The map where the JSONObject's properties are kept.
*/
private final Map<String, Object> map;
public static final int RECURSION_DEPTH_LIMIT = 1000;

public Class<? extends Map> getMapType() {
return map.getClass();
Expand Down Expand Up @@ -276,6 +277,17 @@ public JSONObject(JSONTokener x) throws JSONException {
* If a key in the map is <code>null</code>
*/
public JSONObject(Map<?, ?> m) {
this(m, 0);
}

/**
* Construct a JSONObject from a map with recursion depth.
*
*/
protected JSONObject(Map<?, ?> m, int recursionDepth) {
if (recursionDepth > RECURSION_DEPTH_LIMIT) {
throw new JSONException("JSONObject has reached recursion depth limit of " + RECURSION_DEPTH_LIMIT);
}
if (m == null) {
this.map = new HashMap<String, Object>();
} else {
Expand All @@ -287,7 +299,7 @@ public JSONObject(Map<?, ?> m) {
final Object value = e.getValue();
if (value != null) {
testValidity(value);
this.map.put(String.valueOf(e.getKey()), wrap(value));
this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1));
}
}
}
Expand Down Expand Up @@ -2566,7 +2578,15 @@ public static Object wrap(Object object) {
return wrap(object, null);
}

public static Object wrap(Object object, int recursionDepth) {
return wrap(object, null, recursionDepth);
}

private static Object wrap(Object object, Set<Object> objectsRecord) {
return wrap(object, objectsRecord, 0);
}

private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth) {
try {
if (NULL.equals(object)) {
return NULL;
Expand All @@ -2584,14 +2604,14 @@ private static Object wrap(Object object, Set<Object> objectsRecord) {

if (object instanceof Collection) {
Collection<?> coll = (Collection<?>) object;
return new JSONArray(coll);
return new JSONArray(coll, recursionDepth);
}
if (object.getClass().isArray()) {
return new JSONArray(object);
}
if (object instanceof Map) {
Map<?, ?> map = (Map<?, ?>) object;
return new JSONObject(map);
return new JSONObject(map, recursionDepth);
}
Package objectPackage = object.getClass().getPackage();
String objectPackageName = objectPackage != null ? objectPackage
Expand Down
21 changes: 21 additions & 0 deletions src/test/java/org/json/junit/JSONArrayTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1415,4 +1415,25 @@ public String toJSONString() {
.put(2);
assertFalse(ja1.similar(ja3));
}

@Test(expected = JSONException.class)
public void testRecursiveDepth() {
HashMap<String, Object> map = new HashMap<>();
map.put("t", map);
new JSONArray().put(map);
}

@Test(expected = JSONException.class)
public void testRecursiveDepthAtPosition() {
HashMap<String, Object> map = new HashMap<>();
map.put("t", map);
new JSONArray().put(0, map);
}

@Test(expected = JSONException.class)
public void testRecursiveDepthArray() {
ArrayList<Object> array = new ArrayList<>();
array.add(array);
new JSONArray(array);
}
}
17 changes: 17 additions & 0 deletions src/test/java/org/json/junit/JSONObjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3716,4 +3716,21 @@ public void issue713BeanConstructorWithNonFiniteNumbers() {
assertThrows(JSONException.class, () -> new JSONObject(bean));
}
}

@Test(expected = JSONException.class)
public void issue743SerializationMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("t", map);
JSONObject object = new JSONObject(map);
String jsonString = object.toString();
}

@Test(expected = JSONException.class)
public void testCircularReferenceMultipleLevel() {
HashMap<String, Object> inside = new HashMap<>();
HashMap<String, Object> jsonObject = new HashMap<>();
inside.put("inside", jsonObject);
jsonObject.put("test", inside);
new JSONObject(jsonObject);
}
}

0 comments on commit 9b090d1

Please sign in to comment.