@@ -28,6 +28,12 @@ extension JSONSerialization {
28
28
}
29
29
}
30
30
31
+ extension JSONSerialization {
32
+ // Structures with container nesting deeper than this limit are not valid if passed in in-memory for validation, nor if they are read during deserialization.
33
+ // This matches Darwin Foundation's validation behavior.
34
+ fileprivate static let maximumRecursionDepth = 512
35
+ }
36
+
31
37
32
38
/* A class for converting JSON to Foundation/Swift objects and converting Foundation/Swift objects to JSON.
33
39
@@ -48,8 +54,15 @@ open class JSONSerialization : NSObject {
48
54
- returns: `true` if `obj` can be converted to JSON, otherwise `false`.
49
55
*/
50
56
open class func isValidJSONObject( _ obj: Any ) -> Bool {
57
+ var recursionDepth = 0
58
+
51
59
// TODO: - revisit this once bridging story gets fully figured out
52
60
func isValidJSONObjectInternal( _ obj: Any ? ) -> Bool {
61
+ // Match Darwin Foundation in not considering a deep object valid.
62
+ guard recursionDepth < JSONSerialization . maximumRecursionDepth else { return false }
63
+ recursionDepth += 1
64
+ defer { recursionDepth -= 1 }
65
+
53
66
// Emulate the SE-0140 behavior bridging behavior for nils
54
67
guard let obj = obj else {
55
68
return true
@@ -173,13 +186,13 @@ open class JSONSerialization : NSObject {
173
186
174
187
let source = JSONReader . UnicodeSource ( buffer: buffer, encoding: encoding)
175
188
let reader = JSONReader ( source: source)
176
- if let ( object, _) = try reader. parseObject ( 0 , options: opt) {
189
+ if let ( object, _) = try reader. parseObject ( 0 , options: opt, recursionDepth : 0 ) {
177
190
return object
178
191
}
179
- else if let ( array, _) = try reader. parseArray ( 0 , options: opt) {
192
+ else if let ( array, _) = try reader. parseArray ( 0 , options: opt, recursionDepth : 0 ) {
180
193
return array
181
194
}
182
- else if opt. contains ( . allowFragments) , let ( value, _) = try reader. parseValue ( 0 , options: opt) {
195
+ else if opt. contains ( . allowFragments) , let ( value, _) = try reader. parseValue ( 0 , options: opt, recursionDepth : 0 ) {
183
196
return value
184
197
}
185
198
throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . propertyListReadCorrupt. rawValue, userInfo: [
@@ -922,9 +935,16 @@ private struct JSONReader {
922
935
}
923
936
return nil
924
937
}
925
-
926
- //MARK: - Value parsing
927
- func parseValue( _ input: Index , options opt: JSONSerialization . ReadingOptions ) throws -> ( Any , Index ) ? {
938
+
939
+ func parseValue( _ input: Index , options opt: JSONSerialization . ReadingOptions , recursionDepth: Int ) throws -> ( Any , Index ) ? {
940
+ guard recursionDepth < JSONSerialization . maximumRecursionDepth else {
941
+ throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . propertyListReadCorrupt. rawValue, userInfo: [
942
+ NSDebugDescriptionErrorKey: " Recursion depth exceeded during parsing "
943
+ ] )
944
+ }
945
+
946
+ let newDepth = recursionDepth + 1
947
+
928
948
if let ( value, parser) = try parseString ( input) {
929
949
return ( value, parser)
930
950
}
@@ -937,10 +957,10 @@ private struct JSONReader {
937
957
else if let parser = try consumeASCIISequence ( " null " , input: input) {
938
958
return ( NSNull ( ) , parser)
939
959
}
940
- else if let ( object, parser) = try parseObject ( input, options: opt) {
960
+ else if let ( object, parser) = try parseObject ( input, options: opt, recursionDepth : newDepth ) {
941
961
return ( object, parser)
942
962
}
943
- else if let ( array, parser) = try parseArray ( input, options: opt) {
963
+ else if let ( array, parser) = try parseArray ( input, options: opt, recursionDepth : newDepth ) {
944
964
return ( array, parser)
945
965
}
946
966
else if let ( number, parser) = try parseNumber ( input, options: opt) {
@@ -950,7 +970,7 @@ private struct JSONReader {
950
970
}
951
971
952
972
//MARK: - Object parsing
953
- func parseObject( _ input: Index , options opt: JSONSerialization . ReadingOptions ) throws -> ( [ String : Any ] , Index ) ? {
973
+ func parseObject( _ input: Index , options opt: JSONSerialization . ReadingOptions , recursionDepth : Int ) throws -> ( [ String : Any ] , Index ) ? {
954
974
guard let beginIndex = try consumeStructure ( Structure . BeginObject, input: input) else {
955
975
return nil
956
976
}
@@ -961,7 +981,7 @@ private struct JSONReader {
961
981
return ( output, finalIndex)
962
982
}
963
983
964
- if let ( key, value, nextIndex) = try parseObjectMember ( index, options: opt) {
984
+ if let ( key, value, nextIndex) = try parseObjectMember ( index, options: opt, recursionDepth : recursionDepth ) {
965
985
output [ key] = value
966
986
967
987
if let finalParser = try consumeStructure ( Structure . EndObject, input: nextIndex) {
@@ -979,7 +999,7 @@ private struct JSONReader {
979
999
}
980
1000
}
981
1001
982
- func parseObjectMember( _ input: Index , options opt: JSONSerialization . ReadingOptions ) throws -> ( String , Any , Index ) ? {
1002
+ func parseObjectMember( _ input: Index , options opt: JSONSerialization . ReadingOptions , recursionDepth : Int ) throws -> ( String , Any , Index ) ? {
983
1003
guard let ( name, index) = try parseString ( input) else {
984
1004
throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . propertyListReadCorrupt. rawValue, userInfo: [
985
1005
NSDebugDescriptionErrorKey : " Missing object key at location \( source. distanceFromStart ( input) ) "
@@ -990,7 +1010,7 @@ private struct JSONReader {
990
1010
NSDebugDescriptionErrorKey : " Invalid separator at location \( source. distanceFromStart ( index) ) "
991
1011
] )
992
1012
}
993
- guard let ( value, finalIndex) = try parseValue ( separatorIndex, options: opt) else {
1013
+ guard let ( value, finalIndex) = try parseValue ( separatorIndex, options: opt, recursionDepth : recursionDepth ) else {
994
1014
throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . propertyListReadCorrupt. rawValue, userInfo: [
995
1015
NSDebugDescriptionErrorKey : " Invalid value at location \( source. distanceFromStart ( separatorIndex) ) "
996
1016
] )
@@ -1000,7 +1020,7 @@ private struct JSONReader {
1000
1020
}
1001
1021
1002
1022
//MARK: - Array parsing
1003
- func parseArray( _ input: Index , options opt: JSONSerialization . ReadingOptions ) throws -> ( [ Any ] , Index ) ? {
1023
+ func parseArray( _ input: Index , options opt: JSONSerialization . ReadingOptions , recursionDepth : Int ) throws -> ( [ Any ] , Index ) ? {
1004
1024
guard let beginIndex = try consumeStructure ( Structure . BeginArray, input: input) else {
1005
1025
return nil
1006
1026
}
@@ -1010,8 +1030,8 @@ private struct JSONReader {
1010
1030
if let finalIndex = try consumeStructure ( Structure . EndArray, input: index) {
1011
1031
return ( output, finalIndex)
1012
1032
}
1013
-
1014
- if let ( value, nextIndex) = try parseValue ( index, options: opt) {
1033
+
1034
+ if let ( value, nextIndex) = try parseValue ( index, options: opt, recursionDepth : recursionDepth ) {
1015
1035
output. append ( value)
1016
1036
1017
1037
if let finalIndex = try consumeStructure ( Structure . EndArray, input: nextIndex) {
0 commit comments