Skip to content

Commit 2dd0f83

Browse files
committed
Resolving issue #743
- Recursive depth issue found in JSONObject - Recursive depth issue found in JSONArray
1 parent 9299177 commit 2dd0f83

File tree

4 files changed

+83
-10
lines changed

4 files changed

+83
-10
lines changed

src/main/java/org/json/JSONArray.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,18 @@ public JSONArray(String source) throws JSONException {
149149
* A Collection.
150150
*/
151151
public JSONArray(Collection<?> collection) {
152+
this(collection, 0);
153+
}
154+
155+
protected JSONArray(Collection<?> collection, int recursionDepth) {
156+
if (recursionDepth > JSONObject.RECURSION_DEPTH_LIMIT) {
157+
throw new JSONException("JSONArray has reached recursion depth limit of " + JSONObject.RECURSION_DEPTH_LIMIT);
158+
}
152159
if (collection == null) {
153160
this.myArrayList = new ArrayList<Object>();
154161
} else {
155162
this.myArrayList = new ArrayList<Object>(collection.size());
156-
this.addAll(collection, true);
163+
this.addAll(collection, true, recursionDepth);
157164
}
158165
}
159166

@@ -205,7 +212,7 @@ public JSONArray(Object array) throws JSONException {
205212
throw new JSONException(
206213
"JSONArray initial value should be a string or collection or array.");
207214
}
208-
this.addAll(array, true);
215+
this.addAll(array, true, 0);
209216
}
210217

211218
/**
@@ -1779,13 +1786,15 @@ public boolean isEmpty() {
17791786
* @param wrap
17801787
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
17811788
* {@code false} to add the items directly
1789+
* @param recursionDepth
1790+
* variable to keep the count of how nested the object creation is happening.
17821791
*
17831792
*/
1784-
private void addAll(Collection<?> collection, boolean wrap) {
1793+
private void addAll(Collection<?> collection, boolean wrap, int recursionDepth) {
17851794
this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size());
17861795
if (wrap) {
17871796
for (Object o: collection){
1788-
this.put(JSONObject.wrap(o));
1797+
this.put(JSONObject.wrap(o, recursionDepth + 1));
17891798
}
17901799
} else {
17911800
for (Object o: collection){
@@ -1815,6 +1824,10 @@ private void addAll(Iterable<?> iter, boolean wrap) {
18151824
}
18161825
}
18171826

1827+
private void addAll(Object array, boolean wrap) throws JSONException {
1828+
this.addAll(array, wrap, 0);
1829+
}
1830+
18181831
/**
18191832
* Add an array's elements to the JSONArray.
18201833
*
@@ -1825,19 +1838,21 @@ private void addAll(Iterable<?> iter, boolean wrap) {
18251838
* @param wrap
18261839
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
18271840
* {@code false} to add the items directly
1841+
* @param recursionDepth
1842+
* Variable to keep the count of how nested the object creation is happening.
18281843
*
18291844
* @throws JSONException
18301845
* If not an array or if an array value is non-finite number.
18311846
* @throws NullPointerException
18321847
* Thrown if the array parameter is null.
18331848
*/
1834-
private void addAll(Object array, boolean wrap) throws JSONException {
1849+
private void addAll(Object array, boolean wrap, int recursionDepth) throws JSONException {
18351850
if (array.getClass().isArray()) {
18361851
int length = Array.getLength(array);
18371852
this.myArrayList.ensureCapacity(this.myArrayList.size() + length);
18381853
if (wrap) {
18391854
for (int i = 0; i < length; i += 1) {
1840-
this.put(JSONObject.wrap(Array.get(array, i)));
1855+
this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1));
18411856
}
18421857
} else {
18431858
for (int i = 0; i < length; i += 1) {
@@ -1850,7 +1865,7 @@ private void addAll(Object array, boolean wrap) throws JSONException {
18501865
// JSONArray
18511866
this.myArrayList.addAll(((JSONArray)array).myArrayList);
18521867
} else if (array instanceof Collection) {
1853-
this.addAll((Collection<?>)array, wrap);
1868+
this.addAll((Collection<?>)array, wrap, recursionDepth);
18541869
} else if (array instanceof Iterable) {
18551870
this.addAll((Iterable<?>)array, wrap);
18561871
} else {

src/main/java/org/json/JSONObject.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ public String toString() {
147147
* The map where the JSONObject's properties are kept.
148148
*/
149149
private final Map<String, Object> map;
150+
public static final int RECURSION_DEPTH_LIMIT = 1000;
150151

151152
public Class<? extends Map> getMapType() {
152153
return map.getClass();
@@ -276,6 +277,17 @@ public JSONObject(JSONTokener x) throws JSONException {
276277
* If a key in the map is <code>null</code>
277278
*/
278279
public JSONObject(Map<?, ?> m) {
280+
this(m, 0);
281+
}
282+
283+
/**
284+
* Construct a JSONObject from a map with recursion depth.
285+
*
286+
*/
287+
protected JSONObject(Map<?, ?> m, int recursionDepth) {
288+
if (recursionDepth > RECURSION_DEPTH_LIMIT) {
289+
throw new JSONException("JSONObject has reached recursion depth limit of " + RECURSION_DEPTH_LIMIT);
290+
}
279291
if (m == null) {
280292
this.map = new HashMap<String, Object>();
281293
} else {
@@ -287,7 +299,7 @@ public JSONObject(Map<?, ?> m) {
287299
final Object value = e.getValue();
288300
if (value != null) {
289301
testValidity(value);
290-
this.map.put(String.valueOf(e.getKey()), wrap(value));
302+
this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1));
291303
}
292304
}
293305
}
@@ -2566,7 +2578,15 @@ public static Object wrap(Object object) {
25662578
return wrap(object, null);
25672579
}
25682580

2581+
public static Object wrap(Object object, int recursionDepth) {
2582+
return wrap(object, null, recursionDepth);
2583+
}
2584+
25692585
private static Object wrap(Object object, Set<Object> objectsRecord) {
2586+
return wrap(object, objectsRecord, 0);
2587+
}
2588+
2589+
private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth) {
25702590
try {
25712591
if (NULL.equals(object)) {
25722592
return NULL;
@@ -2584,14 +2604,14 @@ private static Object wrap(Object object, Set<Object> objectsRecord) {
25842604

25852605
if (object instanceof Collection) {
25862606
Collection<?> coll = (Collection<?>) object;
2587-
return new JSONArray(coll);
2607+
return new JSONArray(coll, recursionDepth);
25882608
}
25892609
if (object.getClass().isArray()) {
25902610
return new JSONArray(object);
25912611
}
25922612
if (object instanceof Map) {
25932613
Map<?, ?> map = (Map<?, ?>) object;
2594-
return new JSONObject(map);
2614+
return new JSONObject(map, recursionDepth);
25952615
}
25962616
Package objectPackage = object.getClass().getPackage();
25972617
String objectPackageName = objectPackage != null ? objectPackage

src/test/java/org/json/junit/JSONArrayTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,4 +1417,25 @@ public String toJSONString() {
14171417
.put(2);
14181418
assertFalse(ja1.similar(ja3));
14191419
}
1420+
1421+
@Test(expected = JSONException.class)
1422+
public void testRecursiveDepth() {
1423+
HashMap<String, Object> map = new HashMap<>();
1424+
map.put("t", map);
1425+
new JSONArray().put(map);
1426+
}
1427+
1428+
@Test(expected = JSONException.class)
1429+
public void testRecursiveDepthAtPosition() {
1430+
HashMap<String, Object> map = new HashMap<>();
1431+
map.put("t", map);
1432+
new JSONArray().put(0, map);
1433+
}
1434+
1435+
@Test(expected = JSONException.class)
1436+
public void testRecursiveDepthArray() {
1437+
ArrayList<Object> array = new ArrayList<>();
1438+
array.add(array);
1439+
new JSONArray(array);
1440+
}
14201441
}

src/test/java/org/json/junit/JSONObjectTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3718,4 +3718,21 @@ public void issue713BeanConstructorWithNonFiniteNumbers() {
37183718
assertThrows(JSONException.class, () -> new JSONObject(bean));
37193719
}
37203720
}
3721+
3722+
@Test(expected = JSONException.class)
3723+
public void issue743SerializationMap() {
3724+
HashMap<String, Object> map = new HashMap<>();
3725+
map.put("t", map);
3726+
JSONObject object = new JSONObject(map);
3727+
String jsonString = object.toString();
3728+
}
3729+
3730+
@Test(expected = JSONException.class)
3731+
public void testCircularReferenceMultipleLevel() {
3732+
HashMap<String, Object> inside = new HashMap<>();
3733+
HashMap<String, Object> jsonObject = new HashMap<>();
3734+
inside.put("inside", jsonObject);
3735+
jsonObject.put("test", inside);
3736+
new JSONObject(jsonObject);
3737+
}
37213738
}

0 commit comments

Comments
 (0)